import 'package:firebase_auth/firebase_auth.dart'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart'; import 'package:yumi/app/routes/sc_routes.dart'; import 'package:yumi/app/routes/sc_fluro_navigator.dart'; import 'package:yumi/shared/tools/sc_google_auth_utils.dart'; import 'package:yumi/shared/tools/sc_loading_manager.dart'; import 'package:yumi/shared/tools/sc_version_utils.dart'; import 'package:yumi/shared/data_sources/sources/local/data_persistence.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart'; import 'package:yumi/ui_kit/components/sc_tts.dart'; import 'package:provider/provider.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; import 'package:yumi/services/audio/rtm_manager.dart'; import '../../shared/data_sources/models/enum/sc_auth_type.dart'; class SocialChatAuthenticationManager extends ChangeNotifier { String authType = ""; String uid = ""; User? _user; User? get user => _user; bool get isSignedIn => _user != null; SocialChatAuthenticationManager() { _initializeAuthentication(); } Future _initializeAuthentication() async { try { await SCGoogleAuthService.initialize(); await _verifyExistingSession(); } catch (_) { // Login buttons should remain usable even if silent Google restore fails. } } Future _verifyExistingSession() async { final user = await SCGoogleAuthService.signInSilently(); _user = user; if (user != null) { authType = SCAuthType.GOOGLE.name; uid = user.uid; await DataPersistence.setPendingChannelAuth(authType, uid); } notifyListeners(); } Future authenticateUser(BuildContext context, String authType) async { if (authType == SCAuthType.GOOGLE.name) { this.authType = authType; try { final signedInUser = await SCGoogleAuthService.signInWithGoogle(); if (signedInUser == null) { return; } _user = signedInUser; uid = _user!.uid; SCLoadingManager.show(); if (uid.isNotEmpty) { await DataPersistence.setPendingChannelAuth(authType, uid); var user = await SCAccountRepository().loginForChannel(authType, uid); if (!context.mounted) { SCLoadingManager.hide(); return; } AccountStorage().setCurrentUser(user); await DataPersistence.clearPendingChannelAuth(); if (!context.mounted) { SCLoadingManager.hide(); return; } final canContinue = await SCVersionUtils.checkReview( context: context, ); if (!context.mounted || !canContinue) { SCLoadingManager.hide(); return; } await Provider.of( context, listen: false, ).resetLocalRoomState( fallbackRtmProvider: Provider.of( context, listen: false, ), ); if (!context.mounted) { return; } SCLoadingManager.hide(); notifyListeners(); SCNavigatorUtils.push(context, SCRoutes.home, replace: true); } } catch (e) { SCLoadingManager.hide(); _showAuthError(e); } } else if (authType == SCAuthType.APPLE.name) { this.authType = authType; try { final appleCredential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.fullName, // 请求姓名权限 ], ); uid = appleCredential.userIdentifier ?? ""; SCLoadingManager.show(); if (uid.isNotEmpty) { await DataPersistence.setPendingChannelAuth(authType, uid); var user = await SCAccountRepository().loginForChannel(authType, uid); if (!context.mounted) { SCLoadingManager.hide(); return; } AccountStorage().setCurrentUser(user); await DataPersistence.clearPendingChannelAuth(); if (!context.mounted) { SCLoadingManager.hide(); return; } final canContinue = await SCVersionUtils.checkReview( context: context, ); if (!context.mounted || !canContinue) { SCLoadingManager.hide(); return; } await Provider.of( context, listen: false, ).resetLocalRoomState( fallbackRtmProvider: Provider.of( context, listen: false, ), ); if (!context.mounted) { return; } SCLoadingManager.hide(); notifyListeners(); SCNavigatorUtils.push(context, SCRoutes.home, replace: true); } } catch (e) { SCLoadingManager.hide(); _showAuthError(e); } } } Future logoutUser() async { await SCGoogleAuthService.signOut(); await DataPersistence.clearPendingChannelAuth(); _user = null; notifyListeners(); } void _showAuthError(Object error) { if (error is DioException) { return; } final message = error.toString().replaceFirst("Exception: ", "").trim(); if (message.isNotEmpty) { SCTts.show(message); } } }