Files
monisuo/flutter_monisuo/lib/providers/auth_provider.dart
2026-04-07 01:05:05 +08:00

176 lines
4.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
}