diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8493baf2..4ed7b121 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -706,6 +706,18 @@ "@fileSharedByDescription": { "description": "The app will show the owner of the file if it's being shared with you by others. The name of the owner is displayed above this line" }, + "emptyTrashbinTooltip": "Empty trash", + "@emptyTrashbinTooltip": { + "description": "Permanently delete all items from trashbin" + }, + "emptyTrashbinConfirmationDialogTitle": "Empty trash", + "@emptyTrashbinConfirmationDialogTitle": { + "description": "Make sure the user wants to delete all items" + }, + "emptyTrashbinConfirmationDialogContent": "All items will be deleted permanently from the server.\n\nThis action is nonreversible", + "@emptyTrashbinConfirmationDialogContent": { + "description": "Make sure the user wants to delete all items" + }, "errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues", "@errorUnauthenticated": { diff --git a/lib/l10n/untranslated-messages.txt b/lib/l10n/untranslated-messages.txt index 25a3cdb5..5ced2d02 100644 --- a/lib/l10n/untranslated-messages.txt +++ b/lib/l10n/untranslated-messages.txt @@ -27,7 +27,10 @@ "useAsAlbumCoverTooltip", "helpTooltip", "removeFromAlbumTooltip", - "fileSharedByDescription" + "fileSharedByDescription", + "emptyTrashbinTooltip", + "emptyTrashbinConfirmationDialogTitle", + "emptyTrashbinConfirmationDialogContent" ], "es": [ @@ -38,7 +41,10 @@ "settingsForceRotationDescription", "helpTooltip", "removeFromAlbumTooltip", - "fileSharedByDescription" + "fileSharedByDescription", + "emptyTrashbinTooltip", + "emptyTrashbinConfirmationDialogTitle", + "emptyTrashbinConfirmationDialogContent" ], "fr": [ @@ -49,7 +55,10 @@ "settingsForceRotationDescription", "helpTooltip", "removeFromAlbumTooltip", - "fileSharedByDescription" + "fileSharedByDescription", + "emptyTrashbinTooltip", + "emptyTrashbinConfirmationDialogTitle", + "emptyTrashbinConfirmationDialogContent" ], "ru": [ @@ -60,6 +69,9 @@ "settingsForceRotationDescription", "helpTooltip", "removeFromAlbumTooltip", - "fileSharedByDescription" + "fileSharedByDescription", + "emptyTrashbinTooltip", + "emptyTrashbinConfirmationDialogTitle", + "emptyTrashbinConfirmationDialogContent" ] } diff --git a/lib/widget/trashbin_browser.dart b/lib/widget/trashbin_browser.dart index c8956981..c92b452c 100644 --- a/lib/widget/trashbin_browser.dart +++ b/lib/widget/trashbin_browser.dart @@ -169,17 +169,17 @@ class _TrashbinBrowserState extends State _onSelectionAppBarRestorePressed(); }, ), - PopupMenuButton<_AppBarMenuOption>( + PopupMenuButton<_SelectionAppBarMenuOption>( tooltip: MaterialLocalizations.of(context).moreButtonTooltip, itemBuilder: (context) => [ PopupMenuItem( - value: _AppBarMenuOption.delete, + value: _SelectionAppBarMenuOption.delete, child: Text(L10n.of(context).deletePermanentlyTooltip), ), ], onSelected: (option) { switch (option) { - case _AppBarMenuOption.delete: + case _SelectionAppBarMenuOption.delete: _onSelectionAppBarDeletePressed(context); break; @@ -209,6 +209,26 @@ class _TrashbinBrowserState extends State Pref.inst().setAlbumBrowserZoomLevel(_thumbZoomLevel); }, ), + PopupMenuButton<_AppBarMenuOption>( + tooltip: MaterialLocalizations.of(context).moreButtonTooltip, + itemBuilder: (context) => [ + PopupMenuItem( + value: _AppBarMenuOption.empty, + child: Text(L10n.of(context).emptyTrashbinTooltip), + ), + ], + onSelected: (option) { + switch (option) { + case _AppBarMenuOption.empty: + _onEmptyTrashPressed(context); + break; + + default: + _log.shout("[_buildNormalAppBar] Unknown option: $option"); + break; + } + }, + ), ], ); } @@ -236,6 +256,25 @@ class _TrashbinBrowserState extends State TrashbinViewerArguments(widget.account, _backingFiles, index)); } + void _onEmptyTrashPressed(BuildContext context) async { + showDialog( + context: context, + builder: (_) => AlertDialog( + title: Text(L10n.of(context).emptyTrashbinConfirmationDialogTitle), + content: Text(L10n.of(context).emptyTrashbinConfirmationDialogContent), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + _deleteFiles(context, _backingFiles); + }, + child: Text(L10n.of(context).confirmButtonLabel), + ), + ], + ), + ); + } + Future _onSelectionAppBarRestorePressed() async { SnackBarManager().showSnackBar(SnackBar( content: Text(L10n.of(context) @@ -343,11 +382,6 @@ class _TrashbinBrowserState extends State } Future _deleteSelected(BuildContext context) async { - SnackBarManager().showSnackBar(SnackBar( - content: Text(L10n.of(context) - .deleteSelectedProcessingNotification(selectedListItems.length)), - duration: k.snackBarDurationShort, - )); final selectedFiles = selectedListItems .whereType<_FileListItem>() .map((e) => e.file) @@ -355,14 +389,23 @@ class _TrashbinBrowserState extends State setState(() { clearSelectedItems(); }); + return _deleteFiles(context, selectedFiles); + } + + Future _deleteFiles(BuildContext context, List files) async { + SnackBarManager().showSnackBar(SnackBar( + content: Text( + L10n.of(context).deleteSelectedProcessingNotification(files.length)), + duration: k.snackBarDurationShort, + )); final fileRepo = FileRepo(FileCachedDataSource()); final failures = []; - for (final f in selectedFiles) { + for (final f in files) { try { await Remove(fileRepo, null)(widget.account, f); } catch (e, stacktrace) { _log.shout( - "[_deleteSelected] Failed while removing file" + + "[_deleteFiles] Failed while removing file" + (kDebugMode ? ": ${f.path}" : ""), e, stacktrace); @@ -486,5 +529,9 @@ class _VideoListItem extends _FileListItem { } enum _AppBarMenuOption { + empty, +} + +enum _SelectionAppBarMenuOption { delete, }