delete selected tags from all media in collection
This commit is contained in:
parent
4866319a3b
commit
45a81e6522
4 changed files with 82 additions and 3 deletions
|
@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
|
||||||
- Info: improved state/place display (requires rescan, limited to AU/GB/IN/US)
|
- Info: improved state/place display (requires rescan, limited to AU/GB/IN/US)
|
||||||
- Info: edit tags with state placeholder
|
- Info: edit tags with state placeholder
|
||||||
- Countries: show states for selected countries
|
- Countries: show states for selected countries
|
||||||
|
- Tags: delete selected tags from all media in collection
|
||||||
- improved support for system font scale
|
- improved support for system font scale
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -635,6 +635,14 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
await _edit(context, entries, (entry) => entry.editTags(newTagsByEntry[entry]!));
|
await _edit(context, entries, (entry) => entry.editTags(newTagsByEntry[entry]!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> removeTags(BuildContext context, {required Set<AvesEntry> entries, required Set<String> tags}) async {
|
||||||
|
final newTagsByEntry = Map.fromEntries(entries.map((v) {
|
||||||
|
return MapEntry(v, v.tags.whereNot(tags.contains).toSet());
|
||||||
|
}));
|
||||||
|
|
||||||
|
await _edit(context, entries, (entry) => entry.editTags(newTagsByEntry[entry]!));
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _removeMetadata(BuildContext context) async {
|
Future<void> _removeMetadata(BuildContext context) async {
|
||||||
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRemoveMetadata);
|
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRemoveMetadata);
|
||||||
if (entries == null || entries.isEmpty) return;
|
if (entries == null || entries.isEmpty) return;
|
||||||
|
|
|
@ -83,9 +83,7 @@ mixin EntryEditorMixin {
|
||||||
if (entries.isEmpty) return null;
|
if (entries.isEmpty) return null;
|
||||||
|
|
||||||
final filtersByEntry = Map.fromEntries(entries.map((v) {
|
final filtersByEntry = Map.fromEntries(entries.map((v) {
|
||||||
// use `<CollectionFilter>{...}` instead of `toSet()` to circumvent an implicit typing issue, as of Dart v2.18.2
|
return MapEntry(v, v.tags.map(TagFilter.new).toSet());
|
||||||
final filters = <CollectionFilter>{...v.tags.map(TagFilter.new)};
|
|
||||||
return MapEntry(v, filters);
|
|
||||||
}));
|
}));
|
||||||
await Navigator.maybeOf(context)?.push(
|
await Navigator.maybeOf(context)?.push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
|
import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/filters/tag.dart';
|
import 'package:aves/model/filters/tag.dart';
|
||||||
import 'package:aves/model/settings/settings.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/collection/entry_set_action_delegate.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||||
import 'package:aves/widgets/filter_grids/common/action_delegates/chip_set.dart';
|
import 'package:aves/widgets/filter_grids/common/action_delegates/chip_set.dart';
|
||||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class TagChipSetActionDelegate extends ChipSetActionDelegate<TagFilter> {
|
class TagChipSetActionDelegate extends ChipSetActionDelegate<TagFilter> {
|
||||||
final Iterable<FilterGridItem<TagFilter>> _items;
|
final Iterable<FilterGridItem<TagFilter>> _items;
|
||||||
|
@ -30,4 +38,68 @@ class TagChipSetActionDelegate extends ChipSetActionDelegate<TagFilter> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
set tileLayout(TileLayout tileLayout) => settings.setTileLayout(TagListPage.routeName, tileLayout);
|
set tileLayout(TileLayout tileLayout) => settings.setTileLayout(TagListPage.routeName, tileLayout);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isVisible(
|
||||||
|
ChipSetAction action, {
|
||||||
|
required AppMode appMode,
|
||||||
|
required bool isSelecting,
|
||||||
|
required int itemCount,
|
||||||
|
required Set<TagFilter> selectedFilters,
|
||||||
|
}) {
|
||||||
|
final isMain = appMode == AppMode.main;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case ChipSetAction.delete:
|
||||||
|
return isMain && isSelecting && !settings.isReadOnly;
|
||||||
|
default:
|
||||||
|
return super.isVisible(
|
||||||
|
action,
|
||||||
|
appMode: appMode,
|
||||||
|
isSelecting: isSelecting,
|
||||||
|
itemCount: itemCount,
|
||||||
|
selectedFilters: selectedFilters,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onActionSelected(BuildContext context, Set<TagFilter> filters, ChipSetAction action) {
|
||||||
|
reportService.log('$action');
|
||||||
|
switch (action) {
|
||||||
|
// single/multiple filters
|
||||||
|
case ChipSetAction.delete:
|
||||||
|
_delete(context, filters);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
super.onActionSelected(context, filters, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _delete(BuildContext context, Set<TagFilter> filters) async {
|
||||||
|
final source = context.read<CollectionSource>();
|
||||||
|
final todoEntries = source.visibleEntries.where((entry) => filters.any((f) => f.test(entry))).toSet();
|
||||||
|
final todoTags = filters.map((v) => v.tag).toSet();
|
||||||
|
|
||||||
|
final confirmed = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AvesDialog(
|
||||||
|
content: Text(context.l10n.genericDangerWarningDialogMessage),
|
||||||
|
actions: [
|
||||||
|
const CancelButton(),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.maybeOf(context)?.pop(true),
|
||||||
|
child: Text(context.l10n.applyButtonLabel),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
|
||||||
|
);
|
||||||
|
if (confirmed == null || !confirmed) return;
|
||||||
|
|
||||||
|
await EntrySetActionDelegate().removeTags(context, entries: todoEntries, tags: todoTags);
|
||||||
|
|
||||||
|
browse(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue