Merge pull request #825 from ente-io/trash-selection-overlay
New selection overlay for trash screen
This commit is contained in:
commit
236190bd17
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -126,7 +123,7 @@ class _TrashPageState extends State<TrashPage> {
|
|||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Text(
|
||||
'Items show the number the days remaining before permanent deletion',
|
||||
'Items show the number of days remaining before permanent deletion',
|
||||
style:
|
||||
Theme.of(context).textTheme.caption!.copyWith(fontSize: 16),
|
||||
),
|
||||
|
|
|
@ -265,7 +265,7 @@ Future<bool> deleteFromTrash(BuildContext context, List<File> files) async {
|
|||
bool didDeletionStart = false;
|
||||
final result = await showNewChoiceDialog(
|
||||
context,
|
||||
title: "Delete permanently",
|
||||
title: "Permanently delete?",
|
||||
body: "This action cannot be undone",
|
||||
firstButtonLabel: "Delete",
|
||||
isCritical: true,
|
||||
|
@ -300,7 +300,9 @@ Future<bool> deleteFromTrash(BuildContext context, List<File> files) async {
|
|||
Future<bool> emptyTrash(BuildContext context) async {
|
||||
final result = await showNewChoiceDialog(
|
||||
context,
|
||||
title: "Empty trash",
|
||||
title: "Empty trash?",
|
||||
body:
|
||||
"All items in trash will be permanently deleted\n\nThis action cannot be undone",
|
||||
firstButtonLabel: "Empty",
|
||||
isCritical: true,
|
||||
firstButtonOnTap: () async {
|
||||
|
|
Loading…
Reference in a new issue