Просмотр исходного кода

chore(mobile): Bump to Flutter 3.13 (#3767)

* Bump to Flutter 3.13.0

* Updates permission status

* Adds hidden to app livecycle state

* Updates and switches to WakelockPlus

* bump flutter version github action

* mobile test version

* fix format

* video player

* video uri

* ios test

* Update android target sdk requirement to PlayStore

---------

Co-authored-by: Alex Tran <Alex.Tran@conductix.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
martyfuhry 1 год назад
Родитель
Сommit
6243bce46c
57 измененных файлов с 356 добавлено и 307 удалено
  1. 1 1
      .github/workflows/build-mobile.yml
  2. 1 1
      .github/workflows/static_analysis.yml
  3. 1 1
      .github/workflows/test.yml
  4. 1 1
      mobile/.fvm/fvm_config.json
  5. 1 1
      mobile/android/app/build.gradle
  6. 1 1
      mobile/android/app/src/main/AndroidManifest.xml
  7. 13 13
      mobile/ios/Podfile.lock
  8. 1 1
      mobile/ios/Runner.xcodeproj/project.pbxproj
  9. 1 1
      mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
  10. 4 0
      mobile/lib/main.dart
  11. 3 3
      mobile/lib/modules/album/ui/album_thumbnail_listtile.dart
  12. 1 1
      mobile/lib/modules/album/ui/album_viewer_appbar.dart
  13. 2 2
      mobile/lib/modules/album/views/library_page.dart
  14. 2 2
      mobile/lib/modules/album/views/select_additional_user_for_sharing_page.dart
  15. 2 2
      mobile/lib/modules/album/views/select_user_for_sharing_page.dart
  16. 1 1
      mobile/lib/modules/album/views/sharing_page.dart
  17. 2 2
      mobile/lib/modules/archive/views/archive_page.dart
  18. 1 1
      mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart
  19. 1 1
      mobile/lib/modules/asset_viewer/ui/top_control_app_bar.dart
  20. 7 8
      mobile/lib/modules/asset_viewer/views/video_viewer_page.dart
  21. 1 1
      mobile/lib/modules/backup/background_service/background.service.dart
  22. 1 1
      mobile/lib/modules/backup/providers/backup.provider.dart
  23. 2 2
      mobile/lib/modules/backup/ui/album_info_card.dart
  24. 1 1
      mobile/lib/modules/backup/ui/current_backup_asset_info_box.dart
  25. 2 2
      mobile/lib/modules/backup/views/backup_album_selection_page.dart
  26. 7 7
      mobile/lib/modules/backup/views/backup_controller_page.dart
  27. 1 1
      mobile/lib/modules/backup/views/failed_backup_status_page.dart
  28. 2 2
      mobile/lib/modules/favorite/views/favorites_page.dart
  29. 1 1
      mobile/lib/modules/home/ui/asset_grid/group_divider_title.dart
  30. 1 1
      mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart
  31. 1 1
      mobile/lib/modules/home/ui/asset_grid/immich_asset_grid_view.dart
  32. 1 1
      mobile/lib/modules/home/ui/control_bottom_app_bar.dart
  33. 1 1
      mobile/lib/modules/home/ui/profile_drawer/profile_drawer.dart
  34. 1 1
      mobile/lib/modules/home/ui/profile_drawer/profile_drawer_header.dart
  35. 3 3
      mobile/lib/modules/home/views/home_page.dart
  36. 1 1
      mobile/lib/modules/login/ui/change_password_form.dart
  37. 1 1
      mobile/lib/modules/memories/ui/memory_card.dart
  38. 2 1
      mobile/lib/modules/onboarding/views/permission_onboarding_page.dart
  39. 2 2
      mobile/lib/modules/partner/views/partner_page.dart
  40. 2 2
      mobile/lib/modules/search/ui/curated_people_row.dart
  41. 1 1
      mobile/lib/modules/search/ui/search_suggestion_list.dart
  42. 1 1
      mobile/lib/modules/search/ui/thumbnail_with_info.dart
  43. 2 2
      mobile/lib/modules/search/views/person_result_page.dart
  44. 1 1
      mobile/lib/modules/settings/views/settings_page.dart
  45. 1 1
      mobile/lib/routing/router.dart
  46. 20 4
      mobile/lib/shared/models/user.g.dart
  47. 5 0
      mobile/lib/shared/providers/app_state.provider.dart
  48. 1 1
      mobile/lib/shared/services/local_notification.service.dart
  49. 1 1
      mobile/lib/shared/ui/photo_view/src/utils/ignorable_change_notifier.dart
  50. 1 1
      mobile/lib/shared/ui/share_dialog.dart
  51. 1 1
      mobile/lib/shared/ui/user_circle_avatar.dart
  52. 3 3
      mobile/lib/shared/views/app_log_detail_page.dart
  53. 2 2
      mobile/lib/shared/views/tab_controller_page.dart
  54. 2 2
      mobile/lib/shared/views/version_announcement_overlay.dart
  55. 228 204
      mobile/pubspec.lock
  56. 4 4
      mobile/pubspec.yaml
  57. 1 1
      mobile/test/sync_service_test.dart

+ 1 - 1
.github/workflows/build-mobile.yml

@@ -45,7 +45,7 @@ jobs:
         uses: subosito/flutter-action@v2
         with:
           channel: "stable"
-          flutter-version: "3.10.5"
+          flutter-version: "3.13.0"
           cache: true
 
       - name: Create the Keystore

+ 1 - 1
.github/workflows/static_analysis.yml

@@ -23,7 +23,7 @@ jobs:
         uses: subosito/flutter-action@v2
         with:
           channel: "stable"
-          flutter-version: "3.10.5"
+          flutter-version: "3.13.0"
 
       - name: Install dependencies
         run: dart pub get

+ 1 - 1
.github/workflows/test.yml

@@ -149,7 +149,7 @@ jobs:
         uses: subosito/flutter-action@v2
         with:
           channel: "stable"
-          flutter-version: "3.10.5"
+          flutter-version: "3.13.0"
       - name: Run tests
         working-directory: ./mobile
         run: flutter test -j 1

+ 1 - 1
mobile/.fvm/fvm_config.json

@@ -1,4 +1,4 @@
 {
-  "flutterSdkVersion": "3.10.5",
+  "flutterSdkVersion": "3.13.0",
   "flavors": {}
 }

+ 1 - 1
mobile/android/app/build.gradle

@@ -52,7 +52,7 @@ android {
     defaultConfig {
         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
         applicationId "app.alextran.immich"
-        minSdkVersion 23
+        minSdkVersion 26
         targetSdkVersion 33
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName

+ 1 - 1
mobile/android/app/src/main/AndroidManifest.xml

@@ -56,7 +56,7 @@
 
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
   <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

+ 13 - 13
mobile/ios/Podfile.lock

@@ -33,7 +33,7 @@ PODS:
     - FlutterMacOS
   - path_provider_ios (0.0.1):
     - Flutter
-  - permission_handler_apple (9.0.4):
+  - permission_handler_apple (9.1.1):
     - Flutter
   - photo_manager (2.0.0):
     - Flutter
@@ -53,7 +53,7 @@ PODS:
     - Flutter
   - video_player_avfoundation (0.0.1):
     - Flutter
-  - wakelock (0.0.1):
+  - wakelock_plus (0.0.1):
     - Flutter
 
 DEPENDENCIES:
@@ -78,7 +78,7 @@ DEPENDENCIES:
   - sqflite (from `.symlinks/plugins/sqflite/ios`)
   - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
   - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`)
-  - wakelock (from `.symlinks/plugins/wakelock/ios`)
+  - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
 
 SPEC REPOS:
   trunk:
@@ -130,8 +130,8 @@ EXTERNAL SOURCES:
     :path: ".symlinks/plugins/url_launcher_ios/ios"
   video_player_avfoundation:
     :path: ".symlinks/plugins/video_player_avfoundation/ios"
-  wakelock:
-    :path: ".symlinks/plugins/wakelock/ios"
+  wakelock_plus:
+    :path: ".symlinks/plugins/wakelock_plus/ios"
 
 SPEC CHECKSUMS:
   connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
@@ -141,26 +141,26 @@ SPEC CHECKSUMS:
   flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
   flutter_udid: 0848809dbed4c055175747ae6a45a8b4f6771e1c
   flutter_web_auth: c25208760459cec375a3c39f6a8759165ca0fa4d
-  fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0
+  fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
   FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
   image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
   integration_test: 13825b8a9334a850581300559b8839134b124670
   isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
-  package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
-  path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
+  package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
+  path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
   path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
-  permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
+  permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
   photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604
   ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
   SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
-  share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
-  shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
+  share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
+  shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
   sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
   Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
   url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
   video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126
-  wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
+  wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
 
 PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
 
-COCOAPODS: 1.12.1
+COCOAPODS: 1.11.3

+ 1 - 1
mobile/ios/Runner.xcodeproj/project.pbxproj

@@ -171,7 +171,7 @@
 		97C146E61CF9000F007C117D /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1300;
+				LastUpgradeCheck = 1430;
 				ORGANIZATIONNAME = "";
 				TargetAttributes = {
 					97C146ED1CF9000F007C117D = {

+ 1 - 1
mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1300"
+   LastUpgradeVersion = "1430"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 4 - 0
mobile/lib/main.dart

@@ -139,6 +139,10 @@ class ImmichAppState extends ConsumerState<ImmichApp>
         debugPrint("[APP STATE] detached");
         ref.read(appStateProvider.notifier).handleAppDetached();
         break;
+      case AppLifecycleState.hidden:
+        debugPrint("[APP STATE] hidden");
+        ref.read(appStateProvider.notifier).handleAppHidden();
+        break;
     }
   }
 

+ 3 - 3
mobile/lib/modules/album/ui/album_thumbnail_listtile.dart

@@ -49,7 +49,7 @@ class AlbumThumbnailListTile extends StatelessWidget {
           type: ThumbnailFormat.JPEG,
         ),
         httpHeaders: {
-          "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}"
+          "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
         },
         cacheKey: getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.JPEG),
         errorWidget: (context, url, error) =>
@@ -105,9 +105,9 @@ class AlbumThumbnailListTile extends StatelessWidget {
                           style: TextStyle(
                             fontSize: 12,
                           ),
-                        ).tr()
+                        ).tr(),
                     ],
-                  )
+                  ),
                 ],
               ),
             ),

+ 1 - 1
mobile/lib/modules/album/ui/album_viewer_appbar.dart

@@ -250,7 +250,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
                   if (selected.isEmpty &&
                       onAddPhotos != null &&
                       userId == album.ownerId)
-                    ...ownerActions
+                    ...ownerActions,
                 ],
               ),
             ),

+ 2 - 2
mobile/lib/modules/album/views/library_page.dart

@@ -60,7 +60,7 @@ class LibraryPage extends HookConsumerWidget {
     Widget buildSortButton() {
       final options = [
         "library_page_sort_created".tr(),
-        "library_page_sort_title".tr()
+        "library_page_sort_title".tr(),
       ];
 
       return PopupMenuButton(
@@ -87,7 +87,7 @@ class LibraryPage extends HookConsumerWidget {
                       color: selected ? Theme.of(context).primaryColor : null,
                       fontSize: 12.0,
                     ),
-                  )
+                  ),
                 ],
               ),
             );

+ 2 - 2
mobile/lib/modules/album/views/select_additional_user_for_sharing_page.dart

@@ -102,7 +102,7 @@ class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
                   } else {
                     sharedUsersList.value = {
                       ...sharedUsersList.value,
-                      users[index]
+                      users[index],
                     };
                   }
                 },
@@ -135,7 +135,7 @@ class SelectAdditionalUserForSharingPage extends HookConsumerWidget {
               "share_add",
               style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
             ).tr(),
-          )
+          ),
         ],
       ),
       body: suggestedShareUsers.when(

+ 2 - 2
mobile/lib/modules/album/views/select_user_for_sharing_page.dart

@@ -123,7 +123,7 @@ class SelectUserForSharingPage extends HookConsumerWidget {
                   } else {
                     sharedUsersList.value = {
                       ...sharedUsersList.value,
-                      users[index]
+                      users[index],
                     };
                   }
                 },
@@ -163,7 +163,7 @@ class SelectUserForSharingPage extends HookConsumerWidget {
                 // color: Theme.of(context).primaryColor,
               ),
             ).tr(),
-          )
+          ),
         ],
       ),
       body: suggestedShareUsers.when(

+ 1 - 1
mobile/lib/modules/album/views/sharing_page.dart

@@ -160,7 +160,7 @@ class SharingPage extends HookConsumerWidget {
                   maxLines: 1,
                 ).tr(),
               ),
-            )
+            ),
           ],
         ),
       );

+ 2 - 2
mobile/lib/modules/archive/views/archive_page.dart

@@ -91,7 +91,7 @@ class ArchivePage extends HookConsumerWidget {
                               selectionEnabledHook.value = false;
                             }
                           },
-                  )
+                  ),
                 ],
               ),
             ),
@@ -124,7 +124,7 @@ class ArchivePage extends HookConsumerWidget {
                   ),
                   if (selectionEnabledHook.value) buildBottomBar(),
                   if (processing.value)
-                    const Center(child: ImmichLoadingIndicator())
+                    const Center(child: ImmichLoadingIndicator()),
                 ],
               ),
       ),

+ 1 - 1
mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart

@@ -199,7 +199,7 @@ class ExifBottomSheet extends HookConsumerWidget {
               Text(
                 "${exifInfo!.latitude!.toStringAsFixed(4)}, ${exifInfo.longitude!.toStringAsFixed(4)}",
                 style: const TextStyle(fontSize: 12),
-              )
+              ),
             ],
           ),
         ],

+ 1 - 1
mobile/lib/modules/asset_viewer/ui/top_control_app_bar.dart

@@ -128,7 +128,7 @@ class TopControlAppBar extends HookConsumerWidget {
         if (asset.isLocal && !asset.isRemote) buildUploadButton(),
         if (asset.isRemote && !asset.isLocal) buildDownloadButton(),
         if (asset.isRemote) buildAddToAlbumButtom(),
-        buildMoreInfoButton()
+        buildMoreInfoButton(),
       ],
     );
   }

+ 7 - 8
mobile/lib/modules/asset_viewer/views/video_viewer_page.dart

@@ -11,7 +11,7 @@ import 'package:immich_mobile/shared/models/store.dart';
 import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
 import 'package:photo_manager/photo_manager.dart';
 import 'package:video_player/video_player.dart';
-import 'package:wakelock/wakelock.dart';
+import 'package:wakelock_plus/wakelock_plus.dart';
 
 // ignore: must_be_immutable
 class VideoViewerPage extends HookConsumerWidget {
@@ -136,16 +136,16 @@ class _VideoPlayerState extends State<VideoPlayer> {
     videoPlayerController.addListener(() {
       if (videoPlayerController.value.isInitialized) {
         if (videoPlayerController.value.isPlaying) {
-          Wakelock.enable();
+          WakelockPlus.enable();
           widget.onPlaying?.call();
         } else if (!videoPlayerController.value.isPlaying) {
-          Wakelock.disable();
+          WakelockPlus.disable();
           widget.onPaused?.call();
         }
 
         if (videoPlayerController.value.position ==
             videoPlayerController.value.duration) {
-          Wakelock.disable();
+          WakelockPlus.disable();
           widget.onVideoEnded();
         }
       }
@@ -155,8 +155,8 @@ class _VideoPlayerState extends State<VideoPlayer> {
   Future<void> initializePlayer() async {
     try {
       videoPlayerController = widget.file == null
-          ? VideoPlayerController.network(
-              widget.url!,
+          ? VideoPlayerController.networkUrl(
+              Uri.parse(widget.url!),
               httpHeaders: {"Authorization": "Bearer ${widget.jwtToken}"},
             )
           : VideoPlayerController.file(widget.file!);
@@ -210,8 +210,7 @@ class _VideoPlayerState extends State<VideoPlayer> {
         child: Center(
           child: Stack(
             children: [
-              if (widget.placeholder != null)
-                widget.placeholder!,
+              if (widget.placeholder != null) widget.placeholder!,
               const Center(
                 child: ImmichLoadingIndicator(),
               ),

+ 1 - 1
mobile/lib/modules/backup/background_service/background.service.dart

@@ -90,7 +90,7 @@ class BackgroundService {
           requireUnmetered,
           requireCharging,
           triggerUpdateDelay,
-          triggerMaxDelay
+          triggerMaxDelay,
         ],
       );
       return ok;

+ 1 - 1
mobile/lib/modules/backup/providers/backup.provider.dart

@@ -511,7 +511,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
       state = state.copyWith(
         selectedAlbumsBackupAssetsIds: {
           ...state.selectedAlbumsBackupAssetsIds,
-          deviceAssetId
+          deviceAssetId,
         },
         allAssetsInDatabase: [...state.allAssetsInDatabase, deviceAssetId],
       );

+ 2 - 2
mobile/lib/modules/backup/ui/album_info_card.dart

@@ -174,7 +174,7 @@ class AlbumInfoCard extends HookConsumerWidget {
                     bottom: 10,
                     right: 25,
                     child: buildSelectedTextBox(),
-                  )
+                  ),
                 ],
               ),
             ),
@@ -218,7 +218,7 @@ class AlbumInfoCard extends HookConsumerWidget {
                             }),
                             future: albumInfo.assetCount,
                           ),
-                        )
+                        ),
                       ],
                     ),
                   ),

+ 1 - 1
mobile/lib/modules/backup/ui/current_backup_asset_info_box.dart

@@ -212,7 +212,7 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
                   Text(
                     " ${uploadProgress.toStringAsFixed(0)}%",
                     style: const TextStyle(fontSize: 12),
-                  )
+                  ),
                 ],
               ),
             ),

+ 2 - 2
mobile/lib/modules/backup/views/backup_album_selection_page.dart

@@ -247,7 +247,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
                   child: Wrap(
                     children: [
                       ...buildSelectedAlbumNameChip(),
-                      ...buildExcludedAlbumNameChip()
+                      ...buildExcludedAlbumNameChip(),
                     ],
                   ),
                 ),
@@ -301,7 +301,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
                             .watch(backupProvider)
                             .availableAlbums
                             .length
-                            .toString()
+                            .toString(),
                       ],
                     ),
                     style: const TextStyle(

+ 7 - 7
mobile/lib/modules/backup/views/backup_controller_page.dart

@@ -26,7 +26,7 @@ import 'package:immich_mobile/shared/ui/confirm_dialog.dart';
 import 'package:immich_mobile/shared/ui/immich_toast.dart';
 import 'package:permission_handler/permission_handler.dart';
 import 'package:url_launcher/url_launcher.dart';
-import 'package:wakelock/wakelock.dart';
+import 'package:wakelock_plus/wakelock_plus.dart';
 
 class BackupControllerPage extends HookConsumerWidget {
   const BackupControllerPage({Key? key}) : super(key: key);
@@ -114,7 +114,7 @@ class BackupControllerPage extends HookConsumerWidget {
           );
           return;
         }
-        Wakelock.enable();
+        WakelockPlus.enable();
         const limit = 100;
         final toDelete = await ref
             .read(backupVerificationServiceProvider)
@@ -140,7 +140,7 @@ class BackupControllerPage extends HookConsumerWidget {
           );
         }
       } finally {
-        Wakelock.disable();
+        WakelockPlus.disable();
         checkInProgress.value = false;
       }
     }
@@ -202,7 +202,7 @@ class BackupControllerPage extends HookConsumerWidget {
                 child: const Text('backup_controller_page_storage_format').tr(
                   args: [
                     backupState.serverInfo.diskUse,
-                    backupState.serverInfo.diskSize
+                    backupState.serverInfo.diskSize,
                   ],
                 ),
               ),
@@ -256,7 +256,7 @@ class BackupControllerPage extends HookConsumerWidget {
                     ),
                   ),
                 ),
-              )
+              ),
             ],
           ),
         ),
@@ -624,7 +624,7 @@ class BackupControllerPage extends HookConsumerWidget {
                   style: TextStyle(fontSize: 12),
                 ).tr(),
                 buildSelectedAlbumName(),
-                buildExcludedAlbumName()
+                buildExcludedAlbumName(),
               ],
             ),
           ),
@@ -776,7 +776,7 @@ class BackupControllerPage extends HookConsumerWidget {
             const Divider(),
             const CurrentUploadingAssetInfoBox(),
             if (!hasExclusiveAccess) buildBackgroundBackupInfo(),
-            buildBackupButton()
+            buildBackupButton(),
           ],
         ),
       ),

+ 1 - 1
mobile/lib/modules/backup/views/failed_backup_status_page.dart

@@ -129,7 +129,7 @@ class FailedBackupStatusPage extends HookConsumerWidget {
                         ],
                       ),
                     ),
-                  )
+                  ),
                 ],
               ),
             ),

+ 2 - 2
mobile/lib/modules/favorite/views/favorites_page.dart

@@ -83,7 +83,7 @@ class FavoritesPage extends HookConsumerWidget {
                       style: TextStyle(fontSize: 14),
                     ),
                     onTap: processing.value ? null : unfavorite,
-                  )
+                  ),
                 ],
               ),
             ),
@@ -108,7 +108,7 @@ class FavoritesPage extends HookConsumerWidget {
                         selectionActive: selectionEnabledHook.value,
                         listener: selectionListener,
                       ),
-                      if (selectionEnabledHook.value) buildBottomBar()
+                      if (selectionEnabledHook.value) buildBottomBar(),
                     ],
                   ),
           ),

+ 1 - 1
mobile/lib/modules/home/ui/asset_grid/group_divider_title.dart

@@ -57,7 +57,7 @@ class GroupDividerTitle extends ConsumerWidget {
                     Icons.check_circle_outline_rounded,
                     color: Colors.grey,
                   ),
-          )
+          ),
         ],
       ),
     );

+ 1 - 1
mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart

@@ -89,7 +89,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
                 perRow.value = 7 - scaleFactor.value.toInt();
               }
             };
-          })
+          }),
         },
         child: ImmichAssetGridView(
           onRefresh: onRefresh,

+ 1 - 1
mobile/lib/modules/home/ui/asset_grid/immich_asset_grid_view.dart

@@ -225,7 +225,7 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
               right: i + 1 == num ? 0.0 : widget.margin,
             ),
             color: Colors.grey,
-          )
+          ),
       ],
     );
   }

+ 1 - 1
mobile/lib/modules/home/ui/control_bottom_app_bar.dart

@@ -155,7 +155,7 @@ class ControlBottomAppBar extends ConsumerWidget {
               if (hasRemote)
                 const SliverToBoxAdapter(
                   child: SizedBox(height: 200),
-                )
+                ),
             ],
           ),
         );

+ 1 - 1
mobile/lib/modules/home/ui/profile_drawer/profile_drawer.dart

@@ -108,7 +108,7 @@ class ProfileDrawer extends HookConsumerWidget {
               buildSignOutButton(),
             ],
           ),
-          const ServerInfoBox()
+          const ServerInfoBox(),
         ],
       ),
     );

+ 1 - 1
mobile/lib/modules/home/ui/profile_drawer/profile_drawer_header.dart

@@ -156,7 +156,7 @@ class ProfileDrawerHeader extends HookConsumerWidget {
           Text(
             authState.userEmail,
             style: Theme.of(context).textTheme.labelMedium,
-          )
+          ),
         ],
       ),
     );

+ 3 - 3
mobile/lib/modules/home/views/home_page.dart

@@ -221,7 +221,7 @@ class HomePage extends HookConsumerWidget {
                   namedArgs: {
                     "album": album.name,
                     "added": result.successfullyAdded.toString(),
-                    "failed": result.alreadyInAlbum.length.toString()
+                    "failed": result.alreadyInAlbum.length.toString(),
                   },
                 ),
               );
@@ -323,7 +323,7 @@ class HomePage extends HookConsumerWidget {
                     ).tr(),
                   ),
                 ),
-              )
+              ),
             ],
           ),
         );
@@ -365,7 +365,7 @@ class HomePage extends HookConsumerWidget {
                 enabled: !processing.value,
                 selectionAssetState: selectionAssetState.value,
               ),
-            if (processing.value) const Center(child: ImmichLoadingIndicator())
+            if (processing.value) const Center(child: ImmichLoadingIndicator()),
           ],
         ),
       );

+ 1 - 1
mobile/lib/modules/login/ui/change_password_form.dart

@@ -94,7 +94,7 @@ class ChangePasswordForm extends HookConsumerWidget {
                     ),
                   ],
                 ),
-              )
+              ),
             ],
           ),
         ),

+ 1 - 1
mobile/lib/modules/memories/ui/memory_card.dart

@@ -110,7 +110,7 @@ class MemoryCard extends HookConsumerWidget {
               left: 18.0,
               bottom: 18.0,
               child: buildTitle(),
-            )
+            ),
         ],
       ),
     );

+ 2 - 1
mobile/lib/modules/onboarding/views/permission_onboarding_page.dart

@@ -153,6 +153,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
         child = buildRequestPermission();
         break;
       case PermissionStatus.granted:
+      case PermissionStatus.provisional:
         child = buildPermissionGranted();
         break;
       case PermissionStatus.restricted:
@@ -183,7 +184,7 @@ class PermissionOnboardingPage extends HookConsumerWidget {
                 ),
                 TextButton(
                   child: const Text('permission_onboarding_log_out').tr(),
-                  onPressed: () { 
+                  onPressed: () {
                     ref.read(authenticationProvider.notifier).logout();
                     AutoRouter.of(context).replace(
                       const LoginRoute(),

+ 2 - 2
mobile/lib/modules/partner/views/partner_page.dart

@@ -44,7 +44,7 @@ class PartnerPage extends HookConsumerWidget {
                       Text("${u.firstName} ${u.lastName}"),
                     ],
                   ),
-                )
+                ),
             ],
           );
         },
@@ -151,7 +151,7 @@ class PartnerPage extends HookConsumerWidget {
                 availableUsers.whenOrNull(data: (data) => addNewUsersHandler),
             icon: const Icon(Icons.person_add),
             tooltip: "partner_page_add_partner".tr(),
-          )
+          ),
         ],
       ),
       body: buildUserList(partners),

+ 2 - 2
mobile/lib/modules/search/ui/curated_people_row.dart

@@ -50,7 +50,7 @@ class CuratedPeopleRow extends StatelessWidget {
       itemBuilder: (context, index) {
         final person = content[index];
         final headers = {
-          "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}"
+          "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
         };
         return Padding(
           padding: const EdgeInsets.only(right: 18.0),
@@ -102,7 +102,7 @@ class CuratedPeopleRow extends StatelessWidget {
                         fontSize: 13.0,
                       ),
                     ),
-                  )
+                  ),
               ],
             ),
           ),

+ 1 - 1
mobile/lib/modules/search/ui/search_suggestion_list.dart

@@ -39,7 +39,7 @@ class SearchSuggestionList extends ConsumerWidget {
                               color: Theme.of(context).primaryColor,
                               fontWeight: FontWeight.bold,
                             ),
-                      )
+                      ),
                     ],
                   ),
                 ),

+ 1 - 1
mobile/lib/modules/search/ui/thumbnail_with_info.dart

@@ -46,7 +46,7 @@ class ThumbnailWithInfo extends StatelessWidget {
                       imageUrl: imageUrl!,
                       httpHeaders: {
                         "Authorization":
-                            "Bearer ${Store.get(StoreKey.accessToken)}"
+                            "Bearer ${Store.get(StoreKey.accessToken)}",
                       },
                       errorWidget: (context, url, error) =>
                           const Icon(Icons.image_not_supported_outlined),

+ 2 - 2
mobile/lib/modules/search/views/person_result_page.dart

@@ -56,7 +56,7 @@ class PersonResultPage extends HookConsumerWidget {
                     style: TextStyle(fontWeight: FontWeight.bold),
                   ),
                   onTap: showEditNameDialog,
-                )
+                ),
               ],
             ),
           );
@@ -134,7 +134,7 @@ class PersonResultPage extends HookConsumerWidget {
                               getFaceThumbnailUrl(personId),
                               headers: {
                                 "Authorization":
-                                    "Bearer ${isar_store.Store.get(isar_store.StoreKey.accessToken)}"
+                                    "Bearer ${isar_store.Store.get(isar_store.StoreKey.accessToken)}",
                               },
                             ),
                           ),

+ 1 - 1
mobile/lib/modules/settings/views/settings_page.dart

@@ -42,7 +42,7 @@ class SettingsPage extends HookConsumerWidget {
               const AssetListSettings(),
               const NotificationSetting(),
               // const ExperimentalSettings(),
-              const AdvancedSettings()
+              const AdvancedSettings(),
             ],
           ).toList(),
         ],

+ 1 - 1
mobile/lib/routing/router.dart

@@ -75,7 +75,7 @@ part 'router.gr.dart';
         AutoRoute(page: HomePage, guards: [AuthGuard, DuplicateGuard]),
         AutoRoute(page: SearchPage, guards: [AuthGuard, DuplicateGuard]),
         AutoRoute(page: SharingPage, guards: [AuthGuard, DuplicateGuard]),
-        AutoRoute(page: LibraryPage, guards: [AuthGuard, DuplicateGuard])
+        AutoRoute(page: LibraryPage, guards: [AuthGuard, DuplicateGuard]),
       ],
       transitionsBuilder: TransitionsBuilders.fadeIn,
     ),

+ 20 - 4
mobile/lib/shared/models/user.g.dart

@@ -157,7 +157,7 @@ User _userDeserialize(
     isPartnerSharedBy: reader.readBoolOrNull(offsets[4]) ?? false,
     isPartnerSharedWith: reader.readBoolOrNull(offsets[5]) ?? false,
     lastName: reader.readString(offsets[6]),
-    memoryEnabled: reader.readBoolOrNull(offsets[7]) ?? true,
+    memoryEnabled: reader.readBoolOrNull(offsets[7]),
     profileImagePath: reader.readStringOrNull(offsets[8]) ?? '',
     updatedAt: reader.readDateTime(offsets[9]),
   );
@@ -186,7 +186,7 @@ P _userDeserializeProp<P>(
     case 6:
       return (reader.readString(offset)) as P;
     case 7:
-      return (reader.readBoolOrNull(offset) ?? true) as P;
+      return (reader.readBoolOrNull(offset)) as P;
     case 8:
       return (reader.readStringOrNull(offset) ?? '') as P;
     case 9:
@@ -979,8 +979,24 @@ extension UserQueryFilter on QueryBuilder<User, User, QFilterCondition> {
     });
   }
 
+  QueryBuilder<User, User, QAfterFilterCondition> memoryEnabledIsNull() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(const FilterCondition.isNull(
+        property: r'memoryEnabled',
+      ));
+    });
+  }
+
+  QueryBuilder<User, User, QAfterFilterCondition> memoryEnabledIsNotNull() {
+    return QueryBuilder.apply(this, (query) {
+      return query.addFilterCondition(const FilterCondition.isNotNull(
+        property: r'memoryEnabled',
+      ));
+    });
+  }
+
   QueryBuilder<User, User, QAfterFilterCondition> memoryEnabledEqualTo(
-      bool value) {
+      bool? value) {
     return QueryBuilder.apply(this, (query) {
       return query.addFilterCondition(FilterCondition.equalTo(
         property: r'memoryEnabled',
@@ -1661,7 +1677,7 @@ extension UserQueryProperty on QueryBuilder<User, User, QQueryProperty> {
     });
   }
 
-  QueryBuilder<User, bool, QQueryOperations> memoryEnabledProperty() {
+  QueryBuilder<User, bool?, QQueryOperations> memoryEnabledProperty() {
     return QueryBuilder.apply(this, (query) {
       return query.addPropertyName(r'memoryEnabled');
     });

+ 5 - 0
mobile/lib/shared/providers/app_state.provider.dart

@@ -21,6 +21,7 @@ enum AppStateEnum {
   paused,
   resumed,
   detached,
+  hidden,
 }
 
 class AppStateNotiifer extends StateNotifier<AppStateEnum> {
@@ -84,6 +85,10 @@ class AppStateNotiifer extends StateNotifier<AppStateEnum> {
     state = AppStateEnum.detached;
     ref.watch(manualUploadProvider.notifier).cancelBackup();
   }
+
+  void handleAppHidden() {
+    state = AppStateEnum.hidden;
+  }
 }
 
 final appStateProvider =

+ 1 - 1
mobile/lib/shared/services/local_notification.service.dart

@@ -102,7 +102,7 @@ class LocalNotificationService {
                       cancelUploadActionID,
                       'Cancel',
                       showsUserInterface: true,
-                    )
+                    ),
                   ]
                 : null,
           )

+ 1 - 1
mobile/lib/shared/ui/photo_view/src/utils/ignorable_change_notifier.dart

@@ -16,7 +16,7 @@ class IgnorableChangeNotifier extends ChangeNotifier {
       if (_ignorableListeners == null) {
         AssertionError([
           'A $runtimeType was used after being disposed.',
-          'Once you have called dispose() on a $runtimeType, it can no longer be used.'
+          'Once you have called dispose() on a $runtimeType, it can no longer be used.',
         ]);
       }
       return true;

+ 1 - 1
mobile/lib/shared/ui/share_dialog.dart

@@ -15,7 +15,7 @@ class ShareDialog extends StatelessWidget {
             margin: const EdgeInsets.only(top: 12),
             child: const Text('share_dialog_preparing')
                 .tr(),
-          )
+          ),
         ],
       ),
     );

+ 1 - 1
mobile/lib/shared/ui/user_circle_avatar.dart

@@ -62,7 +62,7 @@ class UserCircleAvatar extends ConsumerWidget {
                 image: NetworkImage(
                   profileImageUrl,
                   headers: {
-                    "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}"
+                    "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
                   },
                 ),
                 fadeInDuration: const Duration(milliseconds: 200),

+ 3 - 3
mobile/lib/shared/views/app_log_detail_page.dart

@@ -47,7 +47,7 @@ class AppLogDetailPage extends HookConsumerWidget {
                     size: 16.0,
                     color: Theme.of(context).primaryColor,
                   ),
-                )
+                ),
               ],
             ),
             Container(
@@ -106,7 +106,7 @@ class AppLogDetailPage extends HookConsumerWidget {
                     size: 16.0,
                     color: Theme.of(context).primaryColor,
                   ),
-                )
+                ),
               ],
             ),
             Container(
@@ -181,7 +181,7 @@ class AppLogDetailPage extends HookConsumerWidget {
             if (logMessage.context1 != null)
               buildLogContext1(logMessage.context1.toString()),
             if (logMessage.context2 != null)
-              buildStackMessage(logMessage.context2.toString())
+              buildStackMessage(logMessage.context2.toString()),
           ],
         ),
       ),

+ 2 - 2
mobile/lib/shared/views/tab_controller_page.dart

@@ -148,7 +148,7 @@ class TabControllerPage extends HookConsumerWidget {
                 color: Theme.of(context).primaryColor,
               ),
             ),
-          )
+          ),
         ],
       );
     }
@@ -159,7 +159,7 @@ class TabControllerPage extends HookConsumerWidget {
         const HomeRoute(),
         SearchRoute(),
         const SharingRoute(),
-        const LibraryRoute()
+        const LibraryRoute(),
       ],
       builder: (context, child, animation) {
         final tabsRouter = AutoTabsRouter.of(context);

+ 2 - 2
mobile/lib/shared/views/version_announcement_overlay.dart

@@ -99,7 +99,7 @@ class VersionAnnouncementOverlay extends HookConsumerWidget {
                                       text:
                                           "version_announcement_overlay_text_3"
                                               .tr(),
-                                    )
+                                    ),
                                   ],
                                 ),
                               ),
@@ -126,7 +126,7 @@ class VersionAnnouncementOverlay extends HookConsumerWidget {
                                   ),
                                 ).tr(),
                               ),
-                            )
+                            ),
                           ],
                         ),
                       ),

Разница между файлами не показана из-за своего большого размера
+ 228 - 204
mobile/pubspec.lock


+ 4 - 4
mobile/pubspec.yaml

@@ -20,19 +20,19 @@ dependencies:
   flutter_cache_manager: ^3.3.0
   intl: ^0.18.0
   auto_route: ^5.0.1
-  fluttertoast: ^8.0.8
+  fluttertoast: ^8.2.2
   video_player: ^2.2.18
   chewie: ^1.4.0
   badges: ^2.0.2
   socket_io_client: ^2.0.0-beta.4-nullsafety.0
   flutter_map: ^4.0.0
   flutter_udid: ^2.0.0
-  package_info_plus: ^3.1.2
+  package_info_plus: ^4.1.0
   url_launcher: ^6.1.3
   http: 0.13.5
   cancellation_token_http: ^1.1.0
   easy_localization: ^3.0.1
-  share_plus: ^6.3.0
+  share_plus: ^7.1.0
   flutter_displaymode: ^0.4.0
   scrollable_positioned_list: ^0.3.4
   path: ^1.8.1
@@ -48,7 +48,7 @@ dependencies:
   device_info_plus: ^8.1.0
   connectivity_plus: ^4.0.1
   crypto: ^3.0.3 # TODO remove once native crypto is used on iOS
-  wakelock: ^0.6.2
+  wakelock_plus: ^1.1.1
   flutter_local_notifications: ^15.1.0+1
 
   openapi:

+ 1 - 1
mobile/test/sync_service_test.dart

@@ -45,7 +45,7 @@ void main() {
         AlbumSchema,
         UserSchema,
         StoreValueSchema,
-        LoggerMessageSchema
+        LoggerMessageSchema,
       ],
       maxSizeMiB: 256,
       directory: ".",

Некоторые файлы не были показаны из-за большого количества измененных файлов