#146 editing orientation/tags automatically sets a metadata date

This commit is contained in:
Thibault Deckers 2021-12-28 17:18:58 +09:00
parent da7b2ee8c1
commit 445bde2494
12 changed files with 141 additions and 96 deletions

View file

@ -8,6 +8,11 @@ All notable changes to this project will be documented in this file.
- Info: option to set date from other fields - Info: option to set date from other fields
### Changed
- editing an item orientation or tags automatically sets a metadata date (from the file modified
date), if it is missing
## <a id="v1.5.9"></a>[v1.5.9] - 2021-12-22 ## <a id="v1.5.9"></a>[v1.5.9] - 2021-12-22
### Added ### Added
@ -41,7 +46,8 @@ All notable changes to this project will be documented in this file.
### Changed ### Changed
- Settings: select hidden path directory with a custom file picker instead of the native SAF one - Settings: select hidden path directory with a custom file picker instead of the native SAF one
- Viewer: video cover (before playing the video) is now loaded at original resolution and can be zoomed - Viewer: video cover (before playing the video) is now loaded at original resolution and can be
zoomed
### Fixed ### Fixed
@ -79,7 +85,8 @@ All notable changes to this project will be documented in this file.
### Changed ### Changed
- use build flavors to match distribution channels: `play` (same as original) and `izzy` (no Crashlytics) - use build flavors to match distribution channels: `play` (same as original) and `izzy` (no
Crashlytics)
- use 12/24 hour format settings from device to display times - use 12/24 hour format settings from device to display times
- Privacy: consent request on first launch for installed app inventory access - Privacy: consent request on first launch for installed app inventory access
- use File API to rename and delete items, when possible (primary storage, Android <11) - use File API to rename and delete items, when possible (primary storage, Android <11)

View file

@ -648,26 +648,28 @@ class AvesEntry {
await locate(background: background, force: dataTypes.contains(EntryDataType.address), geocoderLocale: geocoderLocale); await locate(background: background, force: dataTypes.contains(EntryDataType.address), geocoderLocale: geocoderLocale);
} }
Future<Set<EntryDataType>> rotate({required bool clockwise, required bool persist}) async { Future<Set<EntryDataType>> _changeOrientation(Future<Map<String, dynamic>> Function() apply) async {
final newFields = await metadataEditService.rotate(this, clockwise: clockwise); final dataTypes = await setMetadataDateIfMissing();
if (newFields.isEmpty) return {};
await _applyNewFields(newFields, persist: persist); final newFields = await apply();
return { // applying fields is only useful for a smoother visual change,
EntryDataType.basic, // as proper refreshing and persistence happens at the caller level
EntryDataType.catalog, await _applyNewFields(newFields, persist: false);
}; if (newFields.isNotEmpty) {
dataTypes.addAll({
EntryDataType.basic,
EntryDataType.catalog,
});
}
return dataTypes;
} }
Future<Set<EntryDataType>> flip({required bool persist}) async { Future<Set<EntryDataType>> rotate({required bool clockwise}) {
final newFields = await metadataEditService.flip(this); return _changeOrientation(() => metadataEditService.rotate(this, clockwise: clockwise));
if (newFields.isEmpty) return {}; }
await _applyNewFields(newFields, persist: persist); Future<Set<EntryDataType>> flip() {
return { return _changeOrientation(() => metadataEditService.flip(this));
EntryDataType.basic,
EntryDataType.catalog,
};
} }
Future<Set<EntryDataType>> editDate(DateModifier modifier) async { Future<Set<EntryDataType>> editDate(DateModifier modifier) async {
@ -730,6 +732,25 @@ class AvesEntry {
}; };
} }
// when editing a file that has no metadata date,
// we will set one, using the file modified date, if any
Future<Set<EntryDataType>> setMetadataDateIfMissing() async {
if (path == null) return {};
// make sure entry is catalogued before we check whether is has a metadata date
if (!isCatalogued) {
await catalog(background: false, force: false, persist: true);
}
final metadataDate = catalogMetadata?.dateMillis;
if (metadataDate != null && metadataDate > 0) return {};
return await editDate(const DateModifier(
DateEditAction.set,
{MetadataField.exifDateOriginal},
setSource: DateSetSource.fileModifiedDate,
));
}
Future<Set<EntryDataType>> removeMetadata(Set<MetadataType> types) async { Future<Set<EntryDataType>> removeMetadata(Set<MetadataType> types) async {
final newFields = await metadataEditService.removeTypes(this, types); final newFields = await metadataEditService.removeTypes(this, types);
return newFields.isEmpty return newFields.isEmpty

View file

@ -43,6 +43,8 @@ extension ExtraAvesEntryXmpIptc on AvesEntry {
static String prefixOf(String ns) => nsDefaultPrefixes[ns] ?? ''; static String prefixOf(String ns) => nsDefaultPrefixes[ns] ?? '';
Future<Set<EntryDataType>> editTags(Set<String> tags) async { Future<Set<EntryDataType>> editTags(Set<String> tags) async {
final dataTypes = await setMetadataDateIfMissing();
final xmp = await metadataFetchService.getXmp(this); final xmp = await metadataFetchService.getXmp(this);
final extendedXmpString = xmp?.extendedXmpString; final extendedXmpString = xmp?.extendedXmpString;
@ -118,7 +120,10 @@ extension ExtraAvesEntryXmpIptc on AvesEntry {
} }
final newFields = await metadataEditService.setXmp(this, editedXmp); final newFields = await metadataEditService.setXmp(this, editedXmp);
return newFields.isEmpty ? {} : {EntryDataType.catalog}; if (newFields.isNotEmpty) {
dataTypes.add(EntryDataType.catalog);
}
return dataTypes;
} }
Future<void> _setIptcKeywords(List<Map<String, dynamic>> iptc, Set<String> tags) async { Future<void> _setIptcKeywords(List<Map<String, dynamic>> iptc, Set<String> tags) async {

View file

@ -489,7 +489,7 @@ class EntrySetActionDelegate with EntryEditorMixin, FeedbackMixin, PermissionAwa
final todoItems = await _getEditableItems(context, selectedItems: selectedItems, canEdit: (entry) => entry.canRotateAndFlip); final todoItems = await _getEditableItems(context, selectedItems: selectedItems, canEdit: (entry) => entry.canRotateAndFlip);
if (todoItems == null || todoItems.isEmpty) return; if (todoItems == null || todoItems.isEmpty) return;
await _edit(context, selection, todoItems, (entry) => entry.rotate(clockwise: clockwise, persist: true)); await _edit(context, selection, todoItems, (entry) => entry.rotate(clockwise: clockwise));
} }
Future<void> _flip(BuildContext context) async { Future<void> _flip(BuildContext context) async {
@ -499,7 +499,7 @@ class EntrySetActionDelegate with EntryEditorMixin, FeedbackMixin, PermissionAwa
final todoItems = await _getEditableItems(context, selectedItems: selectedItems, canEdit: (entry) => entry.canRotateAndFlip); final todoItems = await _getEditableItems(context, selectedItems: selectedItems, canEdit: (entry) => entry.canRotateAndFlip);
if (todoItems == null || todoItems.isEmpty) return; if (todoItems == null || todoItems.isEmpty) return;
await _edit(context, selection, todoItems, (entry) => entry.flip(persist: true)); await _edit(context, selection, todoItems, (entry) => entry.flip());
} }
Future<void> _editDate(BuildContext context) async { Future<void> _editDate(BuildContext context) async {

View file

@ -24,20 +24,26 @@ import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:aves/widgets/dialogs/entry_editors/rename_entry_dialog.dart'; import 'package:aves/widgets/dialogs/entry_editors/rename_entry_dialog.dart';
import 'package:aves/widgets/dialogs/export_entry_dialog.dart'; import 'package:aves/widgets/dialogs/export_entry_dialog.dart';
import 'package:aves/widgets/filter_grids/album_pick.dart'; import 'package:aves/widgets/filter_grids/album_pick.dart';
import 'package:aves/widgets/viewer/action/printer.dart';
import 'package:aves/widgets/viewer/action/single_entry_editor.dart';
import 'package:aves/widgets/viewer/debug/debug_page.dart'; import 'package:aves/widgets/viewer/debug/debug_page.dart';
import 'package:aves/widgets/viewer/info/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'; import 'package:aves/widgets/viewer/source_viewer_page.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMixin { class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMixin, SingleEntryEditorMixin {
void onActionSelected(BuildContext context, AvesEntry entry, EntryAction action) { @override
final AvesEntry entry;
EntryActionDelegate(this.entry);
void onActionSelected(BuildContext context, EntryAction action) {
switch (action) { switch (action) {
case EntryAction.addShortcut: case EntryAction.addShortcut:
_addShortcut(context, entry); _addShortcut(context);
break; break;
case EntryAction.copyToClipboard: case EntryAction.copyToClipboard:
androidAppService.copyToClipboard(entry.uri, entry.bestTitle).then((success) { androidAppService.copyToClipboard(entry.uri, entry.bestTitle).then((success) {
@ -45,10 +51,10 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
}); });
break; break;
case EntryAction.delete: case EntryAction.delete:
_delete(context, entry); _delete(context);
break; break;
case EntryAction.export: case EntryAction.export:
_export(context, entry); _export(context);
break; break;
case EntryAction.info: case EntryAction.info:
ShowInfoNotification().dispatch(context); ShowInfoNotification().dispatch(context);
@ -57,7 +63,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
EntryPrinter(entry).print(context); EntryPrinter(entry).print(context);
break; break;
case EntryAction.rename: case EntryAction.rename:
_rename(context, entry); _rename(context);
break; break;
case EntryAction.share: case EntryAction.share:
androidAppService.shareEntries({entry}).then((success) { androidAppService.shareEntries({entry}).then((success) {
@ -69,17 +75,17 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
break; break;
// raster // raster
case EntryAction.rotateCCW: case EntryAction.rotateCCW:
_rotate(context, entry, clockwise: false); _rotate(context, clockwise: false);
break; break;
case EntryAction.rotateCW: case EntryAction.rotateCW:
_rotate(context, entry, clockwise: true); _rotate(context, clockwise: true);
break; break;
case EntryAction.flip: case EntryAction.flip:
_flip(context, entry); _flip(context);
break; break;
// vector // vector
case EntryAction.viewSource: case EntryAction.viewSource:
_goToSourceViewer(context, entry); _goToSourceViewer(context);
break; break;
// external // external
case EntryAction.edit: case EntryAction.edit:
@ -108,12 +114,12 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
break; break;
// debug // debug
case EntryAction.debug: case EntryAction.debug:
_goToDebug(context, entry); _goToDebug(context);
break; break;
} }
} }
Future<void> _addShortcut(BuildContext context, AvesEntry entry) async { Future<void> _addShortcut(BuildContext context) async {
final result = await showDialog<Tuple2<AvesEntry?, String>>( final result = await showDialog<Tuple2<AvesEntry?, String>>(
context: context, context: context,
builder: (context) => AddShortcutDialog( builder: (context) => AddShortcutDialog(
@ -131,18 +137,12 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
} }
} }
Future<void> _flip(BuildContext context, AvesEntry entry) async { Future<void> _flip(BuildContext context) async {
if (!await checkStoragePermission(context, {entry})) return; await edit(context, entry.flip);
final dataTypes = await entry.flip(persist: _isMainMode(context));
if (dataTypes.isEmpty) showFeedback(context, context.l10n.genericFailureFeedback);
} }
Future<void> _rotate(BuildContext context, AvesEntry entry, {required bool clockwise}) async { Future<void> _rotate(BuildContext context, {required bool clockwise}) async {
if (!await checkStoragePermission(context, {entry})) return; await edit(context, () => entry.rotate(clockwise: clockwise));
final dataTypes = await entry.rotate(clockwise: clockwise, persist: _isMainMode(context));
if (dataTypes.isEmpty) showFeedback(context, context.l10n.genericFailureFeedback);
} }
Future<void> _rotateScreen(BuildContext context) async { Future<void> _rotateScreen(BuildContext context) async {
@ -156,7 +156,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
} }
} }
Future<void> _delete(BuildContext context, AvesEntry entry) async { Future<void> _delete(BuildContext context) async {
final confirmed = await showDialog<bool>( final confirmed = await showDialog<bool>(
context: context, context: context,
builder: (context) { builder: (context) {
@ -190,7 +190,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
} }
} }
Future<void> _export(BuildContext context, AvesEntry entry) async { Future<void> _export(BuildContext context) async {
final source = context.read<CollectionSource>(); final source = context.read<CollectionSource>();
if (!source.initialized) { if (!source.initialized) {
await source.init(); await source.init();
@ -291,7 +291,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
); );
} }
Future<void> _rename(BuildContext context, AvesEntry entry) async { Future<void> _rename(BuildContext context) async {
final newName = await showDialog<String>( final newName = await showDialog<String>(
context: context, context: context,
builder: (context) => RenameEntryDialog(entry: entry), builder: (context) => RenameEntryDialog(entry: entry),
@ -311,7 +311,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
bool _isMainMode(BuildContext context) => context.read<ValueNotifier<AppMode>>().value == AppMode.main; bool _isMainMode(BuildContext context) => context.read<ValueNotifier<AppMode>>().value == AppMode.main;
void _goToSourceViewer(BuildContext context, AvesEntry entry) { void _goToSourceViewer(BuildContext context) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -323,7 +323,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
); );
} }
void _goToDebug(BuildContext context, AvesEntry entry) { void _goToDebug(BuildContext context) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(

View file

@ -1,22 +1,18 @@
import 'dart:async'; import 'dart:async';
import 'package:aves/app_mode.dart';
import 'package:aves/model/actions/entry_info_actions.dart'; import 'package:aves/model/actions/entry_info_actions.dart';
import 'package:aves/model/actions/events.dart'; import 'package:aves/model/actions/events.dart';
import 'package:aves/model/entry.dart'; import 'package:aves/model/entry.dart';
import 'package:aves/model/entry_xmp_iptc.dart'; import 'package:aves/model/entry_xmp_iptc.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/widgets/common/action_mixins/entry_editor.dart'; 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/feedback.dart';
import 'package:aves/widgets/common/action_mixins/permission_aware.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/action/single_entry_editor.dart';
import 'package:aves/widgets/viewer/embedded/notifications.dart'; import 'package:aves/widgets/viewer/embedded/notifications.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class EntryInfoActionDelegate with EntryEditorMixin, FeedbackMixin, PermissionAwareMixin { class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin, EntryEditorMixin, SingleEntryEditorMixin {
@override
final AvesEntry entry; final AvesEntry entry;
final StreamController<ActionEvent<EntryInfoAction>> _eventStreamController = StreamController<ActionEvent<EntryInfoAction>>.broadcast(); final StreamController<ActionEvent<EntryInfoAction>> _eventStreamController = StreamController<ActionEvent<EntryInfoAction>>.broadcast();
@ -74,43 +70,11 @@ class EntryInfoActionDelegate with EntryEditorMixin, FeedbackMixin, PermissionAw
_eventStreamController.add(ActionEndedEvent(action)); _eventStreamController.add(ActionEndedEvent(action));
} }
bool _isMainMode(BuildContext context) => context.read<ValueNotifier<AppMode>>().value == AppMode.main;
Future<void> _edit(BuildContext context, Future<Set<EntryDataType>> Function() apply) async {
if (!await checkStoragePermission(context, {entry})) return;
// check before applying, because it relies on provider
// but the widget tree may be disposed if the user navigated away
final isMainMode = _isMainMode(context);
final l10n = context.l10n;
final source = context.read<CollectionSource?>();
source?.pauseMonitoring();
final dataTypes = await apply();
final success = dataTypes.isNotEmpty;
try {
if (success) {
if (isMainMode && source != null) {
await source.refreshEntry(entry, dataTypes);
} else {
await entry.refresh(background: false, persist: false, dataTypes: dataTypes, geocoderLocale: settings.appliedLocale);
}
showFeedback(context, l10n.genericSuccessFeedback);
} else {
showFeedback(context, l10n.genericFailureFeedback);
}
} catch (e, stack) {
await reportService.recordError(e, stack);
}
source?.resumeMonitoring();
}
Future<void> _editDate(BuildContext context) async { Future<void> _editDate(BuildContext context) async {
final modifier = await selectDateModifier(context, {entry}); final modifier = await selectDateModifier(context, {entry});
if (modifier == null) return; if (modifier == null) return;
await _edit(context, () => entry.editDate(modifier)); await edit(context, () => entry.editDate(modifier));
} }
Future<void> _editTags(BuildContext context) async { Future<void> _editTags(BuildContext context) async {
@ -121,13 +85,13 @@ class EntryInfoActionDelegate with EntryEditorMixin, FeedbackMixin, PermissionAw
final currentTags = entry.tags; final currentTags = entry.tags;
if (newTags.length == currentTags.length && newTags.every(currentTags.contains)) return; if (newTags.length == currentTags.length && newTags.every(currentTags.contains)) return;
await _edit(context, () => entry.editTags(newTags)); await edit(context, () => entry.editTags(newTags));
} }
Future<void> _removeMetadata(BuildContext context) async { Future<void> _removeMetadata(BuildContext context) async {
final types = await selectMetadataToRemove(context, {entry}); final types = await selectMetadataToRemove(context, {entry});
if (types == null) return; if (types == null) return;
await _edit(context, () => entry.removeMetadata(types)); await edit(context, () => entry.removeMetadata(types));
} }
} }

View file

@ -0,0 +1,48 @@
import 'dart:async';
import 'package:aves/app_mode.dart';
import 'package:aves/model/entry.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/services/common/services.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:flutter/material.dart';
import 'package:provider/provider.dart';
mixin SingleEntryEditorMixin on FeedbackMixin, PermissionAwareMixin {
AvesEntry get entry;
bool _isMainMode(BuildContext context) => context.read<ValueNotifier<AppMode>>().value == AppMode.main;
Future<void> edit(BuildContext context, Future<Set<EntryDataType>> Function() apply) async {
if (!await checkStoragePermission(context, {entry})) return;
// check before applying, because it relies on provider
// but the widget tree may be disposed if the user navigated away
final isMainMode = _isMainMode(context);
final l10n = context.l10n;
final source = context.read<CollectionSource?>();
source?.pauseMonitoring();
final dataTypes = await apply();
final success = dataTypes.isNotEmpty;
try {
if (success) {
if (isMainMode && source != null) {
await source.refreshEntry(entry, dataTypes);
} else {
await entry.refresh(background: false, persist: false, dataTypes: dataTypes, geocoderLocale: settings.appliedLocale);
}
showFeedback(context, l10n.genericSuccessFeedback);
} else {
showFeedback(context, l10n.genericFailureFeedback);
}
} catch (e, stack) {
await reportService.recordError(e, stack);
}
source?.resumeMonitoring();
}
}

View file

@ -13,7 +13,7 @@ import 'package:aves/utils/file_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_filter_chip.dart'; import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
import 'package:aves/widgets/viewer/info/common.dart'; import 'package:aves/widgets/viewer/info/common.dart';
import 'package:aves/widgets/viewer/info/entry_info_action_delegate.dart'; import 'package:aves/widgets/viewer/action/entry_info_action_delegate.dart';
import 'package:aves/widgets/viewer/info/owner.dart'; import 'package:aves/widgets/viewer/info/owner.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View file

@ -5,7 +5,7 @@ import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/common/app_bar_title.dart'; import 'package:aves/widgets/common/app_bar_title.dart';
import 'package:aves/widgets/common/basic/menu.dart'; import 'package:aves/widgets/common/basic/menu.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/viewer/info/entry_info_action_delegate.dart'; import 'package:aves/widgets/viewer/action/entry_info_action_delegate.dart';
import 'package:aves/widgets/viewer/info/info_search.dart'; import 'package:aves/widgets/viewer/info/info_search.dart';
import 'package:aves/widgets/viewer/info/metadata/metadata_section.dart'; import 'package:aves/widgets/viewer/info/metadata/metadata_section.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View file

@ -8,9 +8,9 @@ import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/common/basic/insets.dart'; import 'package:aves/widgets/common/basic/insets.dart';
import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
import 'package:aves/widgets/viewer/action/entry_info_action_delegate.dart';
import 'package:aves/widgets/viewer/embedded/embedded_data_opener.dart'; import 'package:aves/widgets/viewer/embedded/embedded_data_opener.dart';
import 'package:aves/widgets/viewer/info/basic_section.dart'; import 'package:aves/widgets/viewer/info/basic_section.dart';
import 'package:aves/widgets/viewer/info/entry_info_action_delegate.dart';
import 'package:aves/widgets/viewer/info/info_app_bar.dart'; import 'package:aves/widgets/viewer/info/info_app_bar.dart';
import 'package:aves/widgets/viewer/info/location_section.dart'; import 'package:aves/widgets/viewer/info/location_section.dart';
import 'package:aves/widgets/viewer/info/metadata/metadata_section.dart'; import 'package:aves/widgets/viewer/info/metadata/metadata_section.dart';

View file

@ -9,7 +9,7 @@ import 'package:aves/widgets/common/basic/menu.dart';
import 'package:aves/widgets/common/basic/popup_menu_button.dart'; import 'package:aves/widgets/common/basic/popup_menu_button.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/fx/sweeper.dart'; import 'package:aves/widgets/common/fx/sweeper.dart';
import 'package:aves/widgets/viewer/entry_action_delegate.dart'; import 'package:aves/widgets/viewer/action/entry_action_delegate.dart';
import 'package:aves/widgets/viewer/multipage/conductor.dart'; import 'package:aves/widgets/viewer/multipage/conductor.dart';
import 'package:aves/widgets/viewer/overlay/common.dart'; import 'package:aves/widgets/viewer/overlay/common.dart';
import 'package:aves/widgets/viewer/overlay/minimap.dart'; import 'package:aves/widgets/viewer/overlay/minimap.dart';
@ -312,7 +312,7 @@ class _TopOverlayRow extends StatelessWidget {
} }
} }
} }
EntryActionDelegate().onActionSelected(context, targetEntry, action); EntryActionDelegate(targetEntry).onActionSelected(context, action);
} }
} }