From de993289ad9bbc21ae538b3e0f88f1ea6ae946cd Mon Sep 17 00:00:00 2001 From: John Stef Date: Wed, 13 Nov 2024 19:27:49 +0200 Subject: [PATCH] fix(mobile): fix logout timeout (#14104) * fix(mobile): add timeout to logout * chore(mobile): refactor timeout durations * feat(mobile): add loading state to logout button * chore(mobile): format authentication.provider.dart * chore: format * chore: revert settings.json change --------- Co-authored-by: Alex --- .vscode/settings.json | 2 +- .../providers/authentication.provider.dart | 15 ++++++----- .../common/app_bar_dialog/app_bar_dialog.dart | 27 ++++++++++++++++--- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a8661326a0..49dbf3944c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -41,4 +41,4 @@ "explorer.fileNesting.patterns": { "*.ts": "${capture}.spec.ts,${capture}.mock.ts" } -} +} \ No newline at end of file diff --git a/mobile/lib/providers/authentication.provider.dart b/mobile/lib/providers/authentication.provider.dart index 1fe7db5d46..60e31d707e 100644 --- a/mobile/lib/providers/authentication.provider.dart +++ b/mobile/lib/providers/authentication.provider.dart @@ -41,6 +41,8 @@ class AuthenticationNotifier extends StateNotifier { _ref; final _log = Logger("AuthenticationNotifier"); + static const Duration _timeoutDuration = Duration(seconds: 7); + Future login( String email, String password, @@ -102,12 +104,15 @@ class AuthenticationNotifier extends StateNotifier { await _apiService.authenticationApi .logout() + .timeout(_timeoutDuration) .then((_) => log.info("Logout was successful for $userEmail")) .onError( (error, stackTrace) => log.severe("Logout failed for $userEmail", error, stackTrace), ); - + } catch (e, stack) { + log.severe('Logout failed', e, stack); + } finally { await Future.wait([ clearAssetsAndAlbums(_db), Store.delete(StoreKey.currentUser), @@ -125,8 +130,6 @@ class AuthenticationNotifier extends StateNotifier { shouldChangePassword: false, isAuthenticated: false, ); - } catch (e, stack) { - log.severe('Logout failed', e, stack); } } @@ -168,10 +171,8 @@ class AuthenticationNotifier extends StateNotifier { UserPreferencesResponseDto? userPreferences; try { final responses = await Future.wait([ - _apiService.usersApi.getMyUser().timeout(const Duration(seconds: 7)), - _apiService.usersApi - .getMyPreferences() - .timeout(const Duration(seconds: 7)), + _apiService.usersApi.getMyUser().timeout(_timeoutDuration), + _apiService.usersApi.getMyPreferences().timeout(_timeoutDuration), ]); userResponse = responses[0] as UserAdminResponseDto; userPreferences = responses[1] as UserPreferencesResponseDto; diff --git a/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart b/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart index cd694336bc..38d161f852 100644 --- a/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart +++ b/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart @@ -28,6 +28,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { bool isHorizontal = !context.isMobile; final horizontalPadding = isHorizontal ? 100.0 : 20.0; final user = ref.watch(currentUserProvider); + final isLoggingOut = useState(false); useEffect( () { @@ -63,11 +64,16 @@ class ImmichAppBarDialog extends HookConsumerWidget { ); } - buildActionButton(IconData icon, String text, Function() onTap) { + buildActionButton( + IconData icon, + String text, + Function() onTap, { + Widget? trailing, + }) { return ListTile( dense: true, visualDensity: VisualDensity.standard, - contentPadding: const EdgeInsets.only(left: 30), + contentPadding: const EdgeInsets.only(left: 30, right: 30), minLeadingWidth: 40, leading: SizedBox( child: Icon( @@ -83,6 +89,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { ), ).tr(), onTap: onTap, + trailing: trailing, ); } @@ -107,6 +114,10 @@ class ImmichAppBarDialog extends HookConsumerWidget { Icons.logout_rounded, "profile_drawer_sign_out", () async { + if (isLoggingOut.value) { + return; + } + showDialog( context: context, builder: (BuildContext ctx) { @@ -115,7 +126,11 @@ class ImmichAppBarDialog extends HookConsumerWidget { content: "app_bar_signout_dialog_content", ok: "app_bar_signout_dialog_ok", onOk: () async { - await ref.read(authenticationProvider.notifier).logout(); + isLoggingOut.value = true; + await ref + .read(authenticationProvider.notifier) + .logout() + .whenComplete(() => isLoggingOut.value = false); ref.read(manualUploadProvider.notifier).cancelBackup(); ref.read(backupProvider.notifier).cancelBackup(); @@ -127,6 +142,12 @@ class ImmichAppBarDialog extends HookConsumerWidget { }, ); }, + trailing: isLoggingOut.value + ? SizedBox.square( + dimension: 20, + child: const CircularProgressIndicator(strokeWidth: 2), + ) + : null, ); }