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: edit tags with state placeholder
|
||||
- Countries: show states for selected countries
|
||||
- Tags: delete selected tags from all media in collection
|
||||
- improved support for system font scale
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -635,6 +635,14 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
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 {
|
||||
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRemoveMetadata);
|
||||
if (entries == null || entries.isEmpty) return;
|
||||
|
|
|
@ -83,9 +83,7 @@ mixin EntryEditorMixin {
|
|||
if (entries.isEmpty) return null;
|
||||
|
||||
final filtersByEntry = Map.fromEntries(entries.map((v) {
|
||||
// use `<CollectionFilter>{...}` instead of `toSet()` to circumvent an implicit typing issue, as of Dart v2.18.2
|
||||
final filters = <CollectionFilter>{...v.tags.map(TagFilter.new)};
|
||||
return MapEntry(v, filters);
|
||||
return MapEntry(v, v.tags.map(TagFilter.new).toSet());
|
||||
}));
|
||||
await Navigator.maybeOf(context)?.push(
|
||||
MaterialPageRoute(
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/filters/tag.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/tags_page.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class TagChipSetActionDelegate extends ChipSetActionDelegate<TagFilter> {
|
||||
final Iterable<FilterGridItem<TagFilter>> _items;
|
||||
|
@ -30,4 +38,68 @@ class TagChipSetActionDelegate extends ChipSetActionDelegate<TagFilter> {
|
|||
|
||||
@override
|
||||
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