From 98998cccbc52b49a45a078f967b1708572140041 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 20 Feb 2023 21:43:39 -0600 Subject: [PATCH] fix(mobile): user get logged out upon clicking on any thing after logging in (#1808) * fix(mobile): user get logged out upon clicking on any thing after logging in * wip: fixing still * fix: the actual issue * Fix: avaialble album not updating UI --- .../backup/providers/backup.provider.dart | 104 +++++++++--------- .../views/backup_album_selection_page.dart | 21 ++-- .../backup/views/backup_controller_page.dart | 13 ++- mobile/lib/modules/home/views/home_page.dart | 12 +- .../providers/authentication.provider.dart | 29 +++-- .../login/ui/change_password_form.dart | 50 +++++---- mobile/lib/modules/login/ui/login_form.dart | 11 +- mobile/lib/routing/auth_guard.dart | 5 + mobile/lib/shared/services/asset.service.dart | 1 + mobile/pubspec.lock | 4 +- mobile/pubspec.yaml | 4 +- 11 files changed, 137 insertions(+), 117 deletions(-) diff --git a/mobile/lib/modules/backup/providers/backup.provider.dart b/mobile/lib/modules/backup/providers/backup.provider.dart index 2e57250a06..daad2c4fd3 100644 --- a/mobile/lib/modules/backup/providers/backup.provider.dart +++ b/mobile/lib/modules/backup/providers/backup.provider.dart @@ -58,9 +58,7 @@ class BackupNotifier extends StateNotifier { fileType: '...', ), ), - ) { - getBackupInfo(); - } + ); final log = Logger('BackupNotifier'); final BackupService _backupService; @@ -128,55 +126,55 @@ class BackupNotifier extends StateNotifier { requireCharging != null || triggerDelay != null, ); - final bool wasEnabled = state.backgroundBackup; - final bool wasWifi = state.backupRequireWifi; - final bool wasCharging = state.backupRequireCharging; - final int oldTriggerDelay = state.backupTriggerDelay; - state = state.copyWith( - backgroundBackup: enabled, - backupRequireWifi: requireWifi, - backupRequireCharging: requireCharging, - backupTriggerDelay: triggerDelay, - ); + final bool wasEnabled = state.backgroundBackup; + final bool wasWifi = state.backupRequireWifi; + final bool wasCharging = state.backupRequireCharging; + final int oldTriggerDelay = state.backupTriggerDelay; + state = state.copyWith( + backgroundBackup: enabled, + backupRequireWifi: requireWifi, + backupRequireCharging: requireCharging, + backupTriggerDelay: triggerDelay, + ); - if (state.backgroundBackup) { - bool success = true; - if (!wasEnabled) { - if (!await _backgroundService.isIgnoringBatteryOptimizations()) { - onBatteryInfo(); - } - success &= await _backgroundService.enableService(immediate: true); - } - success &= success && - await _backgroundService.configureService( - requireUnmetered: state.backupRequireWifi, - requireCharging: state.backupRequireCharging, - triggerUpdateDelay: state.backupTriggerDelay, - triggerMaxDelay: state.backupTriggerDelay * 10, - ); - if (success) { - final box = Hive.box(backgroundBackupInfoBox); - await Future.wait([ - box.put(backupRequireWifi, state.backupRequireWifi), - box.put(backupRequireCharging, state.backupRequireCharging), - box.put(backupTriggerDelay, state.backupTriggerDelay), - ]); - } else { - state = state.copyWith( - backgroundBackup: wasEnabled, - backupRequireWifi: wasWifi, - backupRequireCharging: wasCharging, - backupTriggerDelay: oldTriggerDelay, - ); - onError("backup_controller_page_background_configure_error"); - } - } else { - final bool success = await _backgroundService.disableService(); - if (!success) { - state = state.copyWith(backgroundBackup: wasEnabled); - onError("backup_controller_page_background_configure_error"); + if (state.backgroundBackup) { + bool success = true; + if (!wasEnabled) { + if (!await _backgroundService.isIgnoringBatteryOptimizations()) { + onBatteryInfo(); } + success &= await _backgroundService.enableService(immediate: true); } + success &= success && + await _backgroundService.configureService( + requireUnmetered: state.backupRequireWifi, + requireCharging: state.backupRequireCharging, + triggerUpdateDelay: state.backupTriggerDelay, + triggerMaxDelay: state.backupTriggerDelay * 10, + ); + if (success) { + final box = Hive.box(backgroundBackupInfoBox); + await Future.wait([ + box.put(backupRequireWifi, state.backupRequireWifi), + box.put(backupRequireCharging, state.backupRequireCharging), + box.put(backupTriggerDelay, state.backupTriggerDelay), + ]); + } else { + state = state.copyWith( + backgroundBackup: wasEnabled, + backupRequireWifi: wasWifi, + backupRequireCharging: wasCharging, + backupTriggerDelay: oldTriggerDelay, + ); + onError("backup_controller_page_background_configure_error"); + } + } else { + final bool success = await _backgroundService.disableService(); + if (!success) { + state = state.copyWith(backgroundBackup: wasEnabled); + onError("backup_controller_page_background_configure_error"); + } + } } /// @@ -460,6 +458,12 @@ class BackupNotifier extends StateNotifier { } } + void setAvailableAlbums(availableAlbums) { + state = state.copyWith( + availableAlbums: availableAlbums, + ); + } + void _onBackupError(ErrorUploadAsset errorAssetInfo) { ref.watch(errorBackupListProvider.notifier).add(errorAssetInfo); } @@ -573,7 +577,6 @@ class BackupNotifier extends StateNotifier { } Future resumeBackup() async { - // assumes the background service is currently running // if true, waits until it has stopped to update the app state from HiveDB // before actually resuming backup by calling the internal `_resumeBackup` @@ -677,7 +680,6 @@ class BackupNotifier extends StateNotifier { _backgroundService.releaseLock(); } } - } final backupProvider = diff --git a/mobile/lib/modules/backup/views/backup_album_selection_page.dart b/mobile/lib/modules/backup/views/backup_album_selection_page.dart index 9928cb6c89..836f192b55 100644 --- a/mobile/lib/modules/backup/views/backup_album_selection_page.dart +++ b/mobile/lib/modules/backup/views/backup_album_selection_page.dart @@ -5,7 +5,6 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/immich_colors.dart'; -import 'package:immich_mobile/modules/backup/models/available_album.model.dart'; import 'package:immich_mobile/modules/backup/providers/backup.provider.dart'; import 'package:immich_mobile/modules/backup/ui/album_info_card.dart'; import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart'; @@ -19,20 +18,18 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { final selectedBackupAlbums = ref.watch(backupProvider).selectedBackupAlbums; final excludedBackupAlbums = ref.watch(backupProvider).excludedBackupAlbums; final isDarkTheme = Theme.of(context).brightness == Brightness.dark; - final albums = useState>( - ref.watch(backupProvider).availableAlbums, - ); + final albums = ref.watch(backupProvider).availableAlbums; useEffect( () { - ref.read(backupProvider.notifier).getBackupInfo(); + ref.watch(backupProvider.notifier).getBackupInfo(); return null; }, [], ); buildAlbumSelectionList() { - if (albums.value.isEmpty) { + if (albums.isEmpty) { return const Center( child: ImmichLoadingIndicator(), ); @@ -42,17 +39,17 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { height: 265, child: ListView.builder( scrollDirection: Axis.horizontal, - itemCount: albums.value.length, + itemCount: albums.length, physics: const BouncingScrollPhysics(), itemBuilder: ((context, index) { - var thumbnailData = albums.value[index].thumbnailData; + var thumbnailData = albums[index].thumbnailData; return Padding( padding: index == 0 ? const EdgeInsets.only(left: 16.00) : const EdgeInsets.all(0), child: AlbumInfoCard( imageData: thumbnailData, - albumInfo: albums.value[index], + albumInfo: albums[index], ), ); }), @@ -142,7 +139,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { padding: const EdgeInsets.only(left: 16.0, right: 16, bottom: 8.0), child: TextFormField( onChanged: (searchValue) { - albums.value = ref + var avaialbleAlbums = ref .watch(backupProvider) .availableAlbums .where( @@ -151,6 +148,10 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { .contains(searchValue.toLowerCase()), ) .toList(); + + ref + .read(backupProvider.notifier) + .setAvailableAlbums(avaialbleAlbums); }, decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric( diff --git a/mobile/lib/modules/backup/views/backup_controller_page.dart b/mobile/lib/modules/backup/views/backup_controller_page.dart index 929fb87142..73858b8344 100644 --- a/mobile/lib/modules/backup/views/backup_controller_page.dart +++ b/mobile/lib/modules/backup/views/backup_controller_page.dart @@ -592,18 +592,23 @@ class BackupControllerPage extends HookConsumerWidget { BackupInfoCard( title: "backup_controller_page_total".tr(), subtitle: "backup_controller_page_total_sub".tr(), - info: "${backupState.allUniqueAssets.length}", + info: ref.watch(backupProvider).availableAlbums.isEmpty + ? "..." + : "${backupState.allUniqueAssets.length}", ), BackupInfoCard( title: "backup_controller_page_backup".tr(), subtitle: "backup_controller_page_backup_sub".tr(), - info: "${backupState.selectedAlbumsBackupAssetsIds.length}", + info: ref.watch(backupProvider).availableAlbums.isEmpty + ? "..." + : "${backupState.selectedAlbumsBackupAssetsIds.length}", ), BackupInfoCard( title: "backup_controller_page_remainder".tr(), subtitle: "backup_controller_page_remainder_sub".tr(), - info: - "${backupState.allUniqueAssets.length - backupState.selectedAlbumsBackupAssetsIds.length}", + info: ref.watch(backupProvider).availableAlbums.isEmpty + ? "..." + : "${backupState.allUniqueAssets.length - backupState.selectedAlbumsBackupAssetsIds.length}", ), const Divider(), buildAutoBackupController(), diff --git a/mobile/lib/modules/home/views/home_page.dart b/mobile/lib/modules/home/views/home_page.dart index d1bdf1406a..86296ae702 100644 --- a/mobile/lib/modules/home/views/home_page.dart +++ b/mobile/lib/modules/home/views/home_page.dart @@ -46,10 +46,10 @@ class HomePage extends HookConsumerWidget { useEffect( () { - ref.read(websocketProvider.notifier).connect(); - ref.read(assetProvider.notifier).getAllAsset(); - ref.read(albumProvider.notifier).getAllAlbums(); - ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums(); + ref.watch(websocketProvider.notifier).connect(); + ref.watch(assetProvider.notifier).getAllAsset(); + ref.watch(albumProvider.notifier).getAllAlbums(); + ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums(); ref.watch(serverInfoProvider.notifier).getServerVersion(); selectionEnabledHook.addListener(() { @@ -229,8 +229,8 @@ class HomePage extends HookConsumerWidget { top: true, child: Stack( children: [ - ref.watch(assetProvider).renderList == null - || ref.watch(assetProvider).allAssets.isEmpty + ref.watch(assetProvider).renderList == null || + ref.watch(assetProvider).allAssets.isEmpty ? buildLoadingIndicator() : ImmichAssetGrid( renderList: ref.watch(assetProvider).renderList!, diff --git a/mobile/lib/modules/login/providers/authentication.provider.dart b/mobile/lib/modules/login/providers/authentication.provider.dart index 88b49a4b10..1cb760d214 100644 --- a/mobile/lib/modules/login/providers/authentication.provider.dart +++ b/mobile/lib/modules/login/providers/authentication.provider.dart @@ -92,20 +92,25 @@ class AuthenticationNotifier extends StateNotifier { } Future logout() async { - await Future.wait([ - _apiService.authenticationApi.logout(), - Hive.box(userInfoBox).delete(accessTokenKey), - Store.delete(StoreKey.assetETag), - Store.delete(StoreKey.userRemoteId), - _assetCacheService.invalidate(), - _albumCacheService.invalidate(), - _sharedAlbumCacheService.invalidate(), - Hive.box(hiveLoginInfoBox).delete(savedLoginInfoKey) - ]); + try { + await Future.wait([ + _apiService.authenticationApi.logout(), + Hive.box(userInfoBox).delete(accessTokenKey), + Store.delete(StoreKey.assetETag), + Store.delete(StoreKey.userRemoteId), + _assetCacheService.invalidate(), + _albumCacheService.invalidate(), + _sharedAlbumCacheService.invalidate(), + Hive.box(hiveLoginInfoBox).delete(savedLoginInfoKey) + ]); - state = state.copyWith(isAuthenticated: false); + state = state.copyWith(isAuthenticated: false); - return true; + return true; + } catch (e) { + debugPrint("Error logging out $e"); + return false; + } } setAutoBackup(bool backupState) async { diff --git a/mobile/lib/modules/login/ui/change_password_form.dart b/mobile/lib/modules/login/ui/change_password_form.dart index b153f9e24b..f871579488 100644 --- a/mobile/lib/modules/login/ui/change_password_form.dart +++ b/mobile/lib/modules/login/ui/change_password_form.dart @@ -68,7 +68,28 @@ class ChangePasswordForm extends HookConsumerWidget { ), ChangePasswordButton( passwordController: passwordController, - formKey: formKey, + onPressed: () async { + if (formKey.currentState!.validate()) { + var isSuccess = await ref + .read(authenticationProvider.notifier) + .changePassword(passwordController.value.text); + + if (isSuccess) { + bool res = await ref + .read(authenticationProvider.notifier) + .logout(); + + if (res) { + ref.read(backupProvider.notifier).cancelBackup(); + ref.read(assetProvider.notifier).clearAllAsset(); + ref.read(websocketProvider.notifier).disconnect(); + + AutoRouter.of(context) + .replace(const LoginRoute()); + } + } + } + }, ), ], ), @@ -122,7 +143,7 @@ class ConfirmPasswordInput extends StatelessWidget { return TextFormField( obscureText: true, controller: confirmController, - decoration: InputDecoration( + decoration: InputDecoration( labelText: 'change_password_form_confirm_password'.tr(), hintText: 'change_password_form_reenter_new_password'.tr(), border: const OutlineInputBorder(), @@ -135,12 +156,11 @@ class ConfirmPasswordInput extends StatelessWidget { class ChangePasswordButton extends ConsumerWidget { final TextEditingController passwordController; - final GlobalKey formKey; - + final VoidCallback onPressed; const ChangePasswordButton({ Key? key, required this.passwordController, - required this.formKey, + required this.onPressed, }) : super(key: key); @override @@ -153,25 +173,7 @@ class ChangePasswordButton extends ConsumerWidget { elevation: 2, padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 25), ), - onPressed: () async { - if (formKey.currentState!.validate()) { - var isSuccess = await ref - .watch(authenticationProvider.notifier) - .changePassword(passwordController.value.text); - - if (isSuccess) { - bool res = - await ref.watch(authenticationProvider.notifier).logout(); - - if (res) { - ref.watch(backupProvider.notifier).cancelBackup(); - ref.watch(assetProvider.notifier).clearAllAsset(); - ref.watch(websocketProvider.notifier).disconnect(); - AutoRouter.of(context).replace(const LoginRoute()); - } - } - } - }, + onPressed: onPressed, child: Text( 'common_change_password'.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold), diff --git a/mobile/lib/modules/login/ui/login_form.dart b/mobile/lib/modules/login/ui/login_form.dart index 1050da9e50..2c6b2a4a85 100644 --- a/mobile/lib/modules/login/ui/login_form.dart +++ b/mobile/lib/modules/login/ui/login_form.dart @@ -298,10 +298,10 @@ class LoginButton extends ConsumerWidget { ), onPressed: () async { // This will remove current cache asset state of previous user login. - ref.watch(assetProvider.notifier).clearAllAsset(); + ref.read(assetProvider.notifier).clearAllAsset(); var isAuthenticated = - await ref.watch(authenticationProvider.notifier).login( + await ref.read(authenticationProvider.notifier).login( emailController.text, passwordController.text, serverEndpointController.text, @@ -309,12 +309,11 @@ class LoginButton extends ConsumerWidget { if (isAuthenticated) { // Resume backup (if enable) then navigate - - if (ref.watch(authenticationProvider).shouldChangePassword && - !ref.watch(authenticationProvider).isAdmin) { + if (ref.read(authenticationProvider).shouldChangePassword && + !ref.read(authenticationProvider).isAdmin) { AutoRouter.of(context).push(const ChangePasswordRoute()); } else { - ref.watch(backupProvider.notifier).resumeBackup(); + ref.read(backupProvider.notifier).resumeBackup(); AutoRouter.of(context).replace(const TabControllerRoute()); } } else { diff --git a/mobile/lib/routing/auth_guard.dart b/mobile/lib/routing/auth_guard.dart index 692cd4e38c..53693ea1de 100644 --- a/mobile/lib/routing/auth_guard.dart +++ b/mobile/lib/routing/auth_guard.dart @@ -1,5 +1,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/foundation.dart'; +import 'package:hive/hive.dart'; +import 'package:immich_mobile/constants/hive_box.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; @@ -9,6 +11,9 @@ class AuthGuard extends AutoRouteGuard { @override void onNavigation(NavigationResolver resolver, StackRouter router) async { try { + var userInfoHiveBox = await Hive.openBox(userInfoBox); + var accessToken = userInfoHiveBox.get(accessTokenKey); + _apiService.setAccessToken(accessToken); var res = await _apiService.authenticationApi.validateAccessToken(); if (res != null && res.authStatus) { diff --git a/mobile/lib/shared/services/asset.service.dart b/mobile/lib/shared/services/asset.service.dart index 91e3a015db..724cc53b20 100644 --- a/mobile/lib/shared/services/asset.service.dart +++ b/mobile/lib/shared/services/asset.service.dart @@ -46,6 +46,7 @@ class AssetService { ); } catch (e, stack) { log.severe('Error while getting remote assets', e, stack); + debugPrint("[ERROR] [getRemoteAssets] $e"); return Pair(null, etag); } } diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index f2a9e074a8..33de5b74db 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -375,10 +375,10 @@ packages: dependency: "direct main" description: name: flutter_hooks - sha256: "2b202559a4ed3656bbb7aae9d8b335fb0037b23acc7ae3f377d1ba0b95c21aec" + sha256: "6a126f703b89499818d73305e4ce1e3de33b4ae1c5512e3b8eab4b986f46774c" url: "https://pub.dev" source: hosted - version: "0.18.5+1" + version: "0.18.6" flutter_launcher_icons: dependency: "direct dev" description: diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 648c53b1b3..6f068ee891 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -14,8 +14,8 @@ dependencies: path_provider_ios: photo_manager: ^2.5.0 - flutter_hooks: ^0.18.0 - hooks_riverpod: ^2.0.0-dev.0 + flutter_hooks: ^0.18.6 + hooks_riverpod: ^2.2.0 hive: ^2.2.1 hive_flutter: ^1.1.0 cached_network_image: ^3.2.2