import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:auto_route/auto_route.dart'; import 'package:dio/dio.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:mnemo_cards/main.dart'; import 'package:mnemo_cards/managers/repository/http_repository.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:rxdart/rxdart.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:device_info_plus/device_info_plus.dart'; import '../domain/router/app_router.dart'; import '../domain/router/app_router.gr.dart'; import '../features/analytics/analytics.dart'; import 'user_state_holder.dart'; class UserManager { CompositeSubscription? _subscription; final HttpRepository _repository; GoogleSignIn _googleSignIn = GoogleSignIn( scopes: [ 'email', // 'https://www.googleapis.com/auth/contacts.readonly', ], // clientId: '01767851968-dvbvmte4m90dkqitp013s4nd5c0df1n8.apps.googleusercontent.com', // "701767851968-bud97rud1d9qtqju96addn31nhm0oofu.apps.googleusercontent.com", ); late final SharedPreferences? _sharedPreferences; final UserStateHolder userStateHolder; UserManager(this._repository) : userStateHolder = UserStateHolder(); bool get hasUser => userStateHolder.user != null; Future login() async { if (await _googleSignIn.isSignedIn()) { await _googleSignIn.signOut(); } final account = await _googleSignIn.signIn(); await Future.delayed(Duration(milliseconds: 300)); } Future logout() async { if (await _googleSignIn.isSignedIn()) { await _googleSignIn.signOut(); } Analytics.logout(userStateHolder.user); userStateHolder.clear(); } Future _createUser( String externalId, ExternalIdType idType, String? name, ) async { final (user, token) = await _repository.createOrGetUser(externalId, idType, name); _setAuthToken(token); userStateHolder.setUser(user); } void _setAuthToken(String authToken) async { _repository.setAuthToken(authToken); await _sharedPreferences!.setString('authToken', authToken); } void _clearAuthToken() async { await _sharedPreferences!.remove('authToken'); } Future _updateUser() async { String? authToken = _sharedPreferences!.getString('authToken'); if (authToken != null) { _setAuthToken(authToken); try { final fetchedUser = await _repository.getUser(); userStateHolder.setUser(fetchedUser!); return; } catch (e) { _clearAuthToken(); AppRouter.openAuthOrProfile(); } } // not creating empty user // if (Platform.isAndroid) { // final deviceInfoPlugin = DeviceInfoPlugin(); // final deviceInfo = await deviceInfoPlugin.androidInfo; // final id = deviceInfo.id; // await _createUser(id, ExternalIdType.device); // } } Future init() async { _sharedPreferences = await SharedPreferences.getInstance(); //todo add ios try { await _updateUser(); } on Object catch (e, s) { log('User manager init error', error: e, stackTrace: s); } _subscription = CompositeSubscription() ..add(_googleSignIn.onCurrentUserChanged .startWith(_googleSignIn.currentUser) .distinct((p, n) => p?.id == n?.id) .listen((account) async { if (account != null) { final name = account.displayName; final token = await account.authentication.then((value) => value.idToken); Analytics.login(ExternalIdType.google); await _createUser(token!, ExternalIdType.google, name); } })) ..add(Stream.periodic(Duration(seconds: 10)).listen((_) async { try { if (userStateHolder.user == null) { await _updateUser(); } } catch (e) { log(e.toString()); _clearAuthToken(); if (e is DioException) { if (e.response?.statusCode == 401) { appRouter.push( PageRouteInfo(ProfilePage.name), ); } } } })) ..add( userStateHolder.asNullableStream .map((user) => user != null) .distinct() .listen((hasUser) { if (hasUser) { appRouter.replace(PageRouteInfo(HomePage.name)); } else { AppRouter.openAuthOrProfile(); } }), ); } Future dispose() async { await _subscription?.cancel(); _subscription = null; } } enum ExternalIdType { google, device }