import 'package:moneymgr_mobile/services/api/api_client.dart'; import 'package:moneymgr_mobile/services/api/api_token.dart'; import 'package:moneymgr_mobile/services/api/auth_api.dart'; import 'package:moneymgr_mobile/services/storage/prefs.dart'; import 'package:moneymgr_mobile/services/storage/secure_storage.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import '../services/router/routes_list.dart'; part 'auth_state.g.dart'; /// The current authentication state of the app. /// /// This notifier is responsible for saving/removing the token and profile info /// to the storage through the [setAuthToken] and [logout] methods. @riverpod class CurrentAuthState extends _$CurrentAuthState { @override AuthState build() { final secureStorage = ref.watch(secureStorageProvider).requireValue; final token = secureStorage.token(); return token != null ? AuthState.authenticated : AuthState.unauthenticated; } /// Attempts to authenticate with [token] and saves the token and profile info to storage. /// Will invalidate the state if success and throw an exception in case of failure Future setAuthToken(ApiToken token) async { // Attempt to use provided token await ApiClient( token: token, prefs: await ref.watch(prefsProvider.future), ).authInfo(); final secureStorage = ref.read(secureStorageProvider).requireValue; await secureStorage.setToken(token); ref // Invalidate the state so the auth state will be updated to authenticated. .invalidateSelf(); } /// Logs out, deletes the saved token and profile info from storage, and invalidates /// the state. Future logout() async { final secureStorage = ref.read(secureStorageProvider).requireValue; await secureStorage.removeToken(); ref // Invalidate the state so the auth state will be updated to authenticated. .invalidateSelf(); } } /// The possible authentication states of the app. enum AuthState { unknown(redirectPath: homePage, allowedPaths: [homePage]), unauthenticated( redirectPath: authPage, allowedPaths: [authPage, qrAuthPath, manualAuthPage, settingsPage], ), authenticated( redirectPath: homePage, allowedPaths: null, forbiddenPaths: [authPage, manualAuthPage], ); const AuthState({ required this.redirectPath, required this.allowedPaths, this.forbiddenPaths, }); /// The target path to redirect when the current route is not allowed in this /// auth state. final String redirectPath; /// List of paths allowed when the app is in this auth state. May be set to null if there is no /// restriction applicable final List? allowedPaths; /// List of paths not allowed when the app is in this auth state. May be set to null if there is no /// restriction applicable final List? forbiddenPaths; }