fixed collection update when editing entry metadata
This commit is contained in:
parent
f422f848f4
commit
ffdbb6e857
12 changed files with 50 additions and 33 deletions
|
@ -445,8 +445,8 @@
|
||||||
"@collectionActionCopy": {},
|
"@collectionActionCopy": {},
|
||||||
"collectionActionMove": "Move to album",
|
"collectionActionMove": "Move to album",
|
||||||
"@collectionActionMove": {},
|
"@collectionActionMove": {},
|
||||||
"collectionActionRefreshMetadata": "Refresh metadata",
|
"collectionActionRescan": "Rescan",
|
||||||
"@collectionActionRefreshMetadata": {},
|
"@collectionActionRescan": {},
|
||||||
|
|
||||||
"collectionSortTitle": "Sort",
|
"collectionSortTitle": "Sort",
|
||||||
"@collectionSortTitle": {},
|
"@collectionSortTitle": {},
|
||||||
|
|
|
@ -213,7 +213,7 @@
|
||||||
"collectionActionAddShortcut": "홈 화면에 추가",
|
"collectionActionAddShortcut": "홈 화면에 추가",
|
||||||
"collectionActionCopy": "앨범으로 복사",
|
"collectionActionCopy": "앨범으로 복사",
|
||||||
"collectionActionMove": "앨범으로 이동",
|
"collectionActionMove": "앨범으로 이동",
|
||||||
"collectionActionRefreshMetadata": "새로 분석",
|
"collectionActionRescan": "새로 분석",
|
||||||
|
|
||||||
"collectionSortTitle": "정렬",
|
"collectionSortTitle": "정렬",
|
||||||
"collectionSortDate": "날짜",
|
"collectionSortDate": "날짜",
|
||||||
|
|
|
@ -19,7 +19,7 @@ enum EntrySetAction {
|
||||||
delete,
|
delete,
|
||||||
copy,
|
copy,
|
||||||
move,
|
move,
|
||||||
refreshMetadata,
|
rescan,
|
||||||
}
|
}
|
||||||
|
|
||||||
class EntrySetActions {
|
class EntrySetActions {
|
||||||
|
@ -28,7 +28,7 @@ class EntrySetActions {
|
||||||
EntrySetAction.delete,
|
EntrySetAction.delete,
|
||||||
EntrySetAction.copy,
|
EntrySetAction.copy,
|
||||||
EntrySetAction.move,
|
EntrySetAction.move,
|
||||||
EntrySetAction.refreshMetadata,
|
EntrySetAction.rescan,
|
||||||
EntrySetAction.map,
|
EntrySetAction.map,
|
||||||
EntrySetAction.stats,
|
EntrySetAction.stats,
|
||||||
];
|
];
|
||||||
|
@ -65,8 +65,8 @@ extension ExtraEntrySetAction on EntrySetAction {
|
||||||
return context.l10n.collectionActionCopy;
|
return context.l10n.collectionActionCopy;
|
||||||
case EntrySetAction.move:
|
case EntrySetAction.move:
|
||||||
return context.l10n.collectionActionMove;
|
return context.l10n.collectionActionMove;
|
||||||
case EntrySetAction.refreshMetadata:
|
case EntrySetAction.rescan:
|
||||||
return context.l10n.collectionActionRefreshMetadata;
|
return context.l10n.collectionActionRescan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ extension ExtraEntrySetAction on EntrySetAction {
|
||||||
return AIcons.copy;
|
return AIcons.copy;
|
||||||
case EntrySetAction.move:
|
case EntrySetAction.move:
|
||||||
return AIcons.move;
|
return AIcons.move;
|
||||||
case EntrySetAction.refreshMetadata:
|
case EntrySetAction.rescan:
|
||||||
return AIcons.refresh;
|
return AIcons.refresh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -638,20 +638,14 @@ class AvesEntry {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> editDate(DateModifier modifier, {required bool persist}) async {
|
Future<bool> editDate(DateModifier modifier) async {
|
||||||
final newFields = await metadataEditService.editDate(this, modifier);
|
final newFields = await metadataEditService.editDate(this, modifier);
|
||||||
if (newFields.isEmpty) return false;
|
return newFields.isNotEmpty;
|
||||||
|
|
||||||
await refresh(persist: persist);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> removeMetadata(Set<MetadataType> types, {required bool persist}) async {
|
Future<bool> removeMetadata(Set<MetadataType> types) async {
|
||||||
final newFields = await metadataEditService.removeTypes(this, types);
|
final newFields = await metadataEditService.removeTypes(this, types);
|
||||||
if (newFields.isEmpty) return false;
|
return newFields.isNotEmpty;
|
||||||
|
|
||||||
await refresh(persist: persist);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> delete() {
|
Future<bool> delete() {
|
||||||
|
|
|
@ -171,7 +171,7 @@ class SqfliteMetadataDb implements MetadataDb {
|
||||||
Future<void> removeIds(Set<int> contentIds, {required bool metadataOnly}) async {
|
Future<void> removeIds(Set<int> contentIds, {required bool metadataOnly}) async {
|
||||||
if (contentIds.isEmpty) return;
|
if (contentIds.isEmpty) return;
|
||||||
|
|
||||||
final stopwatch = Stopwatch()..start();
|
// final stopwatch = Stopwatch()..start();
|
||||||
final db = await _database;
|
final db = await _database;
|
||||||
// using array in `whereArgs` and using it with `where contentId IN ?` is a pain, so we prefer `batch` instead
|
// using array in `whereArgs` and using it with `where contentId IN ?` is a pain, so we prefer `batch` instead
|
||||||
final batch = db.batch();
|
final batch = db.batch();
|
||||||
|
@ -188,7 +188,7 @@ class SqfliteMetadataDb implements MetadataDb {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await batch.commit(noResult: true);
|
await batch.commit(noResult: true);
|
||||||
debugPrint('$runtimeType removeIds complete in ${stopwatch.elapsed.inMilliseconds}ms for ${contentIds.length} entries');
|
// debugPrint('$runtimeType removeIds complete in ${stopwatch.elapsed.inMilliseconds}ms for ${contentIds.length} entries');
|
||||||
}
|
}
|
||||||
|
|
||||||
// entries
|
// entries
|
||||||
|
|
|
@ -122,7 +122,7 @@ class Settings extends ChangeNotifier {
|
||||||
if (includeInternalKeys) {
|
if (includeInternalKeys) {
|
||||||
await _prefs!.clear();
|
await _prefs!.clear();
|
||||||
} else {
|
} else {
|
||||||
await Future.forEach(_prefs!.getKeys().whereNot(internalKeys.contains), _prefs!.remove);
|
await Future.forEach<String>(_prefs!.getKeys().whereNot(internalKeys.contains), _prefs!.remove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ class CollectionLens with ChangeNotifier {
|
||||||
_subscriptions.add(sourceEvents.on<EntryAddedEvent>().listen((e) => onEntryAdded(e.entries)));
|
_subscriptions.add(sourceEvents.on<EntryAddedEvent>().listen((e) => onEntryAdded(e.entries)));
|
||||||
_subscriptions.add(sourceEvents.on<EntryRemovedEvent>().listen((e) => onEntryRemoved(e.entries)));
|
_subscriptions.add(sourceEvents.on<EntryRemovedEvent>().listen((e) => onEntryRemoved(e.entries)));
|
||||||
_subscriptions.add(sourceEvents.on<EntryMovedEvent>().listen((e) => _refresh()));
|
_subscriptions.add(sourceEvents.on<EntryMovedEvent>().listen((e) => _refresh()));
|
||||||
|
_subscriptions.add(sourceEvents.on<EntryRefreshedEvent>().listen((e) => _refresh()));
|
||||||
_subscriptions.add(sourceEvents.on<FilterVisibilityChangedEvent>().listen((e) => _refresh()));
|
_subscriptions.add(sourceEvents.on<FilterVisibilityChangedEvent>().listen((e) => _refresh()));
|
||||||
_subscriptions.add(sourceEvents.on<CatalogMetadataChangedEvent>().listen((e) => _refresh()));
|
_subscriptions.add(sourceEvents.on<CatalogMetadataChangedEvent>().listen((e) => _refresh()));
|
||||||
_subscriptions.add(sourceEvents.on<AddressMetadataChangedEvent>().listen((e) {
|
_subscriptions.add(sourceEvents.on<AddressMetadataChangedEvent>().listen((e) {
|
||||||
|
|
|
@ -254,7 +254,17 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
|
||||||
|
|
||||||
Future<void> refresh();
|
Future<void> refresh();
|
||||||
|
|
||||||
Future<void> refreshMetadata(Set<AvesEntry> entries);
|
Future<void> rescan(Set<AvesEntry> entries);
|
||||||
|
|
||||||
|
Future<void> refreshMetadata(Set<AvesEntry> entries) async {
|
||||||
|
await Future.forEach<AvesEntry>(entries, (entry) => entry.refresh(persist: true));
|
||||||
|
|
||||||
|
_invalidate(entries);
|
||||||
|
updateLocations();
|
||||||
|
updateTags();
|
||||||
|
|
||||||
|
eventBus.fire(EntryRefreshedEvent(entries));
|
||||||
|
}
|
||||||
|
|
||||||
// monitoring
|
// monitoring
|
||||||
|
|
||||||
|
@ -334,6 +344,12 @@ class EntryMovedEvent {
|
||||||
const EntryMovedEvent(this.entries);
|
const EntryMovedEvent(this.entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EntryRefreshedEvent {
|
||||||
|
final Set<AvesEntry> entries;
|
||||||
|
|
||||||
|
const EntryRefreshedEvent(this.entries);
|
||||||
|
}
|
||||||
|
|
||||||
class FilterVisibilityChangedEvent {
|
class FilterVisibilityChangedEvent {
|
||||||
final Set<CollectionFilter> filters;
|
final Set<CollectionFilter> filters;
|
||||||
final bool visible;
|
final bool visible;
|
||||||
|
|
|
@ -189,9 +189,9 @@ class MediaStoreSource extends CollectionSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> refreshMetadata(Set<AvesEntry> entries) {
|
Future<void> rescan(Set<AvesEntry> entries) async {
|
||||||
final contentIds = entries.map((entry) => entry.contentId).whereNotNull().toSet();
|
final contentIds = entries.map((entry) => entry.contentId).whereNotNull().toSet();
|
||||||
metadataDb.removeIds(contentIds, metadataOnly: true);
|
await metadataDb.removeIds(contentIds, metadataOnly: true);
|
||||||
return refresh();
|
return refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,7 +289,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
case EntrySetAction.delete:
|
case EntrySetAction.delete:
|
||||||
case EntrySetAction.copy:
|
case EntrySetAction.copy:
|
||||||
case EntrySetAction.move:
|
case EntrySetAction.move:
|
||||||
case EntrySetAction.refreshMetadata:
|
case EntrySetAction.rescan:
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
case EntrySetAction.stats:
|
case EntrySetAction.stats:
|
||||||
_actionDelegate.onActionSelected(context, action);
|
_actionDelegate.onActionSelected(context, action);
|
||||||
|
|
|
@ -42,8 +42,8 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
case EntrySetAction.move:
|
case EntrySetAction.move:
|
||||||
_moveSelection(context, moveType: MoveType.move);
|
_moveSelection(context, moveType: MoveType.move);
|
||||||
break;
|
break;
|
||||||
case EntrySetAction.refreshMetadata:
|
case EntrySetAction.rescan:
|
||||||
_refreshMetadata(context);
|
_rescan(context);
|
||||||
break;
|
break;
|
||||||
case EntrySetAction.map:
|
case EntrySetAction.map:
|
||||||
_goToMap(context);
|
_goToMap(context);
|
||||||
|
@ -68,12 +68,12 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _refreshMetadata(BuildContext context) {
|
void _rescan(BuildContext context) {
|
||||||
final source = context.read<CollectionSource>();
|
final source = context.read<CollectionSource>();
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
final selection = context.read<Selection<AvesEntry>>();
|
||||||
final selectedItems = _getExpandedSelectedItems(selection);
|
final selectedItems = _getExpandedSelectedItems(selection);
|
||||||
|
|
||||||
source.refreshMetadata(selectedItems);
|
source.rescan(selectedItems);
|
||||||
selection.browse();
|
selection.browse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,19 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin {
|
||||||
Future<void> _edit(BuildContext context, Future<bool> Function() apply) async {
|
Future<void> _edit(BuildContext context, Future<bool> Function() apply) async {
|
||||||
if (!await checkStoragePermission(context, {entry})) return;
|
if (!await checkStoragePermission(context, {entry})) return;
|
||||||
|
|
||||||
|
final l10n = context.l10n;
|
||||||
final source = context.read<CollectionSource?>();
|
final source = context.read<CollectionSource?>();
|
||||||
source?.pauseMonitoring();
|
source?.pauseMonitoring();
|
||||||
final success = await apply();
|
final success = await apply();
|
||||||
if (success) {
|
if (success) {
|
||||||
showFeedback(context, context.l10n.genericSuccessFeedback);
|
if (_isMainMode(context) && source != null) {
|
||||||
|
await source.refreshMetadata({entry});
|
||||||
|
} else {
|
||||||
|
await entry.refresh(persist: false);
|
||||||
|
}
|
||||||
|
showFeedback(context, l10n.genericSuccessFeedback);
|
||||||
} else {
|
} else {
|
||||||
showFeedback(context, context.l10n.genericFailureFeedback);
|
showFeedback(context, l10n.genericFailureFeedback);
|
||||||
}
|
}
|
||||||
source?.resumeMonitoring();
|
source?.resumeMonitoring();
|
||||||
}
|
}
|
||||||
|
@ -52,7 +58,7 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin {
|
||||||
);
|
);
|
||||||
if (modifier == null) return;
|
if (modifier == null) return;
|
||||||
|
|
||||||
await _edit(context, () => entry.editDate(modifier, persist: _isMainMode(context)));
|
await _edit(context, () => entry.editDate(modifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showMetadataRemovalDialog(BuildContext context) async {
|
Future<void> _showMetadataRemovalDialog(BuildContext context) async {
|
||||||
|
@ -85,6 +91,6 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin {
|
||||||
if (proceed == null || !proceed) return;
|
if (proceed == null || !proceed) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _edit(context, () => entry.removeMetadata(types, persist: _isMainMode(context)));
|
await _edit(context, () => entry.removeMetadata(types));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue