Files
monisuo/flutter_monisuo/lib/providers/auth_provider.dart

187 lines
4.5 KiB
Dart
Raw Normal View History

2026-03-30 00:30:42 +08:00
import 'dart:typed_data';
import 'package:flutter/material.dart';
2026-03-23 00:43:19 +08:00
import '../core/network/api_response.dart';
import '../core/network/dio_client.dart';
import '../core/storage/local_storage.dart';
import '../data/models/user.dart';
import '../data/services/user_service.dart';
2026-04-21 08:09:45 +08:00
import '../main.dart';
import '../ui/pages/auth/login_page.dart';
2026-04-07 01:05:05 +08:00
/// 認證狀態管理
class AuthProvider extends ChangeNotifier {
final UserService _userService;
User? _user;
bool _isLoggedIn = false;
bool _isLoading = false;
String? _token;
AuthProvider(this._userService) {
2026-03-23 00:08:19 +08:00
_initAuth();
}
// Getters
User? get user => _user;
bool get isLoggedIn => _isLoggedIn;
bool get isLoading => _isLoading;
String? get token => _token;
2026-04-07 01:05:05 +08:00
/// 初始化認證狀態
2026-03-23 00:08:19 +08:00
Future<void> _initAuth() async {
_token = LocalStorage.getToken();
2026-03-23 00:08:19 +08:00
_isLoggedIn = _token?.isNotEmpty == true;
if (_isLoggedIn) {
2026-03-23 00:08:19 +08:00
_user = _loadUserFromStorage();
}
notifyListeners();
}
2026-03-23 00:08:19 +08:00
User? _loadUserFromStorage() {
final userJson = LocalStorage.getUserInfo();
return userJson != null ? User.fromJson(userJson) : null;
}
2026-04-07 01:05:05 +08:00
/// 登錄
2026-03-23 00:08:19 +08:00
Future<ApiResponse<User>> login(String username, String password) {
return _authenticate(() => _userService.login(username, password));
}
2026-04-07 01:05:05 +08:00
/// 註冊(含身份證圖片和可選推廣碼)
2026-04-04 21:19:29 +08:00
Future<ApiResponse<User>> register(
String username,
String password, {
String? referralCode,
required Uint8List frontBytes,
required Uint8List backBytes,
}) {
return _authenticate(() => _userService.register(
username,
password,
referralCode: referralCode,
frontBytes: frontBytes,
backBytes: backBytes,
));
2026-03-23 00:08:19 +08:00
}
2026-04-07 01:05:05 +08:00
/// 統一認證處理
2026-03-23 00:08:19 +08:00
Future<ApiResponse<User>> _authenticate(
Future<ApiResponse<Map<String, dynamic>>> Function() action,
) async {
_setLoading(true);
try {
2026-03-23 00:08:19 +08:00
final response = await action();
2026-03-23 00:08:19 +08:00
if (!response.success || response.data == null) {
2026-04-07 01:05:05 +08:00
return ApiResponse.fail(response.message ?? '操作失敗');
}
2026-03-23 00:08:19 +08:00
return _handleAuthSuccess(response.data!, response.message);
} catch (e) {
2026-04-07 01:05:05 +08:00
return ApiResponse.fail('操作失敗: $e');
2026-03-23 00:08:19 +08:00
} finally {
_setLoading(false);
}
}
2026-04-07 01:05:05 +08:00
/// 處理認證成功
2026-03-23 00:08:19 +08:00
ApiResponse<User> _handleAuthSuccess(
Map<String, dynamic> data,
String? message,
) {
_token = data['token'] as String?;
final userJson = data['user'] as Map<String, dynamic>? ??
data['userInfo'] as Map<String, dynamic>?;
if (_token != null) {
LocalStorage.saveToken(_token!);
}
2026-03-23 00:08:19 +08:00
if (userJson != null) {
LocalStorage.saveUserInfo(userJson);
_user = User.fromJson(userJson);
}
2026-03-23 00:08:19 +08:00
_isLoggedIn = true;
2026-04-04 21:19:29 +08:00
notifyListeners();
2026-03-23 00:08:19 +08:00
return _user != null
? ApiResponse.success(_user!, message)
2026-04-07 01:05:05 +08:00
: ApiResponse.fail('用戶信息獲取失敗');
}
2026-04-07 01:05:05 +08:00
/// 退出登錄
Future<void> logout() async {
try {
await _userService.logout();
2026-04-21 08:09:45 +08:00
} catch (_) {}
2026-03-23 00:08:19 +08:00
_clearAuthState();
2026-04-21 08:09:45 +08:00
notifyListeners();
_navigateToLogin();
2026-03-23 00:08:19 +08:00
}
void _clearAuthState() {
LocalStorage.clearUserData();
_user = null;
_token = null;
_isLoggedIn = false;
}
2026-04-07 01:05:05 +08:00
/// 強制登出token 過期時由 DioClient 回調觸發)
void forceLogout() {
_clearAuthState();
notifyListeners();
2026-04-21 08:09:45 +08:00
_navigateToLogin();
}
/// 使用全局導航 Key 跳轉到登錄頁並清空路由棧
void _navigateToLogin() {
final nav = navigatorKey.currentState;
if (nav != null) {
nav.pushAndRemoveUntil(
MaterialPageRoute(builder: (_) => LoginPage()),
(route) => false,
);
}
}
2026-04-07 01:05:05 +08:00
/// 刷新用戶信息
Future<void> refreshUserInfo() async {
if (!_isLoggedIn) return;
try {
final response = await _userService.getUserInfo();
if (response.success && response.data != null) {
_user = response.data;
await LocalStorage.saveUserInfo(_user!.toJson());
notifyListeners();
}
} catch (_) {
2026-04-07 01:05:05 +08:00
// 忽略錯誤
}
}
2026-03-23 00:08:19 +08:00
2026-04-07 01:05:05 +08:00
/// 提交KYC實名認證真實圖片上傳
2026-03-30 00:30:42 +08:00
Future<ApiResponse<void>> submitKyc(
Uint8List frontBytes, Uint8List backBytes) async {
try {
final response =
await _userService.uploadKyc(frontBytes, backBytes);
if (response.success) {
await refreshUserInfo();
}
return response;
} catch (e) {
2026-04-07 01:05:05 +08:00
return ApiResponse.fail('KYC提交失敗: $e');
2026-03-30 00:30:42 +08:00
}
}
2026-03-23 00:08:19 +08:00
void _setLoading(bool value) {
_isLoading = value;
notifyListeners();
}
}