fixed source update on hidden filter import

This commit is contained in:
Thibault Deckers 2022-02-21 14:22:41 +09:00
parent d110695d53
commit 6b4d9c0bc3
11 changed files with 86 additions and 72 deletions

View file

@ -20,9 +20,9 @@ final Settings settings = Settings._private();
class Settings extends ChangeNotifier {
final EventChannel _platformSettingsChangeChannel = const EventChannel('deckers.thibault/aves/settings_change');
final StreamController<String> _updateStreamController = StreamController<String>.broadcast();
final StreamController<SettingsChangedEvent> _updateStreamController = StreamController<SettingsChangedEvent>.broadcast();
Stream<String> get updateStream => _updateStreamController.stream;
Stream<SettingsChangedEvent> get updateStream => _updateStreamController.stream;
Settings._private();
@ -356,6 +356,17 @@ class Settings extends ChangeNotifier {
set hiddenFilters(Set<CollectionFilter> newValue) => setAndNotify(hiddenFiltersKey, newValue.map((filter) => filter.toJson()).toList());
void changeFilterVisibility(Set<CollectionFilter> filters, bool visible) {
final _hiddenFilters = hiddenFilters;
if (visible) {
_hiddenFilters.removeAll(filters);
} else {
_hiddenFilters.addAll(filters);
searchHistory = searchHistory..removeWhere(filters.contains);
}
hiddenFilters = _hiddenFilters;
}
// viewer
List<EntryAction> get viewerQuickActions => getEnumListOrDefault(viewerQuickActionsKey, SettingsDefaults.viewerQuickActions, EntryAction.values);
@ -540,7 +551,7 @@ class Settings extends ChangeNotifier {
settingsStore.setBool(key, newValue);
}
if (oldValue != newValue) {
_updateStreamController.add(key);
_updateStreamController.add(SettingsChangedEvent(key, oldValue, newValue));
notifyListeners();
}
}
@ -583,37 +594,39 @@ class Settings extends ChangeNotifier {
await reset(includeInternalKeys: false);
// apply user modifications
jsonMap.forEach((key, value) {
if (value == null) {
jsonMap.forEach((key, newValue) {
final oldValue = settingsStore.get(key);
if (newValue == null) {
settingsStore.remove(key);
} else if (key.startsWith(tileExtentPrefixKey)) {
if (value is double) {
settingsStore.setDouble(key, value);
if (newValue is double) {
settingsStore.setDouble(key, newValue);
} else {
debugPrint('failed to import key=$key, value=$value is not a double');
debugPrint('failed to import key=$key, value=$newValue is not a double');
}
} else if (key.startsWith(tileLayoutPrefixKey)) {
if (value is String) {
settingsStore.setString(key, value);
if (newValue is String) {
settingsStore.setString(key, newValue);
} else {
debugPrint('failed to import key=$key, value=$value is not a string');
debugPrint('failed to import key=$key, value=$newValue is not a string');
}
} else {
switch (key) {
case subtitleTextColorKey:
case subtitleBackgroundColorKey:
if (value is int) {
settingsStore.setInt(key, value);
if (newValue is int) {
settingsStore.setInt(key, newValue);
} else {
debugPrint('failed to import key=$key, value=$value is not an int');
debugPrint('failed to import key=$key, value=$newValue is not an int');
}
break;
case subtitleFontSizeKey:
case infoMapZoomKey:
if (value is double) {
settingsStore.setDouble(key, value);
if (newValue is double) {
settingsStore.setDouble(key, newValue);
} else {
debugPrint('failed to import key=$key, value=$value is not a double');
debugPrint('failed to import key=$key, value=$newValue is not a double');
}
break;
case isInstalledAppAccessAllowedKey:
@ -638,10 +651,10 @@ class Settings extends ChangeNotifier {
case subtitleShowOutlineKey:
case saveSearchHistoryKey:
case filePickerShowHiddenFilesKey:
if (value is bool) {
settingsStore.setBool(key, value);
if (newValue is bool) {
settingsStore.setBool(key, newValue);
} else {
debugPrint('failed to import key=$key, value=$value is not a bool');
debugPrint('failed to import key=$key, value=$newValue is not a bool');
}
break;
case localeKey:
@ -661,10 +674,10 @@ class Settings extends ChangeNotifier {
case unitSystemKey:
case accessibilityAnimationsKey:
case timeToTakeActionKey:
if (value is String) {
settingsStore.setString(key, value);
if (newValue is String) {
settingsStore.setString(key, newValue);
} else {
debugPrint('failed to import key=$key, value=$value is not a string');
debugPrint('failed to import key=$key, value=$newValue is not a string');
}
break;
case confirmationDialogsKey:
@ -677,17 +690,29 @@ class Settings extends ChangeNotifier {
case collectionSelectionQuickActionsKey:
case viewerQuickActionsKey:
case videoQuickActionsKey:
if (value is List) {
settingsStore.setStringList(key, value.cast<String>());
if (newValue is List) {
settingsStore.setStringList(key, newValue.cast<String>());
} else {
debugPrint('failed to import key=$key, value=$value is not a list');
debugPrint('failed to import key=$key, value=$newValue is not a list');
}
break;
}
}
_updateStreamController.add(key);
if (oldValue != newValue) {
_updateStreamController.add(SettingsChangedEvent(key, oldValue, newValue));
}
});
notifyListeners();
}
}
}
@immutable
class SettingsChangedEvent {
final String key;
final dynamic oldValue;
final dynamic newValue;
// old and new values as stored, e.g. `List<String>` for collections
const SettingsChangedEvent(this.key, this.oldValue, this.newValue);
}

View file

@ -79,10 +79,10 @@ class CollectionLens with ChangeNotifier {
favourites.addListener(_onFavouritesChanged);
}
_subscriptions.add(settings.updateStream
.where([
Settings.collectionSortFactorKey,
Settings.collectionGroupFactorKey,
].contains)
.where((event) => [
Settings.collectionSortFactorKey,
Settings.collectionGroupFactorKey,
].contains(event.key))
.listen((_) => _onSettingsChanged()));
_refresh();
}

View file

@ -45,7 +45,14 @@ mixin SourceBase {
abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagMixin, TrashMixin {
CollectionSource() {
settings.updateStream.where((key) => key == Settings.localeKey).listen((_) => invalidateAlbumDisplayNames());
settings.updateStream.where((event) => event.key == Settings.localeKey).listen((_) => invalidateAlbumDisplayNames());
settings.updateStream.where((event) => event.key == Settings.hiddenFiltersKey).listen((event) {
final oldValue = event.oldValue;
if (oldValue is List<String>?) {
final oldHiddenFilters = (oldValue ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet();
_onFilterVisibilityChanged(oldHiddenFilters, settings.hiddenFilters);
}
});
}
final EventBus _eventBus = EventBus();
@ -441,20 +448,13 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
return recentEntry(filter);
}
void changeFilterVisibility(Set<CollectionFilter> filters, bool visible) {
final hiddenFilters = settings.hiddenFilters;
if (visible) {
hiddenFilters.removeAll(filters);
} else {
hiddenFilters.addAll(filters);
settings.searchHistory = settings.searchHistory..removeWhere(filters.contains);
}
settings.hiddenFilters = hiddenFilters;
void _onFilterVisibilityChanged(Set<CollectionFilter> oldHiddenFilters, Set<CollectionFilter> currentHiddenFilters) {
updateDerivedFilters();
eventBus.fire(FilterVisibilityChangedEvent(filters, visible));
eventBus.fire(const FilterVisibilityChangedEvent());
if (visible) {
final candidateEntries = visibleEntries.where((entry) => filters.any((f) => f.test(entry))).toSet();
final newlyVisibleFilters = oldHiddenFilters.whereNot(currentHiddenFilters.contains).toSet();
if (newlyVisibleFilters.isNotEmpty) {
final candidateEntries = visibleEntries.where((entry) => newlyVisibleFilters.any((f) => f.test(entry))).toSet();
analyze(null, entries: candidateEntries);
}
}

View file

@ -1,6 +1,5 @@
import 'package:aves/model/actions/move_type.dart';
import 'package:aves/model/entry.dart';
import 'package:aves/model/filters/filters.dart';
import 'package:flutter/foundation.dart';
@immutable
@ -34,10 +33,7 @@ class EntryRefreshedEvent {
@immutable
class FilterVisibilityChangedEvent {
final Set<CollectionFilter> filters;
final bool visible;
const FilterVisibilityChangedEvent(this.filters, this.visible);
const FilterVisibilityChangedEvent();
}
@immutable

View file

@ -229,9 +229,9 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
}
}
settings.updateStream.where((key) => key == Settings.isInstalledAppAccessAllowedKey).listen((_) => applyIsInstalledAppAccessAllowed());
settings.updateStream.where((key) => key == Settings.keepScreenOnKey).listen((_) => applyKeepScreenOn());
settings.updateStream.where((key) => key == Settings.platformAccelerometerRotationKey).listen((_) => applyIsRotationLocked());
settings.updateStream.where((event) => event.key == Settings.isInstalledAppAccessAllowedKey).listen((_) => applyIsInstalledAppAccessAllowed());
settings.updateStream.where((event) => event.key == Settings.keepScreenOnKey).listen((_) => applyKeepScreenOn());
settings.updateStream.where((event) => event.key == Settings.platformAccelerometerRotationKey).listen((_) => applyIsRotationLocked());
applyKeepScreenOn();
applyIsRotationLocked();
@ -239,7 +239,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
Future<void> _setupErrorReporting() async {
await reportService.init();
settings.updateStream.where((key) => key == Settings.isErrorReportingAllowedKey).listen(
settings.updateStream.where((event) => event.key == Settings.isErrorReportingAllowedKey).listen(
(_) => reportService.setCollectionEnabled(settings.isErrorReportingAllowed),
);
await reportService.setCollectionEnabled(settings.isErrorReportingAllowed);

View file

@ -40,7 +40,7 @@ class _CollectionPageState extends State<CollectionPage> {
@override
void initState() {
super.initState();
_subscriptions.add(settings.updateStream.where((key) => key == Settings.enableBinKey).listen((_) {
_subscriptions.add(settings.updateStream.where((event) => event.key == Settings.enableBinKey).listen((_) {
if (!settings.enableBin) {
collection.removeFilter(TrashFilter.instance);
}

View file

@ -132,7 +132,6 @@ class _AppDebugPageState extends State<AppDebugPage> {
),
ElevatedButton(
onPressed: () async {
final source = context.read<CollectionSource>();
await source.init();
await source.refresh();
},
@ -163,18 +162,16 @@ class _AppDebugPageState extends State<AppDebugPage> {
Future<void> _onActionSelected(AppDebugAction action) async {
switch (action) {
case AppDebugAction.prepScreenshotThumbnails:
final source = context.read<CollectionSource>();
source.changeFilterVisibility(settings.hiddenFilters, true);
source.changeFilterVisibility({
settings.changeFilterVisibility(settings.hiddenFilters, true);
settings.changeFilterVisibility({
TagFilter('aves-thumbnail', not: true),
}, false);
await favourites.clear();
await favourites.add(source.visibleEntries);
break;
case AppDebugAction.prepScreenshotStats:
final source = context.read<CollectionSource>();
source.changeFilterVisibility(settings.hiddenFilters, true);
source.changeFilterVisibility({
settings.changeFilterVisibility(settings.hiddenFilters, true);
settings.changeFilterVisibility({
PathFilter('/storage/emulated/0/Pictures/Dev'),
}, false);
break;

View file

@ -1,7 +1,7 @@
import 'package:aves/model/actions/chip_actions.dart';
import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/highlight.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:aves/widgets/filter_grids/albums_page.dart';
@ -51,8 +51,7 @@ class ChipActionDelegate {
);
if (confirmed == null || !confirmed) return;
final source = context.read<CollectionSource>();
source.changeFilterVisibility({filter}, false);
settings.changeFilterVisibility({filter}, false);
}
void _goTo(

View file

@ -271,8 +271,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
);
if (confirmed == null || !confirmed) return;
final source = context.read<CollectionSource>();
source.changeFilterVisibility(filters, false);
settings.changeFilterVisibility(filters, false);
_browse(context);
}

View file

@ -1,7 +1,6 @@
import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/filters/path.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
@ -116,7 +115,7 @@ class _HiddenFilters extends StatelessWidget {
.map((filter) => AvesFilterChip(
filter: filter,
removable: true,
onTap: (filter) => context.read<CollectionSource>().changeFilterVisibility({filter}, true),
onTap: (filter) => settings.changeFilterVisibility({filter}, true),
onLongPress: null,
))
.toList(),
@ -152,7 +151,7 @@ class _HiddenPaths extends StatelessWidget {
trailing: IconButton(
icon: const Icon(AIcons.clear),
onPressed: () {
context.read<CollectionSource>().changeFilterVisibility({pathFilter}, true);
settings.changeFilterVisibility({pathFilter}, true);
},
tooltip: context.l10n.actionRemove,
),
@ -176,7 +175,7 @@ class _HiddenPaths extends StatelessWidget {
// wait for the dialog to hide as applying the change may block the UI
await Future.delayed(Durations.pageTransitionAnimation * timeDilation);
if (path != null && path.isNotEmpty) {
context.read<CollectionSource>().changeFilterVisibility({PathFilter(path)}, false);
settings.changeFilterVisibility({PathFilter(path)}, false);
}
},
),

View file

@ -2,7 +2,6 @@ import 'package:aves/model/filters/mime.dart';
import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/enums/video_loop_mode.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
@ -36,7 +35,7 @@ class VideoSection extends StatelessWidget {
if (!standalonePage)
SwitchListTile(
value: currentShowVideos,
onChanged: (v) => context.read<CollectionSource>().changeFilterVisibility({MimeFilter.video}, v),
onChanged: (v) => settings.changeFilterVisibility({MimeFilter.video}, v),
title: Text(context.l10n.settingsVideoShowVideos),
),
const VideoActionsTile(),