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 <alex.tran1502@gmail.com>
This commit is contained in:
John Stef 2024-11-13 19:27:49 +02:00 committed by GitHub
parent c58bd307ce
commit de993289ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 33 additions and 11 deletions

View File

@ -41,4 +41,4 @@
"explorer.fileNesting.patterns": {
"*.ts": "${capture}.spec.ts,${capture}.mock.ts"
}
}
}

View File

@ -41,6 +41,8 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
_ref;
final _log = Logger("AuthenticationNotifier");
static const Duration _timeoutDuration = Duration(seconds: 7);
Future<bool> login(
String email,
String password,
@ -102,12 +104,15 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
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<AuthenticationState> {
shouldChangePassword: false,
isAuthenticated: false,
);
} catch (e, stack) {
log.severe('Logout failed', e, stack);
}
}
@ -168,10 +171,8 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
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;

View File

@ -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,
);
}