ソースを参照

feat(mobile): Multiselect add to favorite from the timeline (#1558)

* multiselect add to favorites
martyfuhry 2 年 前
コミット
b8d2f5b373

+ 12 - 0
mobile/lib/modules/favorite/providers/favorite_provider.dart

@@ -34,6 +34,18 @@ class FavoriteSelectionNotifier extends StateNotifier<Set<String>> {
       state.contains(asset.id),
     );
   }
+
+  Future<void> addToFavorites(Iterable<Asset> assets) {
+    state = state.union(assets.map((a) => a.id).toSet());
+    final futures = assets.map((a) => 
+        ref.watch(assetProvider.notifier).toggleFavorite(
+          a,
+          true,
+        ),
+      );
+
+    return Future.wait(futures);
+  }
 }
 
 final favoriteProvider =

+ 10 - 0
mobile/lib/modules/home/ui/control_bottom_app_bar.dart

@@ -8,6 +8,7 @@ import 'package:immich_mobile/shared/models/album.dart';
 
 class ControlBottomAppBar extends ConsumerWidget {
   final Function onShare;
+  final Function onFavorite;
   final Function onDelete;
   final Function(Album album) onAddToAlbum;
   final void Function() onCreateNewAlbum;
@@ -18,6 +19,7 @@ class ControlBottomAppBar extends ConsumerWidget {
   const ControlBottomAppBar({
     Key? key,
     required this.onShare,
+    required this.onFavorite,
     required this.onDelete,
     required this.sharedAlbums,
     required this.albums,
@@ -37,6 +39,13 @@ class ControlBottomAppBar extends ConsumerWidget {
               onShare();
             },
           ),
+          ControlBoxButton(
+            iconData: Icons.star_rounded,
+            label: "Favorite",
+            onPressed: () {
+              onFavorite();
+            },
+          ),
           ControlBoxButton(
             iconData: Icons.delete_outline_rounded,
             label: "control_bottom_app_bar_delete".tr(),
@@ -51,6 +60,7 @@ class ControlBottomAppBar extends ConsumerWidget {
               );
             },
           ),
+
         ],
       );
     }

+ 29 - 13
mobile/lib/modules/home/views/home_page.dart

@@ -10,6 +10,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:immich_mobile/modules/album/providers/album.provider.dart';
 import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
 import 'package:immich_mobile/modules/album/services/album.service.dart';
+import 'package:immich_mobile/modules/favorite/providers/favorite_provider.dart';
 import 'package:immich_mobile/modules/home/providers/multiselect.provider.dart';
 import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
 import 'package:immich_mobile/modules/home/ui/control_bottom_app_bar.dart';
@@ -83,27 +84,39 @@ class HomePage extends HookConsumerWidget {
         selectionEnabledHook.value = false;
       }
 
-      void onDelete() {
-        ref.watch(assetProvider.notifier).deleteAssets(selection.value);
-        selectionEnabledHook.value = false;
-      }
-
-      Iterable<Asset> remoteOnlySelection() {
+      Iterable<Asset> remoteOnlySelection({String? localErrorMessage}) {
         final Set<Asset> assets = selection.value;
         final bool onlyRemote = assets.every((e) => e.isRemote);
         if (!onlyRemote) {
-          ImmichToast.show(
-            context: context,
-            msg: "Can not add local assets to albums yet, skipping",
-            gravity: ToastGravity.BOTTOM,
-          );
+          if (localErrorMessage != null && localErrorMessage.isNotEmpty) {
+            ImmichToast.show(
+              context: context,
+              msg: localErrorMessage,
+              gravity: ToastGravity.BOTTOM,
+            );
+          }
           return assets.where((a) => a.isRemote);
         }
         return assets;
       }
 
+      void onFavoriteAssets() {
+        final remoteAssests = remoteOnlySelection(
+          localErrorMessage: 'Can not favorite local assets yet, skipping',
+        );
+        ref.watch(favoriteProvider.notifier).addToFavorites(remoteAssests);
+        selectionEnabledHook.value = false;
+      }
+
+      void onDelete() {
+        ref.watch(assetProvider.notifier).deleteAssets(selection.value);
+        selectionEnabledHook.value = false;
+      }
+
       void onAddToAlbum(Album album) async {
-        final Iterable<Asset> assets = remoteOnlySelection();
+        final Iterable<Asset> assets = remoteOnlySelection(
+          localErrorMessage: "Can not add local assets to albums yet, skipping",
+        );
         if (assets.isEmpty) {
           return;
         }
@@ -142,7 +155,9 @@ class HomePage extends HookConsumerWidget {
       }
 
       void onCreateNewAlbum() async {
-        final Iterable<Asset> assets = remoteOnlySelection();
+        final Iterable<Asset> assets = remoteOnlySelection(
+          localErrorMessage: "Can not add local assets to albums yet, skipping",
+        );
         if (assets.isEmpty) {
           return;
         }
@@ -221,6 +236,7 @@ class HomePage extends HookConsumerWidget {
             if (selectionEnabledHook.value)
               ControlBottomAppBar(
                 onShare: onShareAssets,
+                onFavorite: onFavoriteAssets,
                 onDelete: onDelete,
                 onAddToAlbum: onAddToAlbum,
                 albums: albums,

+ 6 - 8
mobile/lib/shared/providers/asset.provider.dart

@@ -277,14 +277,12 @@ class AssetNotifier extends StateNotifier<AssetsState> {
       return asset.isFavorite;
     }
 
-    await _updateAssetsState(
-      state.allAssets.map((a) {
-        if (asset.id == a.id) {
-          return Asset.remote(newAsset);
-        }
-        return a;
-      }).toList(),
-    );
+    final index = state.allAssets.indexWhere((a) => asset.id == a.id);
+    if (index > 0) {
+      state.allAssets.removeAt(index);
+      state.allAssets.insert(index, Asset.remote(newAsset));
+      _updateAssetsState(state.allAssets);
+    }
 
     return newAsset.isFavorite;
   }