import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../data/datasources/remote/auth_remote_datasource.dart'; import '../../core/di/injection.dart'; class UserState { final String? accountSequence; final String? nickname; final String? phone; final String? kycStatus; final String? source; final String? accessToken; final String? refreshToken; final bool isLoggedIn; final bool isLoading; final String? error; UserState({ this.accountSequence, this.nickname, this.phone, this.kycStatus, this.source, this.accessToken, this.refreshToken, this.isLoggedIn = false, this.isLoading = false, this.error, }); UserState copyWith({ String? accountSequence, String? nickname, String? phone, String? kycStatus, String? source, String? accessToken, String? refreshToken, bool? isLoggedIn, bool? isLoading, String? error, }) { return UserState( accountSequence: accountSequence ?? this.accountSequence, nickname: nickname ?? this.nickname, phone: phone ?? this.phone, kycStatus: kycStatus ?? this.kycStatus, source: source ?? this.source, accessToken: accessToken ?? this.accessToken, refreshToken: refreshToken ?? this.refreshToken, isLoggedIn: isLoggedIn ?? this.isLoggedIn, isLoading: isLoading ?? this.isLoading, error: error, ); } } class UserNotifier extends StateNotifier { final AuthRemoteDataSource _authDataSource; UserNotifier(this._authDataSource) : super(UserState()) { _loadFromStorage(); } Future _loadFromStorage() async { final prefs = await SharedPreferences.getInstance(); final accessToken = prefs.getString('access_token'); final refreshToken = prefs.getString('refresh_token'); final accountSequence = prefs.getString('account_sequence'); final phone = prefs.getString('phone'); if (accessToken != null && refreshToken != null && accountSequence != null) { state = state.copyWith( accessToken: accessToken, refreshToken: refreshToken, accountSequence: accountSequence, phone: phone, isLoggedIn: true, ); } } Future _saveToStorage(AuthResult result) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('access_token', result.accessToken); await prefs.setString('refresh_token', result.refreshToken); await prefs.setString('account_sequence', result.user.accountSequence); await prefs.setString('phone', result.user.phone); } Future _clearStorage() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('access_token'); await prefs.remove('refresh_token'); await prefs.remove('account_sequence'); await prefs.remove('phone'); } Future sendSmsCode(String phone, String type) async { state = state.copyWith(isLoading: true, error: null); try { await _authDataSource.sendSmsCode(phone, type); state = state.copyWith(isLoading: false); } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); rethrow; } } Future register(String phone, String password, String smsCode) async { state = state.copyWith(isLoading: true, error: null); try { final result = await _authDataSource.register(phone, password, smsCode); await _saveToStorage(result); state = state.copyWith( accessToken: result.accessToken, refreshToken: result.refreshToken, accountSequence: result.user.accountSequence, phone: result.user.phone, kycStatus: result.user.kycStatus, source: result.user.source, isLoggedIn: true, isLoading: false, ); } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); rethrow; } } Future loginWithPassword(String phone, String password) async { state = state.copyWith(isLoading: true, error: null); try { final result = await _authDataSource.loginWithPassword(phone, password); await _saveToStorage(result); state = state.copyWith( accessToken: result.accessToken, refreshToken: result.refreshToken, accountSequence: result.user.accountSequence, phone: result.user.phone, kycStatus: result.user.kycStatus, source: result.user.source, isLoggedIn: true, isLoading: false, ); } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); rethrow; } } Future loginWithSms(String phone, String smsCode) async { state = state.copyWith(isLoading: true, error: null); try { final result = await _authDataSource.loginWithSms(phone, smsCode); await _saveToStorage(result); state = state.copyWith( accessToken: result.accessToken, refreshToken: result.refreshToken, accountSequence: result.user.accountSequence, phone: result.user.phone, kycStatus: result.user.kycStatus, source: result.user.source, isLoggedIn: true, isLoading: false, ); } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); rethrow; } } Future logout() async { if (state.refreshToken != null) { try { await _authDataSource.logout(state.refreshToken!); } catch (_) {} } await _clearStorage(); state = UserState(); } Future refreshTokenIfNeeded() async { if (state.refreshToken == null) return; try { final newAccessToken = await _authDataSource.refreshToken(state.refreshToken!); final prefs = await SharedPreferences.getInstance(); await prefs.setString('access_token', newAccessToken); state = state.copyWith(accessToken: newAccessToken); } catch (e) { await logout(); } } Future resetPassword(String phone, String smsCode, String newPassword) async { state = state.copyWith(isLoading: true, error: null); try { await _authDataSource.resetPassword(phone, smsCode, newPassword); state = state.copyWith(isLoading: false); } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); rethrow; } } Future changePassword(String oldPassword, String newPassword) async { state = state.copyWith(isLoading: true, error: null); try { await _authDataSource.changePassword(oldPassword, newPassword); state = state.copyWith(isLoading: false); } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); rethrow; } } // Legacy method for compatibility void login({ required String accountSequence, String? nickname, String? phone, }) { state = state.copyWith( accountSequence: accountSequence, nickname: nickname, phone: phone, isLoggedIn: true, ); } // Legacy mock method for development void setMockUser() { state = state.copyWith( accountSequence: '1001', nickname: '测试用户', phone: '138****8888', isLoggedIn: true, ); } } final userNotifierProvider = StateNotifierProvider( (ref) => UserNotifier(getIt()), ); final currentAccountSequenceProvider = Provider((ref) { return ref.watch(userNotifierProvider).accountSequence; }); final isLoggedInProvider = Provider((ref) { return ref.watch(userNotifierProvider).isLoggedIn; }); final accessTokenProvider = Provider((ref) { return ref.watch(userNotifierProvider).accessToken; });