瀏覽代碼

Merge pull request #778 from ente-io/delete_states

Delete file(s): Switch to new actionSheet
Neeraj Gupta 2 年之前
父節點
當前提交
160e90d322

+ 1 - 0
lib/ui/components/button_widget.dart

@@ -24,6 +24,7 @@ enum ButtonAction {
   first,
   second,
   third,
+  fourth,
   cancel,
   error;
 }

+ 1 - 1
lib/ui/viewer/actions/file_selection_actions_widget.dart

@@ -266,7 +266,7 @@ class _FileSelectionActionWidgetState extends State<FileSelectionActionWidget> {
   }
 
   Future<void> _onDeleteClick() async {
-    showDeleteSheet(context, widget.selectedFiles);
+    return showDeleteSheet(context, widget.selectedFiles);
   }
 
   Future<void> _removeFilesFromAlbum() async {

+ 89 - 49
lib/ui/viewer/file/fading_app_bar.dart

@@ -23,6 +23,9 @@ import 'package:photos/services/hidden_service.dart';
 import 'package:photos/services/ignored_files_service.dart';
 import 'package:photos/services/local_sync_service.dart';
 import 'package:photos/ui/common/progress_dialog.dart';
+import 'package:photos/ui/components/action_sheet_widget.dart';
+import 'package:photos/ui/components/button_widget.dart';
+import 'package:photos/ui/components/models/button_type.dart';
 import 'package:photos/ui/create_collection_page.dart';
 import 'package:photos/ui/viewer/file/custom_app_bar.dart';
 import 'package:photos/utils/delete_file_util.dart';
@@ -229,11 +232,11 @@ class FadingAppBarState extends State<FadingAppBar> {
           }
           return items;
         },
-        onSelected: (dynamic value) {
+        onSelected: (dynamic value) async {
           if (value == 1) {
             _download(widget.file);
           } else if (value == 2) {
-            _showDeleteSheet(widget.file);
+            await _showSingleFileDeleteSheet(widget.file);
           } else if (value == 3) {
             _setAs(widget.file);
           } else if (value == 4) {
@@ -341,71 +344,108 @@ class FadingAppBarState extends State<FadingAppBar> {
     );
   }
 
-  void _showDeleteSheet(File file) {
-    final List<Widget> actions = [];
-    if (file.uploadedFileID == null || file.localID == null) {
-      actions.add(
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
-            await deleteFilesFromEverywhere(context, [file]);
-            Navigator.of(context, rootNavigator: true).pop();
-            widget.onFileRemoved(file);
+  Future<void> _showSingleFileDeleteSheet(File file) async {
+    final List<ButtonWidget> buttons = [];
+    final String fileType = file.fileType == FileType.video ? "video" : "photo";
+    final bool isBothLocalAndRemote =
+        file.uploadedFileID != null && file.localID != null;
+    final bool isLocalOnly =
+        file.uploadedFileID == null && file.localID != null;
+    final bool isRemoteOnly =
+        file.uploadedFileID != null && file.localID == null;
+    final String title = "Delete $fileType${isBothLocalAndRemote ? '' : '?'}";
+    const String bodyHighlight = "It will be deleted from all albums.";
+    String body = "";
+    if (isBothLocalAndRemote) {
+      body = "This $fileType is in both ente and your device.";
+    } else if (isRemoteOnly) {
+      body = "This $fileType will be deleted from ente.";
+    } else if (isLocalOnly) {
+      body = "This $fileType will be deleted from your device.";
+    } else {
+      throw AssertionError("Unexpected state");
+    }
+    // Add option to delete from ente
+    if (isBothLocalAndRemote || isRemoteOnly) {
+      buttons.add(
+        ButtonWidget(
+          labelText: isBothLocalAndRemote ? "Delete from ente" : "Yes, delete",
+          buttonType: ButtonType.neutral,
+          buttonSize: ButtonSize.large,
+          shouldStickToDarkTheme: true,
+          buttonAction: ButtonAction.first,
+          shouldSurfaceExecutionStates: true,
+          isInAlert: true,
+          onTap: () async {
+            await deleteFilesFromRemoteOnly(context, [file]);
+            showShortToast(context, "Moved to trash");
+            // Navigator.of(context, rootNavigator: true).pop();
+            // TODO: Fix behavior when inside a collection
           },
-          child: const Text("Everywhere"),
         ),
       );
-    } else {
-      // uploaded file which is present locally too
-      actions.add(
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
+    }
+    // Add option to delete from local
+    if (isBothLocalAndRemote || isLocalOnly) {
+      buttons.add(
+        ButtonWidget(
+          labelText:
+              isBothLocalAndRemote ? "Delete from device" : "Yes, delete",
+          buttonType: ButtonType.neutral,
+          buttonSize: ButtonSize.large,
+          shouldStickToDarkTheme: true,
+          buttonAction: ButtonAction.second,
+          shouldSurfaceExecutionStates: false,
+          isInAlert: true,
+          onTap: () async {
             await deleteFilesOnDeviceOnly(context, [file]);
-            showShortToast(context, "File deleted from device");
-            Navigator.of(context, rootNavigator: true).pop();
+            // showShortToast(context, "File deleted from device");
+            // Navigator.of(context, rootNavigator: true).pop();
             // TODO: Fix behavior when inside a device folder
           },
-          child: const Text("Device"),
-        ),
-      );
-
-      actions.add(
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
-            await deleteFilesFromRemoteOnly(context, [file]);
-            showShortToast(context, "Moved to trash");
-            Navigator.of(context, rootNavigator: true).pop();
-            // TODO: Fix behavior when inside a collection
-          },
-          child: const Text("ente"),
         ),
       );
+    }
 
-      actions.add(
-        CupertinoActionSheetAction(
-          isDestructiveAction: true,
-          onPressed: () async {
+    if (isBothLocalAndRemote) {
+      buttons.add(
+        ButtonWidget(
+          labelText: "Delete from both",
+          buttonType: ButtonType.neutral,
+          buttonSize: ButtonSize.large,
+          shouldStickToDarkTheme: true,
+          buttonAction: ButtonAction.third,
+          shouldSurfaceExecutionStates: true,
+          isInAlert: true,
+          onTap: () async {
             await deleteFilesFromEverywhere(context, [file]);
             Navigator.of(context, rootNavigator: true).pop();
             widget.onFileRemoved(file);
           },
-          child: const Text("Everywhere"),
         ),
       );
     }
-    final action = CupertinoActionSheet(
-      title: const Text("Delete file?"),
-      actions: actions,
-      cancelButton: CupertinoActionSheetAction(
-        child: const Text("Cancel"),
-        onPressed: () {
-          Navigator.of(context, rootNavigator: true).pop();
-        },
+    buttons.add(
+      const ButtonWidget(
+        labelText: "Cancel",
+        buttonType: ButtonType.secondary,
+        buttonSize: ButtonSize.large,
+        shouldStickToDarkTheme: true,
+        buttonAction: ButtonAction.fourth,
+        isInAlert: true,
       ),
     );
-    showCupertinoModalPopup(context: context, builder: (_) => action);
+    final ButtonAction? result = await showActionSheet(
+      context: context,
+      buttons: buttons,
+      actionSheetType: ActionSheetType.defaultActionSheet,
+      title: title,
+      body: body,
+      bodyHighlight: bodyHighlight,
+    );
+    if (result != null && result == ButtonAction.error) {
+      showGenericErrorDialog(context: context);
+    }
   }
 
   Future<void> _download(File file) async {

+ 87 - 62
lib/utils/delete_file_util.dart

@@ -22,6 +22,9 @@ import 'package:photos/services/sync_service.dart';
 import 'package:photos/services/trash_sync_service.dart';
 import 'package:photos/ui/common/dialogs.dart';
 import 'package:photos/ui/common/linear_progress_dialog.dart';
+import 'package:photos/ui/components/action_sheet_widget.dart';
+import 'package:photos/ui/components/button_widget.dart';
+import 'package:photos/ui/components/models/button_type.dart';
 import 'package:photos/utils/dialog_util.dart';
 import 'package:photos/utils/file_util.dart';
 import 'package:photos/utils/toast_util.dart';
@@ -486,99 +489,121 @@ Future<bool> shouldProceedWithDeletion(BuildContext context) async {
   return choice == DialogUserChoice.secondChoice;
 }
 
-void showDeleteSheet(BuildContext context, SelectedFiles selectedFiles) {
+Future<void> showDeleteSheet(
+  BuildContext context,
+  SelectedFiles selectedFiles,
+) async {
   final count = selectedFiles.files.length;
   bool containsUploadedFile = false, containsLocalFile = false;
   for (final file in selectedFiles.files) {
     if (file.uploadedFileID != null) {
+      debugPrint("${file.toString()} is uploaded");
       containsUploadedFile = true;
     }
     if (file.localID != null) {
+      debugPrint("${file.toString()} has local");
       containsLocalFile = true;
     }
   }
-  final actions = <Widget>[];
-  if (containsUploadedFile && containsLocalFile) {
-    actions.add(
-      CupertinoActionSheetAction(
-        isDestructiveAction: true,
-        onPressed: () async {
-          Navigator.of(context, rootNavigator: true).pop();
-          await deleteFilesOnDeviceOnly(
-            context,
-            selectedFiles.files.toList(),
-          );
-          selectedFiles.clearAll();
-          showToast(context, "Files deleted from device");
-        },
-        child: const Text("Device"),
-      ),
-    );
-    actions.add(
-      CupertinoActionSheetAction(
-        isDestructiveAction: true,
-        onPressed: () async {
-          Navigator.of(context, rootNavigator: true).pop();
+  final List<ButtonWidget> buttons = [];
+  final bool isBothLocalAndRemote = containsUploadedFile && containsLocalFile;
+  final bool isLocalOnly = !containsUploadedFile;
+  final bool isRemoteOnly = !containsLocalFile;
+  final String title = "Delete item${count > 1 ? 's' : ''}"
+      "${isBothLocalAndRemote ? '' : '?'}";
+  final String? bodyHighlight =
+      isBothLocalAndRemote ? "They will be deleted from all albums." : null;
+  String body = "";
+  if (isBothLocalAndRemote) {
+    body = "Some items are in both ente and your device.";
+  } else if (isRemoteOnly) {
+    body = "Selected items will be deleted from all albums and moved to trash.";
+  } else if (isLocalOnly) {
+    body = "These items will be deleted from your device.";
+  } else {
+    throw AssertionError("Unexpected state");
+  }
+  // Add option to delete from ente
+  if (isBothLocalAndRemote || isRemoteOnly) {
+    buttons.add(
+      ButtonWidget(
+        labelText: isBothLocalAndRemote ? "Delete from ente" : "Yes, delete",
+        buttonType: ButtonType.neutral,
+        buttonSize: ButtonSize.large,
+        shouldStickToDarkTheme: true,
+        buttonAction: ButtonAction.first,
+        shouldSurfaceExecutionStates: true,
+        isInAlert: true,
+        onTap: () async {
           await deleteFilesFromRemoteOnly(
             context,
             selectedFiles.files.toList(),
           );
-          selectedFiles.clearAll();
-
           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,
-            selectedFiles.files.toList(),
-          );
-          selectedFiles.clearAll();
+  }
+  // Add option to delete from local
+  if (isBothLocalAndRemote || isLocalOnly) {
+    buttons.add(
+      ButtonWidget(
+        labelText: isBothLocalAndRemote ? "Delete from device" : "Yes, delete",
+        buttonType: ButtonType.neutral,
+        buttonSize: ButtonSize.large,
+        shouldStickToDarkTheme: true,
+        buttonAction: ButtonAction.second,
+        shouldSurfaceExecutionStates: false,
+        isInAlert: true,
+        onTap: () async {
+          await deleteFilesOnDeviceOnly(context, selectedFiles.files.toList());
         },
-        child: const Text("Everywhere"),
       ),
     );
-  } else {
-    actions.add(
-      CupertinoActionSheetAction(
-        isDestructiveAction: true,
-        onPressed: () async {
-          Navigator.of(context, rootNavigator: true).pop();
+  }
+
+  if (isBothLocalAndRemote) {
+    buttons.add(
+      ButtonWidget(
+        labelText: "Delete from both",
+        buttonType: ButtonType.neutral,
+        buttonSize: ButtonSize.large,
+        shouldStickToDarkTheme: true,
+        buttonAction: ButtonAction.third,
+        shouldSurfaceExecutionStates: true,
+        isInAlert: true,
+        onTap: () async {
           await deleteFilesFromEverywhere(
             context,
             selectedFiles.files.toList(),
           );
-          selectedFiles.clearAll();
+          // Navigator.of(context, rootNavigator: true).pop();
+          // widget.onFileRemoved(file);
         },
-        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();
-      },
+  buttons.add(
+    const ButtonWidget(
+      labelText: "Cancel",
+      buttonType: ButtonType.secondary,
+      buttonSize: ButtonSize.large,
+      shouldStickToDarkTheme: true,
+      buttonAction: ButtonAction.fourth,
+      isInAlert: true,
     ),
   );
-  showCupertinoModalPopup(
+  final ButtonAction? result = await showActionSheet(
     context: context,
-    builder: (_) => action,
-    barrierColor: Colors.black.withOpacity(0.75),
+    buttons: buttons,
+    actionSheetType: ActionSheetType.defaultActionSheet,
+    title: title,
+    body: body,
+    bodyHighlight: bodyHighlight,
   );
+  if (result != null && result == ButtonAction.error) {
+    showGenericErrorDialog(context: context);
+  } else {
+    selectedFiles.clearAll();
+  }
 }