#1323 preserve favourite status when converting items

This commit is contained in:
Thibault Deckers 2025-02-03 19:12:46 +01:00
parent 0a3a792a7e
commit 598b705b36
4 changed files with 44 additions and 26 deletions

View file

@ -10,9 +10,10 @@ All notable changes to this project will be documented in this file.
### Changed
- improved subsampling and filter quality strategy
- ignore moving an item to its current directory
- keep selection when action on several items is interrupted before processing
- Viewer: improved subsampling and filter quality strategy
- Collection: ignore moving an item to its current directory
- Collection: keep selection when action on several items is interrupted before processing
- Collection: preserve favourite status when converting items
- upgraded Flutter to stable v3.27.3
### Fixed

View file

@ -341,9 +341,9 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
itemCount: todoCount,
onCancel: () => mediaEditService.cancelFileOp(opId),
onDone: (processed) async {
final successOps = processed.where((e) => e.success).toSet();
final deletedOps = successOps.where((e) => !e.skipped).toSet();
final deletedUris = deletedOps.map((event) => event.uri).toSet();
final successOps = processed.where((op) => op.success).toSet();
final deletedOps = successOps.where((op) => !op.skipped).toSet();
final deletedUris = deletedOps.map((op) => op.uri).toSet();
await source.removeEntries(deletedUris, includeTrash: true);
source.resumeMonitoring();
@ -460,11 +460,11 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
itemCount: todoCount,
onCancel: () => cancelled = true,
onDone: (processed) async {
final successOps = processed.where((e) => e.success).toSet();
final editedOps = successOps.where((e) => !e.skipped).toSet();
final successOps = processed.where((op) => op.success).toSet();
final editedOps = successOps.where((op) => !op.skipped).toSet();
source.resumeMonitoring();
unawaited(source.refreshUris(editedOps.map((v) => v.uri).toSet()).then((_) {
unawaited(source.refreshUris(editedOps.map((op) => op.uri).toSet()).then((_) {
// invalidate filters derived from values before edition
// this invalidation must happen after the source is refreshed,
// otherwise filter chips may eagerly rebuild in between with the old state

View file

@ -3,8 +3,10 @@ import 'dart:io';
import 'package:aves/app_mode.dart';
import 'package:aves/model/entry/entry.dart';
import 'package:aves/model/entry/extensions/favourites.dart';
import 'package:aves/model/entry/extensions/multipage.dart';
import 'package:aves/model/entry/extensions/props.dart';
import 'package:aves/model/favourites.dart';
import 'package:aves/model/filters/covered/stored_album.dart';
import 'package:aves/model/filters/trash.dart';
import 'package:aves/model/highlight.dart';
@ -107,13 +109,28 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
),
itemCount: selectionCount,
onDone: (processed) async {
final successOps = processed.where((e) => e.success).toSet();
final exportedOps = successOps.where((e) => !e.skipped).toSet();
final newUris = exportedOps.map((v) => v.newFields['uri'] as String?).nonNulls.toSet();
final successOps = processed.where((op) => op.success).toSet();
final exportedOps = successOps.where((op) => !op.skipped && op.newFields['uri'] != null).toSet();
final newUris = exportedOps.map((op) => op.newFields['uri'] as String).toSet();
final isMainMode = context.read<ValueNotifier<AppMode>>().value == AppMode.main;
// check source favourite status
final favouriteSourceUris = selection.where((entry) => entry.isFavourite).map((entry) => entry.uri).toSet();
final favouriteNewUris = <String>{};
exportedOps.forEach((op) {
final sourceUri = op.uri;
if (favouriteSourceUris.contains(sourceUri)) {
final newUri = op.newFields['uri'] as String;
favouriteNewUris.add(newUri);
}
});
source.resumeMonitoring();
unawaited(source.refreshUris(newUris));
unawaited(source.refreshUris(newUris).then((_) {
// transfer favourite status on exports
final newFavouriteEntries = source.allEntries.where((entry) => favouriteNewUris.contains(entry.uri)).toSet();
favourites.add(newFavouriteEntries);
}));
// get navigator beforehand because
// local context may be deactivated when action is triggered after navigation
@ -241,11 +258,11 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
itemCount: todoCount,
onCancel: () => mediaEditService.cancelFileOp(opId),
onDone: (processed) async {
final successOps = processed.where((v) => v.success).toSet();
final successOps = processed.where((op) => op.success).toSet();
// move
final movedOps = successOps.where((v) => !v.skipped && !v.deleted).toSet();
final movedEntries = movedOps.map((v) => v.uri).map((uri) => entries.firstWhereOrNull((entry) => entry.uri == uri)).nonNulls.toSet();
final movedOps = successOps.where((op) => !op.skipped && !op.deleted).toSet();
final movedEntries = movedOps.map((op) => op.uri).map((uri) => entries.firstWhereOrNull((entry) => entry.uri == uri)).nonNulls.toSet();
await source.updateAfterMove(
todoEntries: entries,
moveType: moveType,
@ -254,8 +271,8 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
);
// delete (when trying to move to bin obsolete entries)
final deletedOps = successOps.where((v) => v.deleted).toSet();
final deletedUris = deletedOps.map((event) => event.uri).toSet();
final deletedOps = successOps.where((op) => op.deleted).toSet();
final deletedUris = deletedOps.map((op) => op.uri).toSet();
await source.removeEntries(deletedUris, includeTrash: true);
source.resumeMonitoring();
@ -405,8 +422,8 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
itemCount: todoCount,
onCancel: () => mediaEditService.cancelFileOp(opId),
onDone: (processed) async {
final successOps = processed.where((e) => e.success).toSet();
final movedOps = successOps.where((e) => !e.skipped).toSet();
final successOps = processed.where((op) => op.success).toSet();
final movedOps = successOps.where((op) => !op.skipped).toSet();
await source.updateAfterRename(
todoEntries: entries,
movedOps: movedOps,
@ -466,7 +483,7 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
Set<String> destinationAlbums,
Set<MoveOpEvent> movedOps,
) async {
final newUris = movedOps.map((v) => v.newFields['uri'] as String?).toSet();
final newUris = movedOps.map((op) => op.newFields['uri'] as String?).toSet();
bool highlightTest(AvesEntry entry) => newUris.contains(entry.uri);
final collection = context.read<CollectionLens?>();

View file

@ -382,9 +382,9 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumBaseFilter>
itemCount: todoCount,
onCancel: () => mediaEditService.cancelFileOp(opId),
onDone: (processed) async {
final successOps = processed.where((event) => event.success);
final deletedOps = successOps.where((e) => !e.skipped).toSet();
final deletedUris = deletedOps.map((event) => event.uri).toSet();
final successOps = processed.where((op) => op.success);
final deletedOps = successOps.where((op) => !op.skipped).toSet();
final deletedUris = deletedOps.map((op) => op.uri).toSet();
await source.removeEntries(deletedUris, includeTrash: true);
browse(context);
source.resumeMonitoring();
@ -547,8 +547,8 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumBaseFilter>
itemCount: todoCount,
onCancel: () => mediaEditService.cancelFileOp(opId),
onDone: (processed) async {
final successOps = processed.where((e) => e.success).toSet();
final movedOps = successOps.where((e) => !e.skipped).toSet();
final successOps = processed.where((op) => op.success).toSet();
final movedOps = successOps.where((op) => !op.skipped).toSet();
await source.renameStoredAlbum(album, destinationAlbum, todoEntries, movedOps);
browse(context);
source.resumeMonitoring();