rwadurian/frontend/mining-app/lib/presentation/providers/user_providers.dart

257 lines
7.6 KiB
Dart

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<UserState> {
final AuthRemoteDataSource _authDataSource;
UserNotifier(this._authDataSource) : super(UserState()) {
_loadFromStorage();
}
Future<void> _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<void> _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<void> _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<void> 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<void> 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<void> 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<void> 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<void> logout() async {
if (state.refreshToken != null) {
try {
await _authDataSource.logout(state.refreshToken!);
} catch (_) {}
}
await _clearStorage();
state = UserState();
}
Future<void> 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<void> 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<void> 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<UserNotifier, UserState>(
(ref) => UserNotifier(getIt<AuthRemoteDataSource>()),
);
final currentAccountSequenceProvider = Provider<String?>((ref) {
return ref.watch(userNotifierProvider).accountSequence;
});
final isLoggedInProvider = Provider<bool>((ref) {
return ref.watch(userNotifierProvider).isLoggedIn;
});
final accessTokenProvider = Provider<String?>((ref) {
return ref.watch(userNotifierProvider).accessToken;
});