ente/lib/ui/viewer/actions/file_selection_actions_widget.dart

464 lines
14 KiB
Dart
Raw Normal View History

import 'package:fast_base58/fast_base58.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/models/collection.dart';
import 'package:photos/models/device_collection.dart';
import 'package:photos/models/file.dart';
2023-01-05 04:04:34 +00:00
import 'package:photos/models/files_split.dart';
import 'package:photos/models/gallery_type.dart';
2022-12-15 11:24:51 +00:00
import 'package:photos/models/magic_metadata.dart';
import 'package:photos/models/selected_files.dart';
2022-12-15 10:02:46 +00:00
import 'package:photos/services/collections_service.dart';
2022-12-15 11:24:51 +00:00
import 'package:photos/services/hidden_service.dart';
import 'package:photos/theme/ente_theme.dart';
2022-12-15 10:02:46 +00:00
import 'package:photos/ui/actions/collection/collection_file_actions.dart';
import 'package:photos/ui/actions/collection/collection_sharing_actions.dart';
2022-12-22 10:31:10 +00:00
import 'package:photos/ui/components/action_sheet_widget.dart';
import 'package:photos/ui/components/blur_menu_item_widget.dart';
import 'package:photos/ui/components/bottom_action_bar/expanded_menu_widget.dart';
2022-12-22 10:31:10 +00:00
import 'package:photos/ui/components/button_widget.dart';
import 'package:photos/ui/components/models/button_type.dart';
2023-01-25 04:57:40 +00:00
import 'package:photos/ui/create_collection_sheet.dart';
2022-12-22 17:13:14 +00:00
import 'package:photos/ui/sharing/manage_links_widget.dart';
2022-12-15 11:24:51 +00:00
import 'package:photos/utils/delete_file_util.dart';
import 'package:photos/utils/magic_util.dart';
2022-12-22 17:13:14 +00:00
import 'package:photos/utils/navigation_util.dart';
import 'package:photos/utils/toast_util.dart';
class FileSelectionActionWidget extends StatefulWidget {
final GalleryType type;
final Collection? collection;
final DeviceCollection? deviceCollection;
final SelectedFiles selectedFiles;
const FileSelectionActionWidget(
this.type,
this.selectedFiles, {
Key? key,
this.collection,
this.deviceCollection,
}) : super(key: key);
@override
State<FileSelectionActionWidget> createState() =>
_FileSelectionActionWidgetState();
}
class _FileSelectionActionWidgetState extends State<FileSelectionActionWidget> {
late int currentUserID;
2023-01-05 04:04:34 +00:00
late FilesSplit split;
2022-12-15 10:02:46 +00:00
late CollectionActions collectionActions;
// _cachedCollectionForSharedLink is primarly used to avoid creating duplicate
// links if user keeps on creating Create link button after selecting
// few files. This link is reset on any selection changed;
Collection? _cachedCollectionForSharedLink;
@override
void initState() {
currentUserID = Configuration.instance.getUserID()!;
split = FilesSplit.split(<File>[], currentUserID);
widget.selectedFiles.addListener(_selectFileChangeListener);
2022-12-15 10:02:46 +00:00
collectionActions = CollectionActions(CollectionsService.instance);
super.initState();
}
@override
void dispose() {
widget.selectedFiles.removeListener(_selectFileChangeListener);
super.dispose();
}
void _selectFileChangeListener() {
if (_cachedCollectionForSharedLink != null) {
_cachedCollectionForSharedLink = null;
}
2023-01-05 04:04:34 +00:00
split = FilesSplit.split(widget.selectedFiles.files, currentUserID);
if (mounted) {
setState(() => {});
}
}
@override
Widget build(BuildContext context) {
final bool showPrefix =
split.pendingUploads.isNotEmpty || split.ownedByOtherUsers.isNotEmpty;
final String suffix = showPrefix
? " (${split.ownedByCurrentUser.length})"
""
: "";
2022-12-16 10:08:35 +00:00
final String suffixInPending = split.ownedByOtherUsers.isNotEmpty
2022-12-16 07:55:07 +00:00
? " (${split.ownedByCurrentUser.length + split.pendingUploads.length})"
""
: "";
final bool anyOwnedFiles =
split.pendingUploads.isNotEmpty || split.ownedByCurrentUser.isNotEmpty;
final bool anyUploadedFiles = split.ownedByCurrentUser.isNotEmpty;
bool showRemoveOption = widget.type.showRemoveFromAlbum();
if (showRemoveOption && widget.type == GalleryType.sharedCollection) {
showRemoveOption = split.ownedByCurrentUser.isNotEmpty;
}
debugPrint('$runtimeType building $mounted');
final colorScheme = getEnteColorScheme(context);
final List<List<BlurMenuItemWidget>> items = [];
final List<BlurMenuItemWidget> firstList = [];
final List<BlurMenuItemWidget> secondList = [];
if (widget.type.showCreateLink()) {
if (_cachedCollectionForSharedLink != null && anyUploadedFiles) {
firstList.add(
BlurMenuItemWidget(
leadingIcon: Icons.copy_outlined,
labelText: "Copy link",
menuItemColor: colorScheme.fillFaint,
onTap: anyUploadedFiles ? _copyLink : null,
),
);
} else {
firstList.add(
BlurMenuItemWidget(
leadingIcon: Icons.link_outlined,
labelText: "Create link$suffix",
menuItemColor: colorScheme.fillFaint,
onTap: anyUploadedFiles ? _onCreatedSharedLinkClicked : null,
),
);
}
}
2022-12-16 10:08:35 +00:00
final showUploadIcon = widget.type == GalleryType.localFolder &&
split.ownedByCurrentUser.isEmpty;
if (widget.type.showAddToAlbum()) {
secondList.add(
BlurMenuItemWidget(
2022-12-16 10:08:35 +00:00
leadingIcon:
showUploadIcon ? Icons.cloud_upload_outlined : Icons.add_outlined,
labelText:
"Add to ${showUploadIcon ? 'ente' : 'album'}$suffixInPending",
menuItemColor: colorScheme.fillFaint,
2022-12-16 07:55:07 +00:00
onTap: anyOwnedFiles ? _addToAlbum : null,
),
);
}
if (widget.type.showMoveToAlbum()) {
secondList.add(
BlurMenuItemWidget(
leadingIcon: Icons.arrow_forward_outlined,
labelText: "Move to album$suffix",
menuItemColor: colorScheme.fillFaint,
2022-12-16 07:55:07 +00:00
onTap: anyUploadedFiles ? _moveFiles : null,
),
);
}
if (showRemoveOption) {
secondList.add(
BlurMenuItemWidget(
leadingIcon: Icons.remove_outlined,
labelText: "Remove from album$suffix",
menuItemColor: colorScheme.fillFaint,
2022-12-16 07:55:07 +00:00
onTap: anyUploadedFiles ? _removeFilesFromAlbum : null,
),
);
}
if (widget.type.showDeleteOption()) {
secondList.add(
BlurMenuItemWidget(
leadingIcon: Icons.delete_outline,
2022-12-16 07:55:07 +00:00
labelText: "Delete$suffixInPending",
menuItemColor: colorScheme.fillFaint,
2022-12-16 07:55:07 +00:00
onTap: anyOwnedFiles ? _onDeleteClick : null,
),
);
}
if (widget.type.showHideOption()) {
secondList.add(
BlurMenuItemWidget(
leadingIcon: Icons.visibility_off_outlined,
labelText: "Hide$suffix",
menuItemColor: colorScheme.fillFaint,
2022-12-16 07:55:07 +00:00
onTap: anyUploadedFiles ? _onHideClick : null,
2022-12-15 11:24:51 +00:00
),
);
} else if (widget.type.showUnHideOption()) {
secondList.add(
2022-12-15 11:24:51 +00:00
BlurMenuItemWidget(
leadingIcon: Icons.visibility_off_outlined,
labelText: "Unhide$suffix",
menuItemColor: colorScheme.fillFaint,
onTap: _onUnhideClick,
),
);
}
if (widget.type.showArchiveOption()) {
secondList.add(
BlurMenuItemWidget(
leadingIcon: Icons.archive_outlined,
labelText: "Archive$suffix",
menuItemColor: colorScheme.fillFaint,
2022-12-16 07:55:07 +00:00
onTap: anyUploadedFiles ? _onArchiveClick : null,
2022-12-15 11:24:51 +00:00
),
);
} else if (widget.type.showUnArchiveOption()) {
secondList.add(
2022-12-15 11:24:51 +00:00
BlurMenuItemWidget(
2022-12-16 07:27:53 +00:00
leadingIcon: Icons.unarchive,
2022-12-15 11:24:51 +00:00
labelText: "Unarchive$suffix",
menuItemColor: colorScheme.fillFaint,
onTap: _onUnArchiveClick,
),
);
}
if (widget.type.showFavoriteOption()) {
secondList.add(
BlurMenuItemWidget(
leadingIcon: Icons.favorite_border_rounded,
labelText: "Favorite$suffix",
menuItemColor: colorScheme.fillFaint,
2022-12-16 07:55:07 +00:00
onTap: anyUploadedFiles ? _onFavoriteClick : null,
),
);
2022-12-15 11:24:51 +00:00
} else if (widget.type.showUnFavoriteOption()) {
secondList.add(
2022-12-15 11:24:51 +00:00
BlurMenuItemWidget(
leadingIcon: Icons.favorite,
labelText: "Remove from favorite$suffix",
menuItemColor: colorScheme.fillFaint,
onTap: _onUnFavoriteClick,
),
);
}
2023-01-27 13:56:29 +00:00
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,
2023-01-27 15:08:05 +00:00
labelText: "Permanently delete",
2023-01-27 13:56:29 +00:00
menuItemColor: colorScheme.fillFaint,
onTap: _permanentlyDelete,
),
);
}
if (firstList.isNotEmpty || secondList.isNotEmpty) {
if (firstList.isNotEmpty) {
items.add(firstList);
}
items.add(secondList);
return ExpandedMenuWidget(
items: items,
);
} else {
// TODO: Return "Select All" here
return const SizedBox.shrink();
}
}
2022-12-15 10:02:46 +00:00
Future<void> _moveFiles() async {
if (split.pendingUploads.isNotEmpty || split.ownedByOtherUsers.isNotEmpty) {
widget.selectedFiles
.unSelectAll(split.pendingUploads.toSet(), skipNotify: true);
widget.selectedFiles
.unSelectAll(split.ownedByOtherUsers.toSet(), skipNotify: true);
}
2023-01-25 04:57:40 +00:00
createCollectionSheet(
widget.selectedFiles,
null,
context,
2023-01-25 04:57:40 +00:00
actionType: CollectionActionType.moveFiles,
);
2022-12-15 10:02:46 +00:00
}
Future<void> _addToAlbum() async {
if (split.ownedByOtherUsers.isNotEmpty) {
widget.selectedFiles
.unSelectAll(split.ownedByOtherUsers.toSet(), skipNotify: true);
}
2023-01-25 04:57:40 +00:00
createCollectionSheet(
2023-01-20 14:57:45 +00:00
widget.selectedFiles,
null,
context,
);
2022-12-15 10:02:46 +00:00
}
2022-12-15 11:24:51 +00:00
Future<void> _onDeleteClick() async {
2023-01-06 07:24:00 +00:00
return showDeleteSheet(context, widget.selectedFiles);
2022-12-15 11:24:51 +00:00
}
2022-12-15 10:02:46 +00:00
Future<void> _removeFilesFromAlbum() async {
2022-12-15 16:25:29 +00:00
if (split.pendingUploads.isNotEmpty || split.ownedByOtherUsers.isNotEmpty) {
widget.selectedFiles
.unSelectAll(split.pendingUploads.toSet(), skipNotify: true);
widget.selectedFiles
.unSelectAll(split.ownedByOtherUsers.toSet(), skipNotify: true);
}
await collectionActions.showRemoveFromCollectionSheetV2(
2022-12-15 10:02:46 +00:00
context,
widget.collection!,
widget.selectedFiles,
);
}
Future<void> _onFavoriteClick() async {
final result = await collectionActions.updateFavorites(
context,
split.ownedByCurrentUser,
true,
);
if (result) {
widget.selectedFiles.clearAll();
}
}
2022-12-15 11:24:51 +00:00
Future<void> _onUnFavoriteClick() async {
final result = await collectionActions.updateFavorites(
context,
split.ownedByCurrentUser,
false,
);
if (result) {
widget.selectedFiles.clearAll();
}
}
Future<void> _onArchiveClick() async {
await changeVisibility(
context,
split.ownedByCurrentUser,
visibilityArchive,
);
widget.selectedFiles.clearAll();
}
Future<void> _onUnArchiveClick() async {
await changeVisibility(
context,
split.ownedByCurrentUser,
visibilityVisible,
);
widget.selectedFiles.clearAll();
}
Future<void> _onHideClick() async {
await CollectionsService.instance.hideFiles(
context,
split.ownedByCurrentUser,
);
widget.selectedFiles.clearAll();
}
Future<void> _onUnhideClick() async {
if (split.pendingUploads.isNotEmpty || split.ownedByOtherUsers.isNotEmpty) {
widget.selectedFiles
.unSelectAll(split.pendingUploads.toSet(), skipNotify: true);
widget.selectedFiles
.unSelectAll(split.ownedByOtherUsers.toSet(), skipNotify: true);
}
2023-01-25 04:57:40 +00:00
createCollectionSheet(
widget.selectedFiles,
null,
context,
2023-01-25 04:57:40 +00:00
actionType: CollectionActionType.unHide,
);
2022-12-15 11:24:51 +00:00
}
Future<void> _onCreatedSharedLinkClicked() async {
if (split.ownedByCurrentUser.isEmpty) {
showShortToast(context, "Can only create link for files owned by you");
return;
}
_cachedCollectionForSharedLink ??= await collectionActions
.createSharedCollectionLink(context, split.ownedByCurrentUser);
2022-12-22 10:31:10 +00:00
final actionResult = await showActionSheet(
context: context,
buttons: [
const ButtonWidget(
labelText: "Copy link",
buttonType: ButtonType.neutral,
buttonSize: ButtonSize.large,
shouldStickToDarkTheme: true,
buttonAction: ButtonAction.first,
isInAlert: true,
),
const ButtonWidget(
2022-12-22 17:13:14 +00:00
labelText: "Manage link",
2022-12-22 10:31:10 +00:00
buttonType: ButtonType.secondary,
buttonSize: ButtonSize.large,
buttonAction: ButtonAction.second,
shouldStickToDarkTheme: true,
isInAlert: true,
2022-12-22 17:13:14 +00:00
),
const ButtonWidget(
labelText: "Done",
buttonType: ButtonType.secondary,
buttonSize: ButtonSize.large,
buttonAction: ButtonAction.third,
shouldStickToDarkTheme: true,
isInAlert: true,
2022-12-22 10:31:10 +00:00
)
],
title: "Public link created",
body: "You can manage your links in the share tab.",
actionSheetType: ActionSheetType.defaultActionSheet,
);
if (actionResult != null && actionResult == ButtonAction.first) {
await _copyLink();
}
2022-12-22 17:13:14 +00:00
if (actionResult != null && actionResult == ButtonAction.second) {
routeToPage(
context,
ManageSharedLinkWidget(collection: _cachedCollectionForSharedLink),
);
}
if (mounted) {
setState(() => {});
}
}
Future<void> _copyLink() async {
if (_cachedCollectionForSharedLink != null) {
final String collectionKey = Base58Encode(
CollectionsService.instance
.getCollectionKey(_cachedCollectionForSharedLink!.id),
);
final String url =
"${_cachedCollectionForSharedLink!.publicURLs?.first?.url}#$collectionKey";
await Clipboard.setData(ClipboardData(text: url));
2022-12-22 10:31:10 +00:00
showShortToast(context, "Link copied to clipboard");
}
}
2023-01-27 13:56:29 +00:00
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();
}
}
}