소스 검색

New selection overlay for trash screen

ashilkn 2 년 전
부모
커밋
0f570d1c62

+ 8 - 0
lib/models/gallery_type.dart

@@ -184,4 +184,12 @@ extension GalleyTypeExtension on GalleryType {
   bool showUnFavoriteOption() {
     return this == GalleryType.favorite;
   }
+
+  bool showRestoreOption() {
+    return this == GalleryType.trash;
+  }
+
+  bool showPermanentlyDeleteOption() {
+    return this == GalleryType.trash;
+  }
 }

+ 40 - 0
lib/ui/viewer/actions/file_selection_actions_widget.dart

@@ -233,6 +233,28 @@ class _FileSelectionActionWidgetState extends State<FileSelectionActionWidget> {
       );
     }
 
+    if (widget.type.showRestoreOption()) {
+      secondList.add(
+        BlurMenuItemWidget(
+          leadingIcon: Icons.visibility,
+          labelText: "Restore",
+          menuItemColor: colorScheme.fillFaint,
+          onTap: _restore,
+        ),
+      );
+    }
+
+    if (widget.type.showPermanentlyDeleteOption()) {
+      secondList.add(
+        BlurMenuItemWidget(
+          leadingIcon: Icons.delete_forever_outlined,
+          labelText: "Permanently delete now",
+          menuItemColor: colorScheme.fillFaint,
+          onTap: _permanentlyDelete,
+        ),
+      );
+    }
+
     if (firstList.isNotEmpty || secondList.isNotEmpty) {
       if (firstList.isNotEmpty) {
         items.add(firstList);
@@ -420,4 +442,22 @@ class _FileSelectionActionWidgetState extends State<FileSelectionActionWidget> {
       showShortToast(context, "Link copied to clipboard");
     }
   }
+
+  void _restore() {
+    createCollectionSheet(
+      widget.selectedFiles,
+      null,
+      context,
+      actionType: CollectionActionType.restoreFiles,
+    );
+  }
+
+  Future<void> _permanentlyDelete() async {
+    if (await deleteFromTrash(
+      context,
+      widget.selectedFiles.files.toList(),
+    )) {
+      widget.selectedFiles.clearAll();
+    }
+  }
 }

+ 18 - 1
lib/ui/viewer/actions/file_selection_overlay_bar.dart

@@ -95,11 +95,28 @@ class _FileSelectionOverlayBarState extends State<FileSelectionOverlayBar> {
         ),
       );
     }
+    if (widget.galleryType == GalleryType.trash) {
+      iconsButton.add(
+        IconButtonWidget(
+          icon: Icons.delete_forever_outlined,
+          iconButtonType: IconButtonType.primary,
+          iconColor: iconColor,
+          onTap: () async {
+            if (await deleteFromTrash(
+              context,
+              widget.selectedFiles.files.toList(),
+            )) {
+              widget.selectedFiles.clearAll();
+            }
+          },
+        ),
+      );
+    }
     iconsButton.add(
       IconButtonWidget(
         icon: Icons.adaptive.share_outlined,
         iconButtonType: IconButtonType.primary,
-        iconColor: getEnteColorScheme(context).blurStrokeBase,
+        iconColor: iconColor,
         onTap: () => shareSelected(
           context,
           shareButtonKey,

+ 0 - 627
lib/ui/viewer/gallery/gallery_overlay_widget.dart

@@ -1,627 +0,0 @@
-import 'dart:async';
-import 'dart:io';
-import 'dart:ui';
-
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/material.dart';
-import 'package:logging/logging.dart';
-import 'package:photos/core/configuration.dart';
-import 'package:photos/core/event_bus.dart';
-import 'package:photos/ente_theme_data.dart';
-import 'package:photos/events/subscription_purchased_event.dart';
-import 'package:photos/models/collection.dart';
-import 'package:photos/models/gallery_type.dart';
-import 'package:photos/models/magic_metadata.dart';
-import 'package:photos/models/selected_files.dart';
-import 'package:photos/services/collections_service.dart';
-import 'package:photos/services/hidden_service.dart';
-import 'package:photos/ui/create_collection_sheet.dart';
-import 'package:photos/utils/delete_file_util.dart';
-import 'package:photos/utils/dialog_util.dart';
-import 'package:photos/utils/magic_util.dart';
-import 'package:photos/utils/share_util.dart';
-import 'package:photos/utils/toast_util.dart';
-
-class GalleryOverlayWidget extends StatefulWidget {
-  final GalleryType type;
-  final SelectedFiles selectedFiles;
-  final String? path;
-  final Collection? collection;
-
-  const GalleryOverlayWidget(
-    this.type,
-    this.selectedFiles, {
-    this.path,
-    this.collection,
-    Key? key,
-  }) : super(key: key);
-
-  @override
-  State<GalleryOverlayWidget> createState() => _GalleryOverlayWidgetState();
-}
-
-class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
-  late StreamSubscription _userAuthEventSubscription;
-  late Function() _selectedFilesListener;
-  final GlobalKey shareButtonKey = GlobalKey();
-
-  @override
-  void initState() {
-    _selectedFilesListener = () {
-      setState(() {});
-    };
-    widget.selectedFiles.addListener(_selectedFilesListener);
-    _userAuthEventSubscription =
-        Bus.instance.on<SubscriptionPurchasedEvent>().listen((event) {
-      setState(() {});
-    });
-    super.initState();
-  }
-
-  @override
-  void dispose() {
-    _userAuthEventSubscription.cancel();
-    widget.selectedFiles.removeListener(_selectedFilesListener);
-    super.dispose();
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    final bool filesAreSelected = widget.selectedFiles.files.isNotEmpty;
-    final bottomPadding = Platform.isAndroid ? 0.0 : 12.0;
-    return Padding(
-      padding: EdgeInsets.only(bottom: bottomPadding),
-      child: AnimatedContainer(
-        duration: const Duration(milliseconds: 300),
-        curve: Curves.easeInOut,
-        height: filesAreSelected ? 108 : 0,
-        child: AnimatedOpacity(
-          duration: const Duration(milliseconds: 100),
-          opacity: filesAreSelected ? 1.0 : 0.0,
-          curve: Curves.easeIn,
-          child: IgnorePointer(
-            ignoring: !filesAreSelected,
-            child: OverlayWidget(
-              widget.type,
-              widget.selectedFiles,
-              path: widget.path,
-              collection: widget.collection,
-            ),
-          ),
-        ),
-      ),
-    );
-  }
-}
-
-class OverlayWidget extends StatefulWidget {
-  final GalleryType type;
-  final SelectedFiles selectedFiles;
-  final String? path;
-  final Collection? collection;
-
-  const OverlayWidget(
-    this.type,
-    this.selectedFiles, {
-    this.path,
-    this.collection,
-    Key? key,
-  }) : super(key: key);
-
-  @override
-  State<OverlayWidget> createState() => _OverlayWidgetState();
-}
-
-class _OverlayWidgetState extends State<OverlayWidget> {
-  final _logger = Logger("GalleryOverlay");
-  late StreamSubscription _userAuthEventSubscription;
-  late Function() _selectedFilesListener;
-  final GlobalKey shareButtonKey = GlobalKey();
-
-  @override
-  void initState() {
-    _selectedFilesListener = () {
-      setState(() {});
-    };
-    widget.selectedFiles.addListener(_selectedFilesListener);
-    _userAuthEventSubscription =
-        Bus.instance.on<SubscriptionPurchasedEvent>().listen((event) {
-      setState(() {});
-    });
-    super.initState();
-  }
-
-  @override
-  void dispose() {
-    _userAuthEventSubscription.cancel();
-    widget.selectedFiles.removeListener(_selectedFilesListener);
-    super.dispose();
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      color: Colors.transparent,
-      child: ListView(
-        //ListView is for animation to work without render overflow
-        physics: const NeverScrollableScrollPhysics(),
-        children: [
-          Padding(
-            padding: const EdgeInsets.symmetric(horizontal: 12),
-            child: Container(
-              decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),
-              child: ClipRRect(
-                borderRadius: BorderRadius.circular(8),
-                child: BackdropFilter(
-                  filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
-                  child: Container(
-                    color: Theme.of(context)
-                        .colorScheme
-                        .frostyBlurBackdropFilterColor,
-                    width: double.infinity,
-                    child: Row(
-                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                      children: [
-                        Padding(
-                          padding: const EdgeInsets.fromLTRB(13, 13, 0, 13),
-                          child: Text(
-                            widget.selectedFiles.files.length.toString() +
-                                ' selected',
-                            style: Theme.of(context)
-                                .textTheme
-                                .subtitle2!
-                                .copyWith(
-                                  fontWeight: FontWeight.w600,
-                                  color:
-                                      Theme.of(context).colorScheme.iconColor,
-                                ),
-                          ),
-                        ),
-                        Row(
-                          children: _getActions(context),
-                        )
-                      ],
-                    ),
-                  ),
-                ),
-              ),
-            ),
-          ),
-          const Padding(padding: EdgeInsets.symmetric(vertical: 8)),
-          Row(
-            mainAxisAlignment: MainAxisAlignment.center,
-            children: [
-              ClipRRect(
-                borderRadius: BorderRadius.circular(24),
-                child: GestureDetector(
-                  onTap: _clearSelectedFiles,
-                  child: BackdropFilter(
-                    filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
-                    child: Container(
-                      padding: const EdgeInsets.symmetric(vertical: 8),
-                      //height: 32,
-                      width: 86,
-                      color: Theme.of(context)
-                          .colorScheme
-                          .frostyBlurBackdropFilterColor,
-                      child: Center(
-                        child: Text(
-                          'Cancel',
-                          style: Theme.of(context)
-                              .textTheme
-                              .subtitle2!
-                              .copyWith(
-                                fontWeight: FontWeight.w600,
-                                color: Theme.of(context).colorScheme.iconColor,
-                              ),
-                        ),
-                      ),
-                    ),
-                  ),
-                ),
-              ),
-            ],
-          ),
-        ],
-      ),
-    );
-  }
-
-  void _clearSelectedFiles() {
-    widget.selectedFiles.clearAll();
-  }
-
-  List<Widget> _getActions(BuildContext context) {
-    final List<Widget> actions = <Widget>[];
-    if (widget.type == GalleryType.trash) {
-      _addTrashAction(actions);
-      return actions;
-    }
-    // skip add button for incoming collection till this feature is implemented
-    if (Configuration.instance.hasConfiguredAccount() &&
-        widget.type != GalleryType.sharedCollection &&
-        widget.type != GalleryType.hidden) {
-      IconData iconData = Platform.isAndroid ? Icons.add : CupertinoIcons.add;
-      // show upload icon instead of add for files selected in local gallery
-      if (widget.type == GalleryType.localFolder) {
-        iconData = Icons.cloud_upload_outlined;
-      }
-      actions.add(
-        Tooltip(
-          message: "add",
-          child: IconButton(
-            color: Theme.of(context).colorScheme.iconColor,
-            icon: Icon(iconData),
-            onPressed: () async {
-              await onActionSelected("add");
-            },
-          ),
-        ),
-      );
-    }
-
-    if (Configuration.instance.hasConfiguredAccount() &&
-        widget.type == GalleryType.ownedCollection &&
-        widget.collection!.type != CollectionType.favorites) {
-      actions.add(
-        Tooltip(
-          message: "Move",
-          child: IconButton(
-            color: Theme.of(context).colorScheme.iconColor,
-            icon: Icon(
-              Platform.isAndroid
-                  ? Icons.arrow_forward
-                  : CupertinoIcons.arrow_right,
-            ),
-            onPressed: () {
-              onActionSelected('move');
-            },
-          ),
-        ),
-      );
-    }
-    actions.add(
-      Tooltip(
-        message: "Share",
-        child: IconButton(
-          color: Theme.of(context).colorScheme.iconColor,
-          key: shareButtonKey,
-          icon: Icon(Platform.isAndroid ? Icons.share : CupertinoIcons.share),
-          onPressed: () {
-            _shareSelected(context);
-          },
-        ),
-      ),
-    );
-    if (widget.type == GalleryType.homepage ||
-        widget.type == GalleryType.archive ||
-        widget.type == GalleryType.hidden ||
-        widget.type == GalleryType.localFolder ||
-        widget.type == GalleryType.searchResults) {
-      actions.add(
-        Tooltip(
-          message: "Delete",
-          child: IconButton(
-            color: Theme.of(context).colorScheme.iconColor,
-            icon:
-                Icon(Platform.isAndroid ? Icons.delete : CupertinoIcons.delete),
-            onPressed: () {
-              _showDeleteSheet(context);
-            },
-          ),
-        ),
-      );
-    } else if (widget.type == GalleryType.ownedCollection) {
-      if (widget.collection!.type == CollectionType.folder) {
-        actions.add(
-          Tooltip(
-            message: "Delete",
-            child: IconButton(
-              color: Theme.of(context).colorScheme.iconColor,
-              icon: Icon(
-                Platform.isAndroid ? Icons.delete : CupertinoIcons.delete,
-              ),
-              onPressed: () {
-                _showDeleteSheet(context);
-              },
-            ),
-          ),
-        );
-      } else {
-        actions.add(
-          Tooltip(
-            message: "Remove",
-            child: IconButton(
-              color: Theme.of(context).colorScheme.iconColor,
-              icon: const Icon(
-                Icons.remove_circle_rounded,
-              ),
-              onPressed: () {
-                _showRemoveFromCollectionSheet(context);
-              },
-            ),
-          ),
-        );
-      }
-    }
-
-    if (widget.type == GalleryType.homepage ||
-        widget.type == GalleryType.archive) {
-      final bool showArchive = widget.type == GalleryType.homepage;
-      if (showArchive) {
-        actions.add(
-          Tooltip(
-            message: 'Archive',
-            child: IconButton(
-              color: Theme.of(context).colorScheme.iconColor,
-              icon: const Icon(
-                Icons.archive_outlined,
-              ),
-              onPressed: () {
-                onActionSelected('archive');
-              },
-            ),
-          ),
-        );
-      } else {
-        actions.insert(
-          0,
-          Tooltip(
-            message: 'Unarchive',
-            child: IconButton(
-              color: Theme.of(context).colorScheme.iconColor,
-              icon: const Icon(
-                Icons.unarchive,
-              ),
-              onPressed: () {
-                onActionSelected('unarchive');
-              },
-            ),
-          ),
-        );
-      }
-    }
-
-    return actions;
-  }
-
-  Future<void> onActionSelected(String value) async {
-    debugPrint("Action Selected $value");
-    switch (value.toLowerCase()) {
-      case 'hide':
-        await _handleHideRequest(context);
-        break;
-      case 'archive':
-        await _handleVisibilityChangeRequest(context, visibilityArchive);
-        break;
-      case 'unarchive':
-        await _handleVisibilityChangeRequest(context, visibilityVisible);
-        break;
-      default:
-        break;
-    }
-  }
-
-  void _addTrashAction(List<Widget> actions) {
-    actions.add(
-      Tooltip(
-        message: "Restore",
-        child: IconButton(
-          color: Theme.of(context).colorScheme.iconColor,
-          icon: const Icon(
-            Icons.restore,
-          ),
-          onPressed: () {
-            createCollectionSheet(
-              widget.selectedFiles,
-              null,
-              context,
-              actionType: CollectionActionType.restoreFiles,
-            );
-          },
-        ),
-      ),
-    );
-    actions.add(
-      Tooltip(
-        message: "Delete permanently",
-        child: IconButton(
-          color: Theme.of(context).colorScheme.iconColor,
-          icon: const Icon(
-            Icons.delete_forever,
-          ),
-          onPressed: () async {
-            if (await deleteFromTrash(
-              context,
-              widget.selectedFiles.files.toList(),
-            )) {
-              _clearSelectedFiles();
-            }
-          },
-        ),
-      ),
-    );
-  }
-
-  Future<void> _handleVisibilityChangeRequest(
-    BuildContext context,
-    int newVisibility,
-  ) async {
-    try {
-      await changeVisibility(
-        context,
-        widget.selectedFiles.files.toList(),
-        newVisibility,
-      );
-    } catch (e, s) {
-      _logger.severe("failed to update file visibility", e, s);
-      await showGenericErrorDialog(context: context);
-    } finally {
-      _clearSelectedFiles();
-    }
-  }
-
-  // note: Keeping this method here so that it can be used whenever we move to
-  // to bottom UI
-  Future<void> _handleHideRequest(BuildContext context) async {
-    try {
-      final hideResult = await CollectionsService.instance
-          .hideFiles(context, widget.selectedFiles.files.toList());
-      if (hideResult) {
-        _clearSelectedFiles();
-      }
-    } catch (e, s) {
-      _logger.severe("failed to update file visibility", e, s);
-      await showGenericErrorDialog(context: context);
-    }
-  }
-
-  void _shareSelected(BuildContext context) {
-    share(
-      context,
-      widget.selectedFiles.files.toList(),
-      shareButtonKey: shareButtonKey,
-    );
-  }
-
-  void _showDeleteSheet(BuildContext context) {
-    final count = widget.selectedFiles.files.length;
-    bool containsUploadedFile = false, containsLocalFile = false;
-    for (final file in widget.selectedFiles.files) {
-      if (file.uploadedFileID != null) {
-        containsUploadedFile = true;
-      }
-      if (file.localID != null) {
-        containsLocalFile = true;
-      }
-    }
-    final actions = <Widget>[];
-    if (containsUploadedFile && containsLocalFile) {
-      actions.add(
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
-            Navigator.of(context, rootNavigator: true).pop();
-            await deleteFilesOnDeviceOnly(
-              context,
-              widget.selectedFiles.files.toList(),
-            );
-            _clearSelectedFiles();
-            showToast(context, "Files deleted from device");
-          },
-          child: const Text("Device"),
-        ),
-      );
-      actions.add(
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
-            Navigator.of(context, rootNavigator: true).pop();
-            await deleteFilesFromRemoteOnly(
-              context,
-              widget.selectedFiles.files.toList(),
-            );
-            _clearSelectedFiles();
-            showShortToast(context, "Moved to trash");
-          },
-          child: const Text("ente"),
-        ),
-      );
-      actions.add(
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
-            Navigator.of(context, rootNavigator: true).pop();
-            await deleteFilesFromEverywhere(
-              context,
-              widget.selectedFiles.files.toList(),
-            );
-            _clearSelectedFiles();
-          },
-          child: const Text("Everywhere"),
-        ),
-      );
-    } else {
-      actions.add(
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
-            Navigator.of(context, rootNavigator: true).pop();
-            await deleteFilesFromEverywhere(
-              context,
-              widget.selectedFiles.files.toList(),
-            );
-            _clearSelectedFiles();
-          },
-          child: const Text("Delete"),
-        ),
-      );
-    }
-    final action = CupertinoActionSheet(
-      title: Text(
-        "Delete " +
-            count.toString() +
-            " file" +
-            (count == 1 ? "" : "s") +
-            (containsUploadedFile && containsLocalFile ? " from" : "?"),
-      ),
-      actions: actions,
-      cancelButton: CupertinoActionSheetAction(
-        child: const Text("Cancel"),
-        onPressed: () {
-          Navigator.of(context, rootNavigator: true).pop();
-        },
-      ),
-    );
-    showCupertinoModalPopup(
-      context: context,
-      builder: (_) => action,
-      barrierColor: Colors.black.withOpacity(0.75),
-    );
-  }
-
-  void _showRemoveFromCollectionSheet(BuildContext context) {
-    final count = widget.selectedFiles.files.length;
-    final action = CupertinoActionSheet(
-      title: Text(
-        "Remove " +
-            count.toString() +
-            " file" +
-            (count == 1 ? "" : "s") +
-            " from " +
-            widget.collection!.name! +
-            "?",
-      ),
-      actions: <Widget>[
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
-            Navigator.of(context, rootNavigator: true).pop();
-            final dialog = createProgressDialog(context, "Removing files...");
-            await dialog.show();
-            try {
-              await CollectionsService.instance.removeFromCollection(
-                widget.collection!.id,
-                widget.selectedFiles.files.toList(),
-              );
-              await dialog.hide();
-              widget.selectedFiles.clearAll();
-            } catch (e, s) {
-              _logger.severe(e, s);
-              await dialog.hide();
-              showGenericErrorDialog(context: context);
-            }
-          },
-          child: const Text("Remove"),
-        ),
-      ],
-      cancelButton: CupertinoActionSheetAction(
-        child: const Text("Cancel"),
-        onPressed: () {
-          Navigator.of(context, rootNavigator: true).pop();
-        },
-      ),
-    );
-    showCupertinoModalPopup(context: context, builder: (_) => action);
-  }
-}

+ 2 - 5
lib/ui/viewer/gallery/trash_page.dart

@@ -9,9 +9,9 @@ import 'package:photos/events/force_reload_trash_page_event.dart';
 import 'package:photos/models/gallery_type.dart';
 import 'package:photos/models/selected_files.dart';
 import 'package:photos/ui/common/bottom_shadow.dart';
+import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
 import 'package:photos/ui/viewer/gallery/gallery.dart';
 import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
-import 'package:photos/ui/viewer/gallery/gallery_overlay_widget.dart';
 import 'package:photos/utils/delete_file_util.dart';
 
 class TrashPage extends StatefulWidget {
@@ -109,10 +109,7 @@ class _TrashPageState extends State<TrashPage> {
               ),
             ),
           ),
-          GalleryOverlayWidget(
-            widget.overlayType,
-            widget._selectedFiles,
-          )
+          FileSelectionOverlayBar(GalleryType.trash, widget._selectedFiles)
         ],
       ),
     );