176 lines
4.2 KiB
Dart
176 lines
4.2 KiB
Dart
import 'dart:typed_data';
|
||
import 'package:flutter/material.dart';
|
||
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';
|
||
|
||
/// 認證狀態管理
|
||
class AuthProvider extends ChangeNotifier {
|
||
final UserService _userService;
|
||
|
||
User? _user;
|
||
bool _isLoggedIn = false;
|
||
bool _isLoading = false;
|
||
String? _token;
|
||
|
||
AuthProvider(this._userService) {
|
||
_initAuth();
|
||
}
|
||
|
||
// Getters
|
||
User? get user => _user;
|
||
bool get isLoggedIn => _isLoggedIn;
|
||
bool get isLoading => _isLoading;
|
||
String? get token => _token;
|
||
|
||
/// 初始化認證狀態
|
||
Future<void> _initAuth() async {
|
||
_token = LocalStorage.getToken();
|
||
_isLoggedIn = _token?.isNotEmpty == true;
|
||
|
||
if (_isLoggedIn) {
|
||
_user = _loadUserFromStorage();
|
||
}
|
||
notifyListeners();
|
||
}
|
||
|
||
User? _loadUserFromStorage() {
|
||
final userJson = LocalStorage.getUserInfo();
|
||
return userJson != null ? User.fromJson(userJson) : null;
|
||
}
|
||
|
||
/// 登錄
|
||
Future<ApiResponse<User>> login(String username, String password) {
|
||
return _authenticate(() => _userService.login(username, password));
|
||
}
|
||
|
||
/// 註冊(含身份證圖片和可選推廣碼)
|
||
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,
|
||
));
|
||
}
|
||
|
||
/// 統一認證處理
|
||
Future<ApiResponse<User>> _authenticate(
|
||
Future<ApiResponse<Map<String, dynamic>>> Function() action,
|
||
) async {
|
||
_setLoading(true);
|
||
|
||
try {
|
||
final response = await action();
|
||
|
||
if (!response.success || response.data == null) {
|
||
return ApiResponse.fail(response.message ?? '操作失敗');
|
||
}
|
||
|
||
return _handleAuthSuccess(response.data!, response.message);
|
||
} catch (e) {
|
||
return ApiResponse.fail('操作失敗: $e');
|
||
} finally {
|
||
_setLoading(false);
|
||
}
|
||
}
|
||
|
||
/// 處理認證成功
|
||
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!);
|
||
}
|
||
|
||
if (userJson != null) {
|
||
LocalStorage.saveUserInfo(userJson);
|
||
_user = User.fromJson(userJson);
|
||
}
|
||
|
||
_isLoggedIn = true;
|
||
notifyListeners();
|
||
|
||
return _user != null
|
||
? ApiResponse.success(_user!, message)
|
||
: ApiResponse.fail('用戶信息獲取失敗');
|
||
}
|
||
|
||
/// 退出登錄
|
||
Future<void> logout() async {
|
||
_setLoading(true);
|
||
|
||
try {
|
||
await _userService.logout();
|
||
} catch (_) {
|
||
// 忽略退出登錄的接口錯誤
|
||
}
|
||
|
||
_clearAuthState();
|
||
_setLoading(false);
|
||
}
|
||
|
||
void _clearAuthState() {
|
||
LocalStorage.clearUserData();
|
||
_user = null;
|
||
_token = null;
|
||
_isLoggedIn = false;
|
||
}
|
||
|
||
/// 強制登出(token 過期時由 DioClient 回調觸發)
|
||
void forceLogout() {
|
||
_clearAuthState();
|
||
notifyListeners();
|
||
}
|
||
|
||
/// 刷新用戶信息
|
||
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 (_) {
|
||
// 忽略錯誤
|
||
}
|
||
}
|
||
|
||
/// 提交KYC實名認證(真實圖片上傳)
|
||
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) {
|
||
return ApiResponse.fail('KYC提交失敗: $e');
|
||
}
|
||
}
|
||
|
||
void _setLoading(bool value) {
|
||
_isLoading = value;
|
||
notifyListeners();
|
||
}
|
||
}
|