From fedf58574527b907f9e504ee6acadfde9c0287c0 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Fri, 12 Nov 2021 09:56:35 +0900 Subject: [PATCH] moved motion photo video opening action from viewer to info page --- lib/model/actions/entry_actions.dart | 9 ---- lib/model/actions/entry_info_actions.dart | 47 +++++++++++++++++++ lib/widgets/viewer/entry_action_delegate.dart | 5 -- .../info/entry_info_action_delegate.dart | 31 ++++++++++++ lib/widgets/viewer/info/info_app_bar.dart | 28 +++++------ lib/widgets/viewer/overlay/top.dart | 11 ++--- 6 files changed, 95 insertions(+), 36 deletions(-) diff --git a/lib/model/actions/entry_actions.dart b/lib/model/actions/entry_actions.dart index ed722f7e8..4a8c98248 100644 --- a/lib/model/actions/entry_actions.dart +++ b/lib/model/actions/entry_actions.dart @@ -19,8 +19,6 @@ enum EntryAction { flip, // vector viewSource, - // motion photo, - viewMotionPhotoVideo, // external edit, open, @@ -44,7 +42,6 @@ class EntryActions { EntryAction.copyToClipboard, EntryAction.print, EntryAction.viewSource, - EntryAction.viewMotionPhotoVideo, EntryAction.rotateScreen, ]; @@ -94,9 +91,6 @@ extension ExtraEntryAction on EntryAction { // vector case EntryAction.viewSource: return context.l10n.entryActionViewSource; - // motion photo - case EntryAction.viewMotionPhotoVideo: - return context.l10n.entryActionViewMotionPhotoVideo; // external case EntryAction.edit: return context.l10n.entryActionEdit; @@ -162,9 +156,6 @@ extension ExtraEntryAction on EntryAction { // vector case EntryAction.viewSource: return AIcons.vector; - // motion photo - case EntryAction.viewMotionPhotoVideo: - return AIcons.motionPhoto; // external case EntryAction.edit: case EntryAction.open: diff --git a/lib/model/actions/entry_info_actions.dart b/lib/model/actions/entry_info_actions.dart index 52ddd4394..f0c6c7805 100644 --- a/lib/model/actions/entry_info_actions.dart +++ b/lib/model/actions/entry_info_actions.dart @@ -1,4 +1,51 @@ +import 'package:aves/theme/icons.dart'; +import 'package:aves/widgets/common/extensions/build_context.dart'; +import 'package:flutter/widgets.dart'; + enum EntryInfoAction { + // general editDate, removeMetadata, + // motion photo + viewMotionPhotoVideo, +} + +class EntryInfoActions { + static const all = [ + EntryInfoAction.editDate, + EntryInfoAction.removeMetadata, + EntryInfoAction.viewMotionPhotoVideo, + ]; +} + +extension ExtraEntryInfoAction on EntryInfoAction { + String getText(BuildContext context) { + switch (this) { + // general + case EntryInfoAction.editDate: + return context.l10n.entryInfoActionEditDate; + case EntryInfoAction.removeMetadata: + return context.l10n.entryInfoActionRemoveMetadata; + // motion photo + case EntryInfoAction.viewMotionPhotoVideo: + return context.l10n.entryActionViewMotionPhotoVideo; + } + } + + Widget getIcon() { + return Icon(_getIconData()); + } + + IconData _getIconData() { + switch (this) { + // general + case EntryInfoAction.editDate: + return AIcons.date; + case EntryInfoAction.removeMetadata: + return AIcons.clear; + // motion photo + case EntryInfoAction.viewMotionPhotoVideo: + return AIcons.motionPhoto; + } + } } diff --git a/lib/widgets/viewer/entry_action_delegate.dart b/lib/widgets/viewer/entry_action_delegate.dart index 1f957b809..4ff192481 100644 --- a/lib/widgets/viewer/entry_action_delegate.dart +++ b/lib/widgets/viewer/entry_action_delegate.dart @@ -24,7 +24,6 @@ import 'package:aves/widgets/dialogs/export_entry_dialog.dart'; import 'package:aves/widgets/dialogs/rename_entry_dialog.dart'; import 'package:aves/widgets/filter_grids/album_pick.dart'; import 'package:aves/widgets/viewer/debug/debug_page.dart'; -import 'package:aves/widgets/viewer/embedded/notifications.dart'; import 'package:aves/widgets/viewer/info/notifications.dart'; import 'package:aves/widgets/viewer/printer.dart'; import 'package:aves/widgets/viewer/source_viewer_page.dart'; @@ -81,10 +80,6 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix case EntryAction.viewSource: _goToSourceViewer(context, entry); break; - // motion photo - case EntryAction.viewMotionPhotoVideo: - OpenEmbeddedDataNotification.motionPhotoVideo().dispatch(context); - break; // external case EntryAction.edit: androidAppService.edit(entry.uri, entry.mimeType).then((success) { diff --git a/lib/widgets/viewer/info/entry_info_action_delegate.dart b/lib/widgets/viewer/info/entry_info_action_delegate.dart index f5f9d0d13..da527c6d5 100644 --- a/lib/widgets/viewer/info/entry_info_action_delegate.dart +++ b/lib/widgets/viewer/info/entry_info_action_delegate.dart @@ -7,6 +7,7 @@ import 'package:aves/widgets/common/action_mixins/entry_editor.dart'; import 'package:aves/widgets/common/action_mixins/feedback.dart'; import 'package:aves/widgets/common/action_mixins/permission_aware.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; +import 'package:aves/widgets/viewer/embedded/notifications.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -15,14 +16,44 @@ class EntryInfoActionDelegate with EntryEditorMixin, FeedbackMixin, PermissionAw const EntryInfoActionDelegate(this.entry); + bool isVisible(EntryInfoAction action) { + switch (action) { + // general + case EntryInfoAction.editDate: + case EntryInfoAction.removeMetadata: + return true; + // motion photo + case EntryInfoAction.viewMotionPhotoVideo: + return entry.isMotionPhoto; + } + } + + bool canApply(EntryInfoAction action) { + switch (action) { + // general + case EntryInfoAction.editDate: + return entry.canEditExif; + case EntryInfoAction.removeMetadata: + return entry.canRemoveMetadata; + // motion photo + case EntryInfoAction.viewMotionPhotoVideo: + return true; + } + } + void onActionSelected(BuildContext context, EntryInfoAction action) async { switch (action) { + // general case EntryInfoAction.editDate: await _editDate(context); break; case EntryInfoAction.removeMetadata: await _removeMetadata(context); break; + // motion photo + case EntryInfoAction.viewMotionPhotoVideo: + OpenEmbeddedDataNotification.motionPhotoVideo().dispatch(context); + break; } } diff --git a/lib/widgets/viewer/info/info_app_bar.dart b/lib/widgets/viewer/info/info_app_bar.dart index e948e4904..94b78e925 100644 --- a/lib/widgets/viewer/info/info_app_bar.dart +++ b/lib/widgets/viewer/info/info_app_bar.dart @@ -25,6 +25,9 @@ class InfoAppBar extends StatelessWidget { @override Widget build(BuildContext context) { + final actionDelegate = EntryInfoActionDelegate(entry); + final menuActions = EntryInfoActions.all.where(actionDelegate.isVisible); + return SliverAppBar( leading: IconButton( // key is expected by test driver @@ -46,24 +49,11 @@ class InfoAppBar extends StatelessWidget { if (entry.canEdit) MenuIconTheme( child: PopupMenuButton( - itemBuilder: (context) { - return [ - PopupMenuItem( - value: EntryInfoAction.editDate, - enabled: entry.canEditExif, - child: MenuRow(text: context.l10n.entryInfoActionEditDate, icon: const Icon(AIcons.date)), - ), - PopupMenuItem( - value: EntryInfoAction.removeMetadata, - enabled: entry.canRemoveMetadata, - child: MenuRow(text: context.l10n.entryInfoActionRemoveMetadata, icon: const Icon(AIcons.clear)), - ), - ]; - }, + itemBuilder: (context) => menuActions.map((action) => _toMenuItem(context, action, enabled: actionDelegate.canApply(action))).toList(), onSelected: (action) async { // wait for the popup menu to hide before proceeding with the action await Future.delayed(Durations.popupMenuAnimation * timeDilation); - EntryInfoActionDelegate(entry).onActionSelected(context, action); + actionDelegate.onActionSelected(context, action); }, ), ), @@ -73,6 +63,14 @@ class InfoAppBar extends StatelessWidget { ); } + PopupMenuItem _toMenuItem(BuildContext context, EntryInfoAction action, {required bool enabled}) { + return PopupMenuItem( + value: action, + enabled: enabled, + child: MenuRow(text: action.getText(context), icon: action.getIcon()), + ); + } + void _goToSearch(BuildContext context) { showSearch( context: context, diff --git a/lib/widgets/viewer/overlay/top.dart b/lib/widgets/viewer/overlay/top.dart index ec701649c..427ed1a7b 100644 --- a/lib/widgets/viewer/overlay/top.dart +++ b/lib/widgets/viewer/overlay/top.dart @@ -65,7 +65,7 @@ class ViewerTopOverlay extends StatelessWidget { Widget _buildOverlay(BuildContext context, int availableCount, AvesEntry mainEntry, {AvesEntry? pageEntry}) { pageEntry ??= mainEntry; - bool _canDo(EntryAction action) { + bool _isVisible(EntryAction action) { final targetEntry = EntryActions.pageActions.contains(action) ? pageEntry! : mainEntry; switch (action) { case EntryAction.toggleFavourite: @@ -84,8 +84,6 @@ class ViewerTopOverlay extends StatelessWidget { return targetEntry.hasGps; case EntryAction.viewSource: return targetEntry.isSvg; - case EntryAction.viewMotionPhotoVideo: - return targetEntry.isMotionPhoto; case EntryAction.rotateScreen: return settings.isRotationLocked; case EntryAction.addShortcut: @@ -104,9 +102,9 @@ class ViewerTopOverlay extends StatelessWidget { final buttonRow = Selector( selector: (context, s) => s.isRotationLocked, builder: (context, s, child) { - final quickActions = settings.viewerQuickActions.where(_canDo).take(availableCount - 1).toList(); - final inAppActions = EntryActions.inApp.where((action) => !quickActions.contains(action)).where(_canDo).toList(); - final externalAppActions = EntryActions.externalApp.where(_canDo).toList(); + final quickActions = settings.viewerQuickActions.where(_isVisible).take(availableCount - 1).toList(); + final inAppActions = EntryActions.inApp.where((action) => !quickActions.contains(action)).where(_isVisible).toList(); + final externalAppActions = EntryActions.externalApp.where(_isVisible).toList(); return _TopOverlayRow( quickActions: quickActions, inAppActions: inAppActions, @@ -222,7 +220,6 @@ class _TopOverlayRow extends StatelessWidget { case EntryAction.share: case EntryAction.rotateScreen: case EntryAction.viewSource: - case EntryAction.viewMotionPhotoVideo: child = IconButton( icon: action.getIcon() ?? const SizedBox(), onPressed: onPressed,