| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- import 'dart:developer' as developer;
- import 'package:dio/dio.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import '../core/network/api_response.dart';
- import '../data/services/auth_service.dart';
- import '../core/network/dio_client.dart';
- // ── State ──────────────────────────────────────────────────
- class GoogleAuthState {
- /// 秘钥加载中
- final bool isSecretLoading;
- /// 发送验证码中
- final bool isSendingCode;
- /// 提交绑定中
- final bool isSubmitting;
- final String? errorMessage;
- final int codeCooldown;
- /// TOTP 秘钥
- final String secret;
- /// otpauth:// URI(用于生成 QR 码)
- final String otpauthUrl;
- /// 脱敏邮箱(从用户信息获取)
- final String maskedEmail;
- const GoogleAuthState({
- this.isSecretLoading = false,
- this.isSendingCode = false,
- this.isSubmitting = false,
- this.errorMessage,
- this.codeCooldown = 0,
- this.secret = '',
- this.otpauthUrl = '',
- this.maskedEmail = '',
- });
- GoogleAuthState copyWith({
- bool? isSecretLoading,
- bool? isSendingCode,
- bool? isSubmitting,
- String? errorMessage,
- int? codeCooldown,
- String? secret,
- String? otpauthUrl,
- String? maskedEmail,
- }) =>
- GoogleAuthState(
- isSecretLoading: isSecretLoading ?? this.isSecretLoading,
- isSendingCode: isSendingCode ?? this.isSendingCode,
- isSubmitting: isSubmitting ?? this.isSubmitting,
- errorMessage: errorMessage,
- codeCooldown: codeCooldown ?? this.codeCooldown,
- secret: secret ?? this.secret,
- otpauthUrl: otpauthUrl ?? this.otpauthUrl,
- maskedEmail: maskedEmail ?? this.maskedEmail,
- );
- }
- // ── Notifier ───────────────────────────────────────────────
- class GoogleAuthNotifier extends Notifier<GoogleAuthState> {
- AuthService get _service => AuthService(ref.read(dioClientProvider));
- @override
- GoogleAuthState build() => const GoogleAuthState();
- void clearError() => state = state.copyWith(errorMessage: null);
- /// 页面加载时获取秘钥 — GET uc/google/sendgoogle
- /// 同时获取用户邮箱用于脱敏显示
- Future<void> fetchSecret() async {
- state = state.copyWith(isSecretLoading: true, errorMessage: null);
- try {
- final results = await Future.wait([
- _service.getGoogleSecret(),
- _service.getMyInfo(),
- ]);
- final secretData = results[0];
- final userInfo = results[1];
- final email = userInfo['email']?.toString() ?? '';
- state = state.copyWith(
- isSecretLoading: false,
- secret: secretData['secret']?.toString() ?? '',
- otpauthUrl: secretData['link']?.toString() ?? '',
- maskedEmail: _maskEmail(email),
- );
- } catch (e) {
- state = state.copyWith(
- isSecretLoading: false,
- errorMessage: _parseError(e),
- );
- }
- }
- /// 发送邮箱验证码 — POST uc/googleAuth/email/code
- Future<bool> sendEmailCode() async {
- state = state.copyWith(isSendingCode: true, errorMessage: null);
- try {
- await _service.sendGoogleAuthEmailCode();
- state = state.copyWith(isSendingCode: false);
- _startCountdown();
- return true;
- } catch (e) {
- state = state.copyWith(
- isSendingCode: false,
- errorMessage: _parseError(e),
- );
- return false;
- }
- }
- /// 绑定谷歌验证器 — POST uc/google/googleAuthWithSms
- Future<bool> bindGoogleAuth({
- required String googleCode,
- required String emailCode,
- }) async {
- state = state.copyWith(isSubmitting: true, errorMessage: null);
- try {
- await _service.bindGoogleAuth(
- codes: googleCode,
- vcode: emailCode,
- secret: state.secret,
- vtype: '2',
- );
- state = state.copyWith(isSubmitting: false);
- return true;
- } catch (e) {
- state = state.copyWith(
- isSubmitting: false,
- errorMessage: _parseError(e),
- );
- return false;
- }
- }
- void _startCountdown() {
- state = state.copyWith(codeCooldown: 60);
- Future.doWhile(() async {
- await Future.delayed(const Duration(seconds: 1));
- final remaining = state.codeCooldown - 1;
- state = state.copyWith(codeCooldown: remaining);
- return remaining > 0;
- });
- }
- /// 邮箱脱敏:user@gmail.com → u**@gmail.com
- String _maskEmail(String email) {
- if (email.isEmpty) return '';
- final parts = email.split('@');
- if (parts.length != 2) return email;
- final name = parts[0];
- if (name.length <= 1) return '$name**@${parts[1]}';
- return '${name[0]}**@${parts[1]}';
- }
- String _parseError(Object e) {
- developer.log('GoogleAuth error: $e', name: 'GOOGLE_AUTH', error: e);
- if (e is DioException) {
- if (e.error is ApiException) {
- return (e.error as ApiException).message;
- }
- final responseData = e.response?.data;
- if (responseData is Map<String, dynamic>) {
- final msg = responseData['message'] as String? ??
- responseData['msg'] as String?;
- if (msg != null && msg.isNotEmpty) return msg;
- }
- return e.message ?? 'errNetworkError';
- }
- if (e is ApiException) return e.message;
- return e.toString();
- }
- }
- // ── Providers ──────────────────────────────────────────────
- final googleAuthProvider =
- NotifierProvider<GoogleAuthNotifier, GoogleAuthState>(
- GoogleAuthNotifier.new,
- );
|