Account recovery is triggered once via a memoized Future, and errors are not swallowed inside the provider

This commit is contained in:
Arseni
2025-12-09 21:10:31 +03:00
parent 336687eccf
commit b16c295094
2 changed files with 18 additions and 16 deletions

View File

@@ -27,7 +27,7 @@ class AccountProvider extends ChangeNotifier {
Resource<Account?> get resource => _resource; Resource<Account?> get resource => _resource;
late LocaleProvider _localeProvider; late LocaleProvider _localeProvider;
PendingLogin? _pendingLogin; PendingLogin? _pendingLogin;
bool _restoreAttempted = false; Future<void>? _restoreFuture;
Account? get account => _resource.data; Account? get account => _resource.data;
PendingLogin? get pendingLogin => _pendingLogin; PendingLogin? get pendingLogin => _pendingLogin;
@@ -35,7 +35,7 @@ class AccountProvider extends ChangeNotifier {
bool get isLoading => _resource.isLoading; bool get isLoading => _resource.isLoading;
Object? get error => _resource.error; Object? get error => _resource.error;
bool get isReady => (!isLoading) && (account != null); bool get isReady => (!isLoading) && (account != null);
bool get restoreAttempted => _restoreAttempted; Future<void>? get restoreFuture => _restoreFuture;
Account? currentUser() { Account? currentUser() {
final acc = account; final acc = account;
@@ -69,7 +69,6 @@ class AccountProvider extends ChangeNotifier {
required String password, required String password,
required String locale, required String locale,
}) async { }) async {
_restoreAttempted = true;
_setResource(_resource.copyWith(isLoading: true, error: null)); _setResource(_resource.copyWith(isLoading: true, error: null));
try { try {
final outcome = await AccountService.login(LoginData.build( final outcome = await AccountService.login(LoginData.build(
@@ -98,7 +97,6 @@ class AccountProvider extends ChangeNotifier {
void completePendingLogin(Account account) { void completePendingLogin(Account account) {
_pendingLogin = null; _pendingLogin = null;
_restoreAttempted = true;
_setResource(Resource(data: account, isLoading: false, error: null)); _setResource(Resource(data: account, isLoading: false, error: null));
_pickupLocale(account.locale); _pickupLocale(account.locale);
} }
@@ -106,7 +104,6 @@ class AccountProvider extends ChangeNotifier {
Future<bool> isAuthorizationStored() async => AuthorizationService.isAuthorizationStored(); Future<bool> isAuthorizationStored() async => AuthorizationService.isAuthorizationStored();
Future<Account?> restore() async { Future<Account?> restore() async {
_restoreAttempted = true;
_setResource(_resource.copyWith(isLoading: true, error: null)); _setResource(_resource.copyWith(isLoading: true, error: null));
try { try {
final acc = await AccountService.restore(); final acc = await AccountService.restore();
@@ -145,7 +142,6 @@ class AccountProvider extends ChangeNotifier {
} }
Future<void> logout() async { Future<void> logout() async {
_restoreAttempted = true;
_setResource(_resource.copyWith(isLoading: true, error: null)); _setResource(_resource.copyWith(isLoading: true, error: null));
try { try {
await AccountService.logout(); await AccountService.logout();
@@ -227,16 +223,11 @@ class AccountProvider extends ChangeNotifier {
} }
} }
Future<void> restoreIfPossible() async { Future<void> restoreIfPossible() {
if (_restoreAttempted) return; return _restoreFuture ??= () async {
_restoreAttempted = true;
final hasAuth = await AuthorizationService.isAuthorizationStored(); final hasAuth = await AuthorizationService.isAuthorizationStored();
if (!hasAuth) { if (!hasAuth) return;
_setResource(Resource(data: null, isLoading: false, error: null));
return;
}
try {
await restore(); await restore();
} catch (_) {} }();
} }
} }

View File

@@ -36,6 +36,17 @@ class AccountLoader extends StatelessWidget {
}); });
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} }
if (provider.restoreFuture == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
provider.restoreIfPossible().catchError((error, stack) {
debugPrint('Account restore failed: $error');
});
});
return const Center(child: CircularProgressIndicator());
}
if (provider.isLoading) return const Center(child: CircularProgressIndicator());
if (provider.account == null) { if (provider.account == null) {
WidgetsBinding.instance.addPostFrameCallback((_) => navigateAndReplace(context, Pages.login)); WidgetsBinding.instance.addPostFrameCallback((_) => navigateAndReplace(context, Pages.login));
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());