#268 groups: serialization

This commit is contained in:
Thibault Deckers 2025-05-11 23:10:31 +02:00
parent 651b5926dc
commit 244217417b
9 changed files with 50 additions and 23 deletions

View file

@ -29,22 +29,17 @@ class FilterGrouping<T extends GroupBaseFilter> with ChangeNotifier {
final T Function(Uri uri, SetOrFilter filter) _createGroupFilter; final T Function(Uri uri, SetOrFilter filter) _createGroupFilter;
final Map<Uri, Set<Uri>> _groups = {}; final Map<Uri, Set<Uri>> _groups = {};
Map<Uri, Set<Uri>> get allGroups => Map.unmodifiable(_groups);
FilterGrouping._private(this._host, this._createGroupFilter) { FilterGrouping._private(this._host, this._createGroupFilter) {
if (kFlutterMemoryAllocationsEnabled) ChangeNotifier.maybeDispatchObjectCreation(this); if (kFlutterMemoryAllocationsEnabled) ChangeNotifier.maybeDispatchObjectCreation(this);
} }
static FilterGrouping? forUri(Uri uri) { void init(Map<Uri, Set<Uri>> groups) {
switch (uri.host) { _groups.clear();
case hostAlbums: _groups.addAll(groups);
return albumGrouping;
default:
return null;
}
} }
void clear() => _groups.clear();
// TODO TLAD [nested] invalidate summary for derived filters (parent groups, dynamic albums)
void addToGroup(Set<Uri> childrenUris, Uri? destinationGroup) { void addToGroup(Set<Uri> childrenUris, Uri? destinationGroup) {
_removeFromGroups(childrenUris); _removeFromGroups(childrenUris);
if (destinationGroup != null) { if (destinationGroup != null) {
@ -60,10 +55,10 @@ class FilterGrouping<T extends GroupBaseFilter> with ChangeNotifier {
void rename(Uri oldUri, Uri newUri) { void rename(Uri oldUri, Uri newUri) {
final childrenUris = _groups[oldUri]; final childrenUris = _groups[oldUri];
if (childrenUris != null) { if (childrenUris == null) return;
// local copy to prevent concurrent modification
addToGroup(Set.of(childrenUris), newUri); // local copy to prevent concurrent modification
} addToGroup(Set.of(childrenUris), newUri);
eventBus.fire(GroupUriChangedEvent(oldUri, newUri)); eventBus.fire(GroupUriChangedEvent(oldUri, newUri));
} }
@ -243,10 +238,19 @@ class FilterGrouping<T extends GroupBaseFilter> with ChangeNotifier {
return null; return null;
} }
static FilterGrouping? forUri(Uri uri) {
switch (uri.host) {
case hostAlbums:
return albumGrouping;
default:
return null;
}
}
// serialization // serialization
static String toJson(Map<Uri, Set<Uri>> groups) => jsonEncode(groups.map((parentUri, childrenUris) { static String toJson(Map<Uri, Set<Uri>> groups) => jsonEncode(groups.map((parentUri, childrenUris) {
return MapEntry(parentUri.toString(), childrenUris.map((v) => v.toString())); return MapEntry(parentUri.toString(), childrenUris.map((v) => v.toString()).toList());
})); }));
static Map<Uri, Set<Uri>>? fromJson(String? jsonString) { static Map<Uri, Set<Uri>>? fromJson(String? jsonString) {

View file

@ -7,9 +7,9 @@ import 'package:aves_model/aves_model.dart';
import 'package:synchronized/synchronized.dart'; import 'package:synchronized/synchronized.dart';
mixin FilterGridsSettings on SettingsAccess { mixin FilterGridsSettings on SettingsAccess {
AlbumChipSectionFactor get albumSectionFactor => getEnumOrDefault(SettingKeys.albumGroupFactorKey, SettingsDefaults.albumGroupFactor, AlbumChipSectionFactor.values); AlbumChipSectionFactor get albumSectionFactor => getEnumOrDefault(SettingKeys.albumSectionFactorKey, SettingsDefaults.albumGroupFactor, AlbumChipSectionFactor.values);
set albumSectionFactor(AlbumChipSectionFactor newValue) => set(SettingKeys.albumGroupFactorKey, newValue.toString()); set albumSectionFactor(AlbumChipSectionFactor newValue) => set(SettingKeys.albumSectionFactorKey, newValue.toString());
ChipSortFactor get albumSortFactor => getEnumOrDefault(SettingKeys.albumSortFactorKey, SettingsDefaults.chipListSortFactor, ChipSortFactor.values); ChipSortFactor get albumSortFactor => getEnumOrDefault(SettingKeys.albumSortFactorKey, SettingsDefaults.chipListSortFactor, ChipSortFactor.values);
@ -59,7 +59,11 @@ mixin FilterGridsSettings on SettingsAccess {
void setShowTitleQuery(String routeName, bool newValue) => set(SettingKeys.showTitleQueryPrefixKey + routeName, newValue); void setShowTitleQuery(String routeName, bool newValue) => set(SettingKeys.showTitleQueryPrefixKey + routeName, newValue);
// TODO TLAD [nested] save/load Map<Uri, Set<Uri>> get albumGroups => FilterGrouping.fromJson(getString(SettingKeys.albumGroupsKey)) ?? {};
set albumGroups(Map<Uri, Set<Uri>> groups) => set(SettingKeys.albumGroupsKey, FilterGrouping.toJson(groups));
// listening
final _lockForPins = Lock(); final _lockForPins = Lock();
@ -97,4 +101,6 @@ mixin FilterGridsSettings on SettingsAccess {
} }
}); });
} }
void saveAlbumGroups() => albumGroups = albumGrouping.allGroups;
} }

View file

@ -77,6 +77,8 @@ mixin NavigationSettings on SettingsAccess {
set drawerPageBookmarks(List<String> newValue) => set(SettingKeys.drawerPageBookmarksKey, newValue); set drawerPageBookmarks(List<String> newValue) => set(SettingKeys.drawerPageBookmarksKey, newValue);
// listening
final _lockForBookmarks = Lock(); final _lockForBookmarks = Lock();
Future<void> updateBookmarkedDynamicAlbums(Map<DynamicAlbumFilter, DynamicAlbumFilter?> changes) async { Future<void> updateBookmarkedDynamicAlbums(Map<DynamicAlbumFilter, DynamicAlbumFilter?> changes) async {

View file

@ -69,9 +69,20 @@ class Settings with ChangeNotifier, SettingsAccess, SearchSettings, AppSettings,
Future<void> init({required bool monitorPlatformSettings}) async { Future<void> init({required bool monitorPlatformSettings}) async {
await store.init(); await store.init();
resetAppliedLocale(); resetAppliedLocale();
_unregister();
_register(monitorPlatformSettings);
initAppSettings();
}
void _unregister() {
albumGrouping.removeListener(saveAlbumGroups);
_subscriptions _subscriptions
..forEach((sub) => sub.cancel()) ..forEach((sub) => sub.cancel())
..clear(); ..clear();
}
void _register(bool monitorPlatformSettings) {
albumGrouping.addListener(saveAlbumGroups);
_subscriptions.add(dynamicAlbums.eventBus.on<DynamicAlbumChangedEvent>().listen((e) { _subscriptions.add(dynamicAlbums.eventBus.on<DynamicAlbumChangedEvent>().listen((e) {
final changes = e.changes; final changes = e.changes;
updateBookmarkedDynamicAlbums(changes); updateBookmarkedDynamicAlbums(changes);
@ -86,7 +97,6 @@ class Settings with ChangeNotifier, SettingsAccess, SearchSettings, AppSettings,
if (monitorPlatformSettings) { if (monitorPlatformSettings) {
_subscriptions.add(_platformSettingsChangeChannel.receiveBroadcastStream().listen((event) => _onPlatformSettingsChanged(event as Map?))); _subscriptions.add(_platformSettingsChangeChannel.receiveBroadcastStream().listen((event) => _onPlatformSettingsChanged(event as Map?)));
} }
initAppSettings();
} }
Future<void> reload() => store.reload(); Future<void> reload() => store.reload();
@ -387,12 +397,13 @@ class Settings with ChangeNotifier, SettingsAccess, SearchSettings, AppSettings,
case SettingKeys.collectionSortFactorKey: case SettingKeys.collectionSortFactorKey:
case SettingKeys.thumbnailLocationIconKey: case SettingKeys.thumbnailLocationIconKey:
case SettingKeys.thumbnailTagIconKey: case SettingKeys.thumbnailTagIconKey:
case SettingKeys.albumGroupFactorKey: case SettingKeys.albumSectionFactorKey:
case SettingKeys.albumSortFactorKey: case SettingKeys.albumSortFactorKey:
case SettingKeys.countrySortFactorKey: case SettingKeys.countrySortFactorKey:
case SettingKeys.stateSortFactorKey: case SettingKeys.stateSortFactorKey:
case SettingKeys.placeSortFactorKey: case SettingKeys.placeSortFactorKey:
case SettingKeys.tagSortFactorKey: case SettingKeys.tagSortFactorKey:
case SettingKeys.albumGroupsKey:
case SettingKeys.imageBackgroundKey: case SettingKeys.imageBackgroundKey:
case SettingKeys.videoAutoPlayModeKey: case SettingKeys.videoAutoPlayModeKey:
case SettingKeys.videoBackgroundModeKey: case SettingKeys.videoBackgroundModeKey:

View file

@ -6,6 +6,7 @@ import 'package:aves/model/entry/entry.dart';
import 'package:aves/model/entry/origins.dart'; import 'package:aves/model/entry/origins.dart';
import 'package:aves/model/favourites.dart'; import 'package:aves/model/favourites.dart';
import 'package:aves/model/filters/covered/stored_album.dart'; import 'package:aves/model/filters/covered/stored_album.dart';
import 'package:aves/model/grouping/common.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/analysis_controller.dart'; import 'package:aves/model/source/analysis_controller.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
@ -59,6 +60,7 @@ class MediaStoreSource extends CollectionSource {
await localMediaDb.init(); await localMediaDb.init();
await vaults.init(); await vaults.init();
await favourites.init(); await favourites.init();
albumGrouping.init(settings.albumGroups);
await covers.init(); await covers.init();
await dynamicAlbums.init(); await dynamicAlbums.init();

View file

@ -77,6 +77,7 @@ class _DebugSettingsSectionState extends State<DebugSettingsSection> with Automa
'systemLocales': '${WidgetsBinding.instance.platformDispatcher.locales}', 'systemLocales': '${WidgetsBinding.instance.platformDispatcher.locales}',
'topEntryIds': '${settings.topEntryIds}', 'topEntryIds': '${settings.topEntryIds}',
'longPressTimeout': '${settings.longPressTimeout}', 'longPressTimeout': '${settings.longPressTimeout}',
'albumGroups': toMultiline(settings.albumGroups.entries),
}, },
), ),
), ),

View file

@ -76,7 +76,7 @@ class SettingKeys {
static const showThumbnailVideoDurationKey = 'show_thumbnail_video_duration'; static const showThumbnailVideoDurationKey = 'show_thumbnail_video_duration';
// filter grids // filter grids
static const albumGroupFactorKey = 'album_group_factor'; static const albumSectionFactorKey = 'album_section_factor';
static const albumSortFactorKey = 'album_sort_factor'; static const albumSortFactorKey = 'album_sort_factor';
static const countrySortFactorKey = 'country_sort_factor'; static const countrySortFactorKey = 'country_sort_factor';
static const stateSortFactorKey = 'state_sort_factor'; static const stateSortFactorKey = 'state_sort_factor';
@ -87,6 +87,7 @@ class SettingKeys {
static const stateSortReverseKey = 'state_sort_reverse'; static const stateSortReverseKey = 'state_sort_reverse';
static const placeSortReverseKey = 'place_sort_reverse'; static const placeSortReverseKey = 'place_sort_reverse';
static const tagSortReverseKey = 'tag_sort_reverse'; static const tagSortReverseKey = 'tag_sort_reverse';
static const albumGroupsKey = 'album_groups';
static const pinnedFiltersKey = 'pinned_filters'; static const pinnedFiltersKey = 'pinned_filters';
static const hiddenFiltersKey = 'hidden_filters'; static const hiddenFiltersKey = 'hidden_filters';
static const deactivatedHiddenFiltersKey = 'deactivated_hidden_filters'; static const deactivatedHiddenFiltersKey = 'deactivated_hidden_filters';

View file

@ -35,7 +35,7 @@ void main() {
}); });
tearDown(() async { tearDown(() async {
albumGrouping.clear(); albumGrouping.init({});
await getIt.reset(); await getIt.reset();
}); });

View file

@ -23,7 +23,7 @@ void main() {
}); });
tearDown(() async { tearDown(() async {
albumGrouping.clear(); albumGrouping.init({});
await dynamicAlbums.clear(); await dynamicAlbums.clear();
await getIt.reset(); await getIt.reset();
}); });