From ebc147771c30298502d23598b529f5a83254861f Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Wed, 11 Jan 2023 19:26:48 +0100 Subject: [PATCH] minor fixes --- .../aves/channel/calls/MetadataEditHandler.kt | 53 ++-- .../thibault/aves/metadata/Mp4ParserHelper.kt | 4 +- .../deckers/thibault/aves/utils/MimeTypes.kt | 3 +- lib/model/settings/settings.dart | 235 +++++++++--------- lib/services/accessibility_service.dart | 8 +- lib/services/window_service.dart | 8 +- lib/utils/dependencies.dart | 4 +- lib/widgets/stats/filter_table.dart | 10 +- lib/widgets/stats/percent_text.dart | 30 +++ lib/widgets/stats/stats_page.dart | 11 +- pubspec.lock | 8 +- pubspec.yaml | 4 + 12 files changed, 217 insertions(+), 161 deletions(-) create mode 100644 lib/widgets/stats/percent_text.dart diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataEditHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataEditHandler.kt index df2c1c86e..bb349855a 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataEditHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataEditHandler.kt @@ -3,6 +3,7 @@ package deckers.thibault.aves.channel.calls import android.content.ContextWrapper import android.net.Uri import deckers.thibault.aves.channel.calls.Coresult.Companion.safe +import deckers.thibault.aves.metadata.Mp4TooLargeException import deckers.thibault.aves.model.ExifOrientationOp import deckers.thibault.aves.model.FieldMap import deckers.thibault.aves.model.provider.ImageProvider.ImageOpCallback @@ -66,10 +67,8 @@ class MetadataEditHandler(private val contextWrapper: ContextWrapper) : MethodCa return } - provider.editOrientation(contextWrapper, path, uri, mimeType, op, object : ImageOpCallback { - override fun onSuccess(fields: FieldMap) = result.success(fields) - override fun onFailure(throwable: Throwable) = result.error("editOrientation-failure", "failed to change orientation for mimeType=$mimeType uri=$uri", throwable) - }) + val callback = MetadataOpCallback("editOrientation", entryMap, result) + provider.editOrientation(contextWrapper, path, uri, mimeType, op, callback) } private fun editDate(call: MethodCall, result: MethodChannel.Result) { @@ -96,10 +95,8 @@ class MetadataEditHandler(private val contextWrapper: ContextWrapper) : MethodCa return } - provider.editDate(contextWrapper, path, uri, mimeType, dateMillis, shiftMinutes, fields, object : ImageOpCallback { - override fun onSuccess(fields: FieldMap) = result.success(fields) - override fun onFailure(throwable: Throwable) = result.error("editDate-failure", "failed to edit date for mimeType=$mimeType uri=$uri", throwable) - }) + val callback = MetadataOpCallback("editDate", entryMap, result) + provider.editDate(contextWrapper, path, uri, mimeType, dateMillis, shiftMinutes, fields, callback) } private fun editMetadata(call: MethodCall, result: MethodChannel.Result) { @@ -125,10 +122,8 @@ class MetadataEditHandler(private val contextWrapper: ContextWrapper) : MethodCa return } - provider.editMetadata(contextWrapper, path, uri, mimeType, metadata, autoCorrectTrailerOffset, callback = object : ImageOpCallback { - override fun onSuccess(fields: FieldMap) = result.success(fields) - override fun onFailure(throwable: Throwable) = result.error("editMetadata-failure", "failed to edit metadata for mimeType=$mimeType uri=$uri", throwable) - }) + val callback = MetadataOpCallback("editMetadata", entryMap, result) + provider.editMetadata(contextWrapper, path, uri, mimeType, metadata, autoCorrectTrailerOffset, callback) } private fun removeTrailerVideo(call: MethodCall, result: MethodChannel.Result) { @@ -152,10 +147,8 @@ class MetadataEditHandler(private val contextWrapper: ContextWrapper) : MethodCa return } - provider.removeTrailerVideo(contextWrapper, path, uri, mimeType, object : ImageOpCallback { - override fun onSuccess(fields: FieldMap) = result.success(fields) - override fun onFailure(throwable: Throwable) = result.error("removeTrailerVideo-failure", "failed to remove trailer video for mimeType=$mimeType uri=$uri", throwable) - }) + val callback = MetadataOpCallback("removeTrailerVideo", entryMap, result) + provider.removeTrailerVideo(contextWrapper, path, uri, mimeType, callback) } private fun removeTypes(call: MethodCall, result: MethodChannel.Result) { @@ -180,13 +173,31 @@ class MetadataEditHandler(private val contextWrapper: ContextWrapper) : MethodCa return } - provider.removeMetadataTypes(contextWrapper, path, uri, mimeType, types.toSet(), object : ImageOpCallback { - override fun onSuccess(fields: FieldMap) = result.success(fields) - override fun onFailure(throwable: Throwable) = result.error("removeTypes-failure", "failed to remove metadata for mimeType=$mimeType uri=$uri", throwable) - }) + val callback = MetadataOpCallback("removeTypes", entryMap, result) + provider.removeMetadataTypes(contextWrapper, path, uri, mimeType, types.toSet(), callback) } companion object { const val CHANNEL = "deckers.thibault/aves/metadata_edit" } -} \ No newline at end of file +} + +private class MetadataOpCallback( + private val errorCodeBase: String, + private val entryMap: FieldMap, + private val result: MethodChannel.Result, +) : ImageOpCallback { + override fun onSuccess(fields: FieldMap) = result.success(fields) + override fun onFailure(throwable: Throwable) { + val errorCode = if (throwable is Mp4TooLargeException) { + if (throwable.type == "moov") { + "$errorCodeBase-mp4largemoov" + } else { + "$errorCodeBase-mp4largeother" + } + } else { + "$errorCodeBase-failure" + } + result.error(errorCode, "failed for entry=$entryMap", throwable) + } +} diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/Mp4ParserHelper.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/Mp4ParserHelper.kt index 5f86a11a6..8edb548df 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/Mp4ParserHelper.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/Mp4ParserHelper.kt @@ -33,7 +33,7 @@ object Mp4ParserHelper { ) setBoxSkipper { type, size -> if (skippedTypes.contains(type)) return@setBoxSkipper true - if (size > BOX_SIZE_DANGER_THRESHOLD) throw Exception("box (type=$type size=$size) is too large") + if (size > BOX_SIZE_DANGER_THRESHOLD) throw Mp4TooLargeException(type, "box (type=$type size=$size) is too large") false } } @@ -232,3 +232,5 @@ object Mp4ParserHelper { return stream.toByteArray() } } + +class Mp4TooLargeException(val type: String, message: String) : RuntimeException(message) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt index af0e471c2..df4ea5f75 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt @@ -90,7 +90,8 @@ object MimeTypes { // as of `metadata-extractor` v2.14.0 fun canReadWithMetadataExtractor(mimeType: String) = when (mimeType) { - DJVU, WBMP, MKV, MP2T, MP2TS, OGV, WEBM -> false + DJVU, WBMP -> false + MKV, MP2T, MP2TS, OGV, WEBM -> false else -> true } diff --git a/lib/model/settings/settings.dart b/lib/model/settings/settings.dart index cd3fcd57c..27c944d82 100644 --- a/lib/model/settings/settings.dart +++ b/lib/model/settings/settings.dart @@ -13,6 +13,7 @@ import 'package:aves/model/settings/defaults.dart'; import 'package:aves/model/settings/enums/enums.dart'; import 'package:aves/model/settings/enums/map_style.dart'; import 'package:aves/model/source/enums/enums.dart'; +import 'package:aves/services/accessibility_service.dart'; import 'package:aves/services/common/optional_event_channel.dart'; import 'package:aves/services/common/services.dart'; import 'package:aves/widgets/aves_app.dart'; @@ -276,23 +277,32 @@ class Settings extends ChangeNotifier { } } + Future sanitize() async { + if (timeToTakeAction == AccessibilityTimeout.system && !(await AccessibilityService.hasRecommendedTimeouts())) { + _set(timeToTakeActionKey, null); + } + if (viewerUseCutout != SettingsDefaults.viewerUseCutout && !(await windowService.isCutoutAware())) { + _set(viewerUseCutoutKey, null); + } + } + // app bool get hasAcceptedTerms => getBool(hasAcceptedTermsKey) ?? SettingsDefaults.hasAcceptedTerms; - set hasAcceptedTerms(bool newValue) => setAndNotify(hasAcceptedTermsKey, newValue); + set hasAcceptedTerms(bool newValue) => _set(hasAcceptedTermsKey, newValue); bool get canUseAnalysisService => getBool(canUseAnalysisServiceKey) ?? SettingsDefaults.canUseAnalysisService; - set canUseAnalysisService(bool newValue) => setAndNotify(canUseAnalysisServiceKey, newValue); + set canUseAnalysisService(bool newValue) => _set(canUseAnalysisServiceKey, newValue); bool get isInstalledAppAccessAllowed => getBool(isInstalledAppAccessAllowedKey) ?? SettingsDefaults.isInstalledAppAccessAllowed; - set isInstalledAppAccessAllowed(bool newValue) => setAndNotify(isInstalledAppAccessAllowedKey, newValue); + set isInstalledAppAccessAllowed(bool newValue) => _set(isInstalledAppAccessAllowedKey, newValue); bool get isErrorReportingAllowed => getBool(isErrorReportingAllowedKey) ?? SettingsDefaults.isErrorReportingAllowed; - set isErrorReportingAllowed(bool newValue) => setAndNotify(isErrorReportingAllowedKey, newValue); + set isErrorReportingAllowed(bool newValue) => _set(isErrorReportingAllowedKey, newValue); static const localeSeparator = '-'; @@ -319,7 +329,7 @@ class Settings extends ChangeNotifier { newValue.countryCode ?? '', ].join(localeSeparator); } - setAndNotify(localeKey, tag); + _set(localeKey, tag); _appliedLocale = null; } @@ -349,57 +359,57 @@ class Settings extends ChangeNotifier { String get catalogTimeZone => getString(catalogTimeZoneKey) ?? ''; - set catalogTimeZone(String newValue) => setAndNotify(catalogTimeZoneKey, newValue); + set catalogTimeZone(String newValue) => _set(catalogTimeZoneKey, newValue); double getTileExtent(String routeName) => getDouble(tileExtentPrefixKey + routeName) ?? 0; - void setTileExtent(String routeName, double newValue) => setAndNotify(tileExtentPrefixKey + routeName, newValue); + void setTileExtent(String routeName, double newValue) => _set(tileExtentPrefixKey + routeName, newValue); TileLayout getTileLayout(String routeName) => getEnumOrDefault(tileLayoutPrefixKey + routeName, SettingsDefaults.tileLayout, TileLayout.values); - void setTileLayout(String routeName, TileLayout newValue) => setAndNotify(tileLayoutPrefixKey + routeName, newValue.toString()); + void setTileLayout(String routeName, TileLayout newValue) => _set(tileLayoutPrefixKey + routeName, newValue.toString()); String get entryRenamingPattern => getString(entryRenamingPatternKey) ?? SettingsDefaults.entryRenamingPattern; - set entryRenamingPattern(String newValue) => setAndNotify(entryRenamingPatternKey, newValue); + set entryRenamingPattern(String newValue) => _set(entryRenamingPatternKey, newValue); List? get topEntryIds => getStringList(topEntryIdsKey)?.map(int.tryParse).whereNotNull().toList(); - set topEntryIds(List? newValue) => setAndNotify(topEntryIdsKey, newValue?.map((id) => id.toString()).whereNotNull().toList()); + set topEntryIds(List? newValue) => _set(topEntryIdsKey, newValue?.map((id) => id.toString()).whereNotNull().toList()); List get recentDestinationAlbums => getStringList(recentDestinationAlbumsKey) ?? []; - set recentDestinationAlbums(List newValue) => setAndNotify(recentDestinationAlbumsKey, newValue.take(_recentFilterHistoryMax).toList()); + set recentDestinationAlbums(List newValue) => _set(recentDestinationAlbumsKey, newValue.take(_recentFilterHistoryMax).toList()); List get recentTags => (getStringList(recentTagsKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toList(); - set recentTags(List newValue) => setAndNotify(recentTagsKey, newValue.take(_recentFilterHistoryMax).map((filter) => filter.toJson()).toList()); + set recentTags(List newValue) => _set(recentTagsKey, newValue.take(_recentFilterHistoryMax).map((filter) => filter.toJson()).toList()); // display DisplayRefreshRateMode get displayRefreshRateMode => getEnumOrDefault(displayRefreshRateModeKey, SettingsDefaults.displayRefreshRateMode, DisplayRefreshRateMode.values); - set displayRefreshRateMode(DisplayRefreshRateMode newValue) => setAndNotify(displayRefreshRateModeKey, newValue.toString()); + set displayRefreshRateMode(DisplayRefreshRateMode newValue) => _set(displayRefreshRateModeKey, newValue.toString()); AvesThemeBrightness get themeBrightness => getEnumOrDefault(themeBrightnessKey, SettingsDefaults.themeBrightness, AvesThemeBrightness.values); - set themeBrightness(AvesThemeBrightness newValue) => setAndNotify(themeBrightnessKey, newValue.toString()); + set themeBrightness(AvesThemeBrightness newValue) => _set(themeBrightnessKey, newValue.toString()); AvesThemeColorMode get themeColorMode => getEnumOrDefault(themeColorModeKey, SettingsDefaults.themeColorMode, AvesThemeColorMode.values); - set themeColorMode(AvesThemeColorMode newValue) => setAndNotify(themeColorModeKey, newValue.toString()); + set themeColorMode(AvesThemeColorMode newValue) => _set(themeColorModeKey, newValue.toString()); bool get enableDynamicColor => getBool(enableDynamicColorKey) ?? SettingsDefaults.enableDynamicColor; - set enableDynamicColor(bool newValue) => setAndNotify(enableDynamicColorKey, newValue); + set enableDynamicColor(bool newValue) => _set(enableDynamicColorKey, newValue); bool get enableBlurEffect => getBool(enableBlurEffectKey) ?? SettingsDefaults.enableBlurEffect; - set enableBlurEffect(bool newValue) => setAndNotify(enableBlurEffectKey, newValue); + set enableBlurEffect(bool newValue) => _set(enableBlurEffectKey, newValue); bool get forceTvLayout => getBool(forceTvLayoutKey) ?? SettingsDefaults.forceTvLayout; - set forceTvLayout(bool newValue) => setAndNotify(forceTvLayoutKey, newValue); + set forceTvLayout(bool newValue) => _set(forceTvLayoutKey, newValue); bool get useTvLayout => device.isTelevision || forceTvLayout; @@ -409,39 +419,39 @@ class Settings extends ChangeNotifier { bool get mustBackTwiceToExit => getBool(mustBackTwiceToExitKey) ?? SettingsDefaults.mustBackTwiceToExit; - set mustBackTwiceToExit(bool newValue) => setAndNotify(mustBackTwiceToExitKey, newValue); + set mustBackTwiceToExit(bool newValue) => _set(mustBackTwiceToExitKey, newValue); KeepScreenOn get keepScreenOn => getEnumOrDefault(keepScreenOnKey, SettingsDefaults.keepScreenOn, KeepScreenOn.values); - set keepScreenOn(KeepScreenOn newValue) => setAndNotify(keepScreenOnKey, newValue.toString()); + set keepScreenOn(KeepScreenOn newValue) => _set(keepScreenOnKey, newValue.toString()); HomePageSetting get homePage => getEnumOrDefault(homePageKey, SettingsDefaults.homePage, HomePageSetting.values); - set homePage(HomePageSetting newValue) => setAndNotify(homePageKey, newValue.toString()); + set homePage(HomePageSetting newValue) => _set(homePageKey, newValue.toString()); bool get enableBottomNavigationBar => getBool(enableBottomNavigationBarKey) ?? SettingsDefaults.enableBottomNavigationBar; - set enableBottomNavigationBar(bool newValue) => setAndNotify(enableBottomNavigationBarKey, newValue); + set enableBottomNavigationBar(bool newValue) => _set(enableBottomNavigationBarKey, newValue); bool get confirmDeleteForever => getBool(confirmDeleteForeverKey) ?? SettingsDefaults.confirmDeleteForever; - set confirmDeleteForever(bool newValue) => setAndNotify(confirmDeleteForeverKey, newValue); + set confirmDeleteForever(bool newValue) => _set(confirmDeleteForeverKey, newValue); bool get confirmMoveToBin => getBool(confirmMoveToBinKey) ?? SettingsDefaults.confirmMoveToBin; - set confirmMoveToBin(bool newValue) => setAndNotify(confirmMoveToBinKey, newValue); + set confirmMoveToBin(bool newValue) => _set(confirmMoveToBinKey, newValue); bool get confirmMoveUndatedItems => getBool(confirmMoveUndatedItemsKey) ?? SettingsDefaults.confirmMoveUndatedItems; - set confirmMoveUndatedItems(bool newValue) => setAndNotify(confirmMoveUndatedItemsKey, newValue); + set confirmMoveUndatedItems(bool newValue) => _set(confirmMoveUndatedItemsKey, newValue); bool get confirmAfterMoveToBin => getBool(confirmAfterMoveToBinKey) ?? SettingsDefaults.confirmAfterMoveToBin; - set confirmAfterMoveToBin(bool newValue) => setAndNotify(confirmAfterMoveToBinKey, newValue); + set confirmAfterMoveToBin(bool newValue) => _set(confirmAfterMoveToBinKey, newValue); bool get setMetadataDateBeforeFileOp => getBool(setMetadataDateBeforeFileOpKey) ?? SettingsDefaults.setMetadataDateBeforeFileOp; - set setMetadataDateBeforeFileOp(bool newValue) => setAndNotify(setMetadataDateBeforeFileOpKey, newValue); + set setMetadataDateBeforeFileOp(bool newValue) => _set(setMetadataDateBeforeFileOpKey, newValue); List get drawerTypeBookmarks => (getStringList(drawerTypeBookmarksKey))?.map((v) { @@ -450,103 +460,103 @@ class Settings extends ChangeNotifier { }).toList() ?? SettingsDefaults.drawerTypeBookmarks; - set drawerTypeBookmarks(List newValue) => setAndNotify(drawerTypeBookmarksKey, newValue.map((filter) => filter?.toJson() ?? '').toList()); + set drawerTypeBookmarks(List newValue) => _set(drawerTypeBookmarksKey, newValue.map((filter) => filter?.toJson() ?? '').toList()); List? get drawerAlbumBookmarks => getStringList(drawerAlbumBookmarksKey); - set drawerAlbumBookmarks(List? newValue) => setAndNotify(drawerAlbumBookmarksKey, newValue); + set drawerAlbumBookmarks(List? newValue) => _set(drawerAlbumBookmarksKey, newValue); List get drawerPageBookmarks => getStringList(drawerPageBookmarksKey) ?? SettingsDefaults.drawerPageBookmarks; - set drawerPageBookmarks(List newValue) => setAndNotify(drawerPageBookmarksKey, newValue); + set drawerPageBookmarks(List newValue) => _set(drawerPageBookmarksKey, newValue); // collection EntryGroupFactor get collectionSectionFactor => getEnumOrDefault(collectionGroupFactorKey, SettingsDefaults.collectionSectionFactor, EntryGroupFactor.values); - set collectionSectionFactor(EntryGroupFactor newValue) => setAndNotify(collectionGroupFactorKey, newValue.toString()); + set collectionSectionFactor(EntryGroupFactor newValue) => _set(collectionGroupFactorKey, newValue.toString()); EntrySortFactor get collectionSortFactor => getEnumOrDefault(collectionSortFactorKey, SettingsDefaults.collectionSortFactor, EntrySortFactor.values); - set collectionSortFactor(EntrySortFactor newValue) => setAndNotify(collectionSortFactorKey, newValue.toString()); + set collectionSortFactor(EntrySortFactor newValue) => _set(collectionSortFactorKey, newValue.toString()); bool get collectionSortReverse => getBool(collectionSortReverseKey) ?? false; - set collectionSortReverse(bool newValue) => setAndNotify(collectionSortReverseKey, newValue); + set collectionSortReverse(bool newValue) => _set(collectionSortReverseKey, newValue); List get collectionBrowsingQuickActions => getEnumListOrDefault(collectionBrowsingQuickActionsKey, SettingsDefaults.collectionBrowsingQuickActions, EntrySetAction.values); - set collectionBrowsingQuickActions(List newValue) => setAndNotify(collectionBrowsingQuickActionsKey, newValue.map((v) => v.toString()).toList()); + set collectionBrowsingQuickActions(List newValue) => _set(collectionBrowsingQuickActionsKey, newValue.map((v) => v.toString()).toList()); List get collectionSelectionQuickActions => getEnumListOrDefault(collectionSelectionQuickActionsKey, SettingsDefaults.collectionSelectionQuickActions, EntrySetAction.values); - set collectionSelectionQuickActions(List newValue) => setAndNotify(collectionSelectionQuickActionsKey, newValue.map((v) => v.toString()).toList()); + set collectionSelectionQuickActions(List newValue) => _set(collectionSelectionQuickActionsKey, newValue.map((v) => v.toString()).toList()); bool get showThumbnailFavourite => getBool(showThumbnailFavouriteKey) ?? SettingsDefaults.showThumbnailFavourite; - set showThumbnailFavourite(bool newValue) => setAndNotify(showThumbnailFavouriteKey, newValue); + set showThumbnailFavourite(bool newValue) => _set(showThumbnailFavouriteKey, newValue); ThumbnailOverlayLocationIcon get thumbnailLocationIcon => getEnumOrDefault(thumbnailLocationIconKey, SettingsDefaults.thumbnailLocationIcon, ThumbnailOverlayLocationIcon.values); - set thumbnailLocationIcon(ThumbnailOverlayLocationIcon newValue) => setAndNotify(thumbnailLocationIconKey, newValue.toString()); + set thumbnailLocationIcon(ThumbnailOverlayLocationIcon newValue) => _set(thumbnailLocationIconKey, newValue.toString()); ThumbnailOverlayTagIcon get thumbnailTagIcon => getEnumOrDefault(thumbnailTagIconKey, SettingsDefaults.thumbnailTagIcon, ThumbnailOverlayTagIcon.values); - set thumbnailTagIcon(ThumbnailOverlayTagIcon newValue) => setAndNotify(thumbnailTagIconKey, newValue.toString()); + set thumbnailTagIcon(ThumbnailOverlayTagIcon newValue) => _set(thumbnailTagIconKey, newValue.toString()); bool get showThumbnailMotionPhoto => getBool(showThumbnailMotionPhotoKey) ?? SettingsDefaults.showThumbnailMotionPhoto; - set showThumbnailMotionPhoto(bool newValue) => setAndNotify(showThumbnailMotionPhotoKey, newValue); + set showThumbnailMotionPhoto(bool newValue) => _set(showThumbnailMotionPhotoKey, newValue); bool get showThumbnailRating => getBool(showThumbnailRatingKey) ?? SettingsDefaults.showThumbnailRating; - set showThumbnailRating(bool newValue) => setAndNotify(showThumbnailRatingKey, newValue); + set showThumbnailRating(bool newValue) => _set(showThumbnailRatingKey, newValue); bool get showThumbnailRaw => getBool(showThumbnailRawKey) ?? SettingsDefaults.showThumbnailRaw; - set showThumbnailRaw(bool newValue) => setAndNotify(showThumbnailRawKey, newValue); + set showThumbnailRaw(bool newValue) => _set(showThumbnailRawKey, newValue); bool get showThumbnailVideoDuration => getBool(showThumbnailVideoDurationKey) ?? SettingsDefaults.showThumbnailVideoDuration; - set showThumbnailVideoDuration(bool newValue) => setAndNotify(showThumbnailVideoDurationKey, newValue); + set showThumbnailVideoDuration(bool newValue) => _set(showThumbnailVideoDurationKey, newValue); // filter grids AlbumChipGroupFactor get albumGroupFactor => getEnumOrDefault(albumGroupFactorKey, SettingsDefaults.albumGroupFactor, AlbumChipGroupFactor.values); - set albumGroupFactor(AlbumChipGroupFactor newValue) => setAndNotify(albumGroupFactorKey, newValue.toString()); + set albumGroupFactor(AlbumChipGroupFactor newValue) => _set(albumGroupFactorKey, newValue.toString()); ChipSortFactor get albumSortFactor => getEnumOrDefault(albumSortFactorKey, SettingsDefaults.albumSortFactor, ChipSortFactor.values); - set albumSortFactor(ChipSortFactor newValue) => setAndNotify(albumSortFactorKey, newValue.toString()); + set albumSortFactor(ChipSortFactor newValue) => _set(albumSortFactorKey, newValue.toString()); ChipSortFactor get countrySortFactor => getEnumOrDefault(countrySortFactorKey, SettingsDefaults.countrySortFactor, ChipSortFactor.values); - set countrySortFactor(ChipSortFactor newValue) => setAndNotify(countrySortFactorKey, newValue.toString()); + set countrySortFactor(ChipSortFactor newValue) => _set(countrySortFactorKey, newValue.toString()); ChipSortFactor get tagSortFactor => getEnumOrDefault(tagSortFactorKey, SettingsDefaults.tagSortFactor, ChipSortFactor.values); - set tagSortFactor(ChipSortFactor newValue) => setAndNotify(tagSortFactorKey, newValue.toString()); + set tagSortFactor(ChipSortFactor newValue) => _set(tagSortFactorKey, newValue.toString()); bool get albumSortReverse => getBool(albumSortReverseKey) ?? false; - set albumSortReverse(bool newValue) => setAndNotify(albumSortReverseKey, newValue); + set albumSortReverse(bool newValue) => _set(albumSortReverseKey, newValue); bool get countrySortReverse => getBool(countrySortReverseKey) ?? false; - set countrySortReverse(bool newValue) => setAndNotify(countrySortReverseKey, newValue); + set countrySortReverse(bool newValue) => _set(countrySortReverseKey, newValue); bool get tagSortReverse => getBool(tagSortReverseKey) ?? false; - set tagSortReverse(bool newValue) => setAndNotify(tagSortReverseKey, newValue); + set tagSortReverse(bool newValue) => _set(tagSortReverseKey, newValue); Set get pinnedFilters => (getStringList(pinnedFiltersKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet(); - set pinnedFilters(Set newValue) => setAndNotify(pinnedFiltersKey, newValue.map((filter) => filter.toJson()).toList()); + set pinnedFilters(Set newValue) => _set(pinnedFiltersKey, newValue.map((filter) => filter.toJson()).toList()); Set get hiddenFilters => (getStringList(hiddenFiltersKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet(); - set hiddenFilters(Set newValue) => setAndNotify(hiddenFiltersKey, newValue.map((filter) => filter.toJson()).toList()); + set hiddenFilters(Set newValue) => _set(hiddenFiltersKey, newValue.map((filter) => filter.toJson()).toList()); void changeFilterVisibility(Set filters, bool visible) { final _hiddenFilters = hiddenFilters; @@ -563,131 +573,131 @@ class Settings extends ChangeNotifier { List get viewerQuickActions => getEnumListOrDefault(viewerQuickActionsKey, SettingsDefaults.viewerQuickActions, EntryAction.values); - set viewerQuickActions(List newValue) => setAndNotify(viewerQuickActionsKey, newValue.map((v) => v.toString()).toList()); + set viewerQuickActions(List newValue) => _set(viewerQuickActionsKey, newValue.map((v) => v.toString()).toList()); bool get showOverlayOnOpening => getBool(showOverlayOnOpeningKey) ?? SettingsDefaults.showOverlayOnOpening; - set showOverlayOnOpening(bool newValue) => setAndNotify(showOverlayOnOpeningKey, newValue); + set showOverlayOnOpening(bool newValue) => _set(showOverlayOnOpeningKey, newValue); bool get showOverlayMinimap => getBool(showOverlayMinimapKey) ?? SettingsDefaults.showOverlayMinimap; - set showOverlayMinimap(bool newValue) => setAndNotify(showOverlayMinimapKey, newValue); + set showOverlayMinimap(bool newValue) => _set(showOverlayMinimapKey, newValue); bool get showOverlayInfo => getBool(showOverlayInfoKey) ?? SettingsDefaults.showOverlayInfo; - set showOverlayInfo(bool newValue) => setAndNotify(showOverlayInfoKey, newValue); + set showOverlayInfo(bool newValue) => _set(showOverlayInfoKey, newValue); bool get showOverlayDescription => getBool(showOverlayDescriptionKey) ?? SettingsDefaults.showOverlayDescription; - set showOverlayDescription(bool newValue) => setAndNotify(showOverlayDescriptionKey, newValue); + set showOverlayDescription(bool newValue) => _set(showOverlayDescriptionKey, newValue); bool get showOverlayRatingTags => getBool(showOverlayRatingTagsKey) ?? SettingsDefaults.showOverlayRatingTags; - set showOverlayRatingTags(bool newValue) => setAndNotify(showOverlayRatingTagsKey, newValue); + set showOverlayRatingTags(bool newValue) => _set(showOverlayRatingTagsKey, newValue); bool get showOverlayShootingDetails => getBool(showOverlayShootingDetailsKey) ?? SettingsDefaults.showOverlayShootingDetails; - set showOverlayShootingDetails(bool newValue) => setAndNotify(showOverlayShootingDetailsKey, newValue); + set showOverlayShootingDetails(bool newValue) => _set(showOverlayShootingDetailsKey, newValue); bool get showOverlayThumbnailPreview => getBool(showOverlayThumbnailPreviewKey) ?? SettingsDefaults.showOverlayThumbnailPreview; - set showOverlayThumbnailPreview(bool newValue) => setAndNotify(showOverlayThumbnailPreviewKey, newValue); + set showOverlayThumbnailPreview(bool newValue) => _set(showOverlayThumbnailPreviewKey, newValue); bool get viewerGestureSideTapNext => getBool(viewerGestureSideTapNextKey) ?? SettingsDefaults.viewerGestureSideTapNext; - set viewerGestureSideTapNext(bool newValue) => setAndNotify(viewerGestureSideTapNextKey, newValue); + set viewerGestureSideTapNext(bool newValue) => _set(viewerGestureSideTapNextKey, newValue); bool get viewerUseCutout => getBool(viewerUseCutoutKey) ?? SettingsDefaults.viewerUseCutout; - set viewerUseCutout(bool newValue) => setAndNotify(viewerUseCutoutKey, newValue); + set viewerUseCutout(bool newValue) => _set(viewerUseCutoutKey, newValue); bool get viewerMaxBrightness => getBool(viewerMaxBrightnessKey) ?? SettingsDefaults.viewerMaxBrightness; - set viewerMaxBrightness(bool newValue) => setAndNotify(viewerMaxBrightnessKey, newValue); + set viewerMaxBrightness(bool newValue) => _set(viewerMaxBrightnessKey, newValue); bool get enableMotionPhotoAutoPlay => getBool(enableMotionPhotoAutoPlayKey) ?? SettingsDefaults.enableMotionPhotoAutoPlay; - set enableMotionPhotoAutoPlay(bool newValue) => setAndNotify(enableMotionPhotoAutoPlayKey, newValue); + set enableMotionPhotoAutoPlay(bool newValue) => _set(enableMotionPhotoAutoPlayKey, newValue); EntryBackground get imageBackground => getEnumOrDefault(imageBackgroundKey, SettingsDefaults.imageBackground, EntryBackground.values); - set imageBackground(EntryBackground newValue) => setAndNotify(imageBackgroundKey, newValue.toString()); + set imageBackground(EntryBackground newValue) => _set(imageBackgroundKey, newValue.toString()); // video bool get enableVideoHardwareAcceleration => getBool(enableVideoHardwareAccelerationKey) ?? SettingsDefaults.enableVideoHardwareAcceleration; - set enableVideoHardwareAcceleration(bool newValue) => setAndNotify(enableVideoHardwareAccelerationKey, newValue); + set enableVideoHardwareAcceleration(bool newValue) => _set(enableVideoHardwareAccelerationKey, newValue); VideoAutoPlayMode get videoAutoPlayMode => getEnumOrDefault(videoAutoPlayModeKey, SettingsDefaults.videoAutoPlayMode, VideoAutoPlayMode.values); - set videoAutoPlayMode(VideoAutoPlayMode newValue) => setAndNotify(videoAutoPlayModeKey, newValue.toString()); + set videoAutoPlayMode(VideoAutoPlayMode newValue) => _set(videoAutoPlayModeKey, newValue.toString()); VideoLoopMode get videoLoopMode => getEnumOrDefault(videoLoopModeKey, SettingsDefaults.videoLoopMode, VideoLoopMode.values); - set videoLoopMode(VideoLoopMode newValue) => setAndNotify(videoLoopModeKey, newValue.toString()); + set videoLoopMode(VideoLoopMode newValue) => _set(videoLoopModeKey, newValue.toString()); bool get videoShowRawTimedText => getBool(videoShowRawTimedTextKey) ?? SettingsDefaults.videoShowRawTimedText; - set videoShowRawTimedText(bool newValue) => setAndNotify(videoShowRawTimedTextKey, newValue); + set videoShowRawTimedText(bool newValue) => _set(videoShowRawTimedTextKey, newValue); VideoControls get videoControls => getEnumOrDefault(videoControlsKey, SettingsDefaults.videoControls, VideoControls.values); - set videoControls(VideoControls newValue) => setAndNotify(videoControlsKey, newValue.toString()); + set videoControls(VideoControls newValue) => _set(videoControlsKey, newValue.toString()); bool get videoGestureDoubleTapTogglePlay => getBool(videoGestureDoubleTapTogglePlayKey) ?? SettingsDefaults.videoGestureDoubleTapTogglePlay; - set videoGestureDoubleTapTogglePlay(bool newValue) => setAndNotify(videoGestureDoubleTapTogglePlayKey, newValue); + set videoGestureDoubleTapTogglePlay(bool newValue) => _set(videoGestureDoubleTapTogglePlayKey, newValue); bool get videoGestureSideDoubleTapSeek => getBool(videoGestureSideDoubleTapSeekKey) ?? SettingsDefaults.videoGestureSideDoubleTapSeek; - set videoGestureSideDoubleTapSeek(bool newValue) => setAndNotify(videoGestureSideDoubleTapSeekKey, newValue); + set videoGestureSideDoubleTapSeek(bool newValue) => _set(videoGestureSideDoubleTapSeekKey, newValue); // subtitles double get subtitleFontSize => getDouble(subtitleFontSizeKey) ?? SettingsDefaults.subtitleFontSize; - set subtitleFontSize(double newValue) => setAndNotify(subtitleFontSizeKey, newValue); + set subtitleFontSize(double newValue) => _set(subtitleFontSizeKey, newValue); TextAlign get subtitleTextAlignment => getEnumOrDefault(subtitleTextAlignmentKey, SettingsDefaults.subtitleTextAlignment, TextAlign.values); - set subtitleTextAlignment(TextAlign newValue) => setAndNotify(subtitleTextAlignmentKey, newValue.toString()); + set subtitleTextAlignment(TextAlign newValue) => _set(subtitleTextAlignmentKey, newValue.toString()); SubtitlePosition get subtitleTextPosition => getEnumOrDefault(subtitleTextPositionKey, SettingsDefaults.subtitleTextPosition, SubtitlePosition.values); - set subtitleTextPosition(SubtitlePosition newValue) => setAndNotify(subtitleTextPositionKey, newValue.toString()); + set subtitleTextPosition(SubtitlePosition newValue) => _set(subtitleTextPositionKey, newValue.toString()); bool get subtitleShowOutline => getBool(subtitleShowOutlineKey) ?? SettingsDefaults.subtitleShowOutline; - set subtitleShowOutline(bool newValue) => setAndNotify(subtitleShowOutlineKey, newValue); + set subtitleShowOutline(bool newValue) => _set(subtitleShowOutlineKey, newValue); Color get subtitleTextColor => Color(getInt(subtitleTextColorKey) ?? SettingsDefaults.subtitleTextColor.value); - set subtitleTextColor(Color newValue) => setAndNotify(subtitleTextColorKey, newValue.value); + set subtitleTextColor(Color newValue) => _set(subtitleTextColorKey, newValue.value); Color get subtitleBackgroundColor => Color(getInt(subtitleBackgroundColorKey) ?? SettingsDefaults.subtitleBackgroundColor.value); - set subtitleBackgroundColor(Color newValue) => setAndNotify(subtitleBackgroundColorKey, newValue.value); + set subtitleBackgroundColor(Color newValue) => _set(subtitleBackgroundColorKey, newValue.value); // info double get infoMapZoom => getDouble(infoMapZoomKey) ?? SettingsDefaults.infoMapZoom; - set infoMapZoom(double newValue) => setAndNotify(infoMapZoomKey, newValue); + set infoMapZoom(double newValue) => _set(infoMapZoomKey, newValue); CoordinateFormat get coordinateFormat => getEnumOrDefault(coordinateFormatKey, SettingsDefaults.coordinateFormat, CoordinateFormat.values); - set coordinateFormat(CoordinateFormat newValue) => setAndNotify(coordinateFormatKey, newValue.toString()); + set coordinateFormat(CoordinateFormat newValue) => _set(coordinateFormatKey, newValue.toString()); UnitSystem get unitSystem => getEnumOrDefault(unitSystemKey, SettingsDefaults.unitSystem, UnitSystem.values); - set unitSystem(UnitSystem newValue) => setAndNotify(unitSystemKey, newValue.toString()); + set unitSystem(UnitSystem newValue) => _set(unitSystemKey, newValue.toString()); // tag editor bool get tagEditorCurrentFilterSectionExpanded => getBool(tagEditorCurrentFilterSectionExpandedKey) ?? SettingsDefaults.tagEditorCurrentFilterSectionExpanded; - set tagEditorCurrentFilterSectionExpanded(bool newValue) => setAndNotify(tagEditorCurrentFilterSectionExpandedKey, newValue); + set tagEditorCurrentFilterSectionExpanded(bool newValue) => _set(tagEditorCurrentFilterSectionExpandedKey, newValue); // map @@ -699,106 +709,106 @@ class Settings extends ChangeNotifier { return available.contains(preferred) ? preferred : available.first; } - set mapStyle(EntryMapStyle? newValue) => setAndNotify(mapStyleKey, newValue?.toString()); + set mapStyle(EntryMapStyle? newValue) => _set(mapStyleKey, newValue?.toString()); LatLng? get mapDefaultCenter { final json = getString(mapDefaultCenterKey); return json != null ? LatLng.fromJson(jsonDecode(json)) : null; } - set mapDefaultCenter(LatLng? newValue) => setAndNotify(mapDefaultCenterKey, newValue != null ? jsonEncode(newValue.toJson()) : null); + set mapDefaultCenter(LatLng? newValue) => _set(mapDefaultCenterKey, newValue != null ? jsonEncode(newValue.toJson()) : null); // search bool get saveSearchHistory => getBool(saveSearchHistoryKey) ?? SettingsDefaults.saveSearchHistory; - set saveSearchHistory(bool newValue) => setAndNotify(saveSearchHistoryKey, newValue); + set saveSearchHistory(bool newValue) => _set(saveSearchHistoryKey, newValue); List get searchHistory => (getStringList(searchHistoryKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toList(); - set searchHistory(List newValue) => setAndNotify(searchHistoryKey, newValue.map((filter) => filter.toJson()).toList()); + set searchHistory(List newValue) => _set(searchHistoryKey, newValue.map((filter) => filter.toJson()).toList()); // bin bool get enableBin => getBool(enableBinKey) ?? SettingsDefaults.enableBin; - set enableBin(bool newValue) => setAndNotify(enableBinKey, newValue); + set enableBin(bool newValue) => _set(enableBinKey, newValue); // accessibility bool get showPinchGestureAlternatives => getBool(showPinchGestureAlternativesKey) ?? SettingsDefaults.showPinchGestureAlternatives; - set showPinchGestureAlternatives(bool newValue) => setAndNotify(showPinchGestureAlternativesKey, newValue); + set showPinchGestureAlternatives(bool newValue) => _set(showPinchGestureAlternativesKey, newValue); AccessibilityAnimations get accessibilityAnimations => getEnumOrDefault(accessibilityAnimationsKey, SettingsDefaults.accessibilityAnimations, AccessibilityAnimations.values); - set accessibilityAnimations(AccessibilityAnimations newValue) => setAndNotify(accessibilityAnimationsKey, newValue.toString()); + set accessibilityAnimations(AccessibilityAnimations newValue) => _set(accessibilityAnimationsKey, newValue.toString()); AccessibilityTimeout get timeToTakeAction => getEnumOrDefault(timeToTakeActionKey, SettingsDefaults.timeToTakeAction, AccessibilityTimeout.values); - set timeToTakeAction(AccessibilityTimeout newValue) => setAndNotify(timeToTakeActionKey, newValue.toString()); + set timeToTakeAction(AccessibilityTimeout newValue) => _set(timeToTakeActionKey, newValue.toString()); // file picker bool get filePickerShowHiddenFiles => getBool(filePickerShowHiddenFilesKey) ?? SettingsDefaults.filePickerShowHiddenFiles; - set filePickerShowHiddenFiles(bool newValue) => setAndNotify(filePickerShowHiddenFilesKey, newValue); + set filePickerShowHiddenFiles(bool newValue) => _set(filePickerShowHiddenFilesKey, newValue); // screen saver bool get screenSaverFillScreen => getBool(screenSaverFillScreenKey) ?? SettingsDefaults.slideshowFillScreen; - set screenSaverFillScreen(bool newValue) => setAndNotify(screenSaverFillScreenKey, newValue); + set screenSaverFillScreen(bool newValue) => _set(screenSaverFillScreenKey, newValue); bool get screenSaverAnimatedZoomEffect => getBool(screenSaverAnimatedZoomEffectKey) ?? SettingsDefaults.slideshowAnimatedZoomEffect; - set screenSaverAnimatedZoomEffect(bool newValue) => setAndNotify(screenSaverAnimatedZoomEffectKey, newValue); + set screenSaverAnimatedZoomEffect(bool newValue) => _set(screenSaverAnimatedZoomEffectKey, newValue); ViewerTransition get screenSaverTransition => getEnumOrDefault(screenSaverTransitionKey, SettingsDefaults.slideshowTransition, ViewerTransition.values); - set screenSaverTransition(ViewerTransition newValue) => setAndNotify(screenSaverTransitionKey, newValue.toString()); + set screenSaverTransition(ViewerTransition newValue) => _set(screenSaverTransitionKey, newValue.toString()); SlideshowVideoPlayback get screenSaverVideoPlayback => getEnumOrDefault(screenSaverVideoPlaybackKey, SettingsDefaults.slideshowVideoPlayback, SlideshowVideoPlayback.values); - set screenSaverVideoPlayback(SlideshowVideoPlayback newValue) => setAndNotify(screenSaverVideoPlaybackKey, newValue.toString()); + set screenSaverVideoPlayback(SlideshowVideoPlayback newValue) => _set(screenSaverVideoPlaybackKey, newValue.toString()); int get screenSaverInterval => getInt(screenSaverIntervalKey) ?? SettingsDefaults.slideshowInterval; - set screenSaverInterval(int newValue) => setAndNotify(screenSaverIntervalKey, newValue); + set screenSaverInterval(int newValue) => _set(screenSaverIntervalKey, newValue); Set get screenSaverCollectionFilters => (getStringList(screenSaverCollectionFiltersKey) ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet(); - set screenSaverCollectionFilters(Set newValue) => setAndNotify(screenSaverCollectionFiltersKey, newValue.map((filter) => filter.toJson()).toList()); + set screenSaverCollectionFilters(Set newValue) => _set(screenSaverCollectionFiltersKey, newValue.map((filter) => filter.toJson()).toList()); // slideshow bool get slideshowRepeat => getBool(slideshowRepeatKey) ?? SettingsDefaults.slideshowRepeat; - set slideshowRepeat(bool newValue) => setAndNotify(slideshowRepeatKey, newValue); + set slideshowRepeat(bool newValue) => _set(slideshowRepeatKey, newValue); bool get slideshowShuffle => getBool(slideshowShuffleKey) ?? SettingsDefaults.slideshowShuffle; - set slideshowShuffle(bool newValue) => setAndNotify(slideshowShuffleKey, newValue); + set slideshowShuffle(bool newValue) => _set(slideshowShuffleKey, newValue); bool get slideshowFillScreen => getBool(slideshowFillScreenKey) ?? SettingsDefaults.slideshowFillScreen; - set slideshowFillScreen(bool newValue) => setAndNotify(slideshowFillScreenKey, newValue); + set slideshowFillScreen(bool newValue) => _set(slideshowFillScreenKey, newValue); bool get slideshowAnimatedZoomEffect => getBool(slideshowAnimatedZoomEffectKey) ?? SettingsDefaults.slideshowAnimatedZoomEffect; - set slideshowAnimatedZoomEffect(bool newValue) => setAndNotify(slideshowAnimatedZoomEffectKey, newValue); + set slideshowAnimatedZoomEffect(bool newValue) => _set(slideshowAnimatedZoomEffectKey, newValue); ViewerTransition get slideshowTransition => getEnumOrDefault(slideshowTransitionKey, SettingsDefaults.slideshowTransition, ViewerTransition.values); - set slideshowTransition(ViewerTransition newValue) => setAndNotify(slideshowTransitionKey, newValue.toString()); + set slideshowTransition(ViewerTransition newValue) => _set(slideshowTransitionKey, newValue.toString()); SlideshowVideoPlayback get slideshowVideoPlayback => getEnumOrDefault(slideshowVideoPlaybackKey, SettingsDefaults.slideshowVideoPlayback, SlideshowVideoPlayback.values); - set slideshowVideoPlayback(SlideshowVideoPlayback newValue) => setAndNotify(slideshowVideoPlaybackKey, newValue.toString()); + set slideshowVideoPlayback(SlideshowVideoPlayback newValue) => _set(slideshowVideoPlaybackKey, newValue.toString()); int get slideshowInterval => getInt(slideshowIntervalKey) ?? SettingsDefaults.slideshowInterval; - set slideshowInterval(int newValue) => setAndNotify(slideshowIntervalKey, newValue); + set slideshowInterval(int newValue) => _set(slideshowIntervalKey, newValue); // widget @@ -807,27 +817,27 @@ class Settings extends ChangeNotifier { return value != null ? Color(value) : null; } - void setWidgetOutline(int widgetId, Color? newValue) => setAndNotify('$widgetOutlinePrefixKey$widgetId', newValue?.value); + void setWidgetOutline(int widgetId, Color? newValue) => _set('$widgetOutlinePrefixKey$widgetId', newValue?.value); WidgetShape getWidgetShape(int widgetId) => getEnumOrDefault('$widgetShapePrefixKey$widgetId', SettingsDefaults.widgetShape, WidgetShape.values); - void setWidgetShape(int widgetId, WidgetShape newValue) => setAndNotify('$widgetShapePrefixKey$widgetId', newValue.toString()); + void setWidgetShape(int widgetId, WidgetShape newValue) => _set('$widgetShapePrefixKey$widgetId', newValue.toString()); Set getWidgetCollectionFilters(int widgetId) => (getStringList('$widgetCollectionFiltersPrefixKey$widgetId') ?? []).map(CollectionFilter.fromJson).whereNotNull().toSet(); - void setWidgetCollectionFilters(int widgetId, Set newValue) => setAndNotify('$widgetCollectionFiltersPrefixKey$widgetId', newValue.map((filter) => filter.toJson()).toList()); + void setWidgetCollectionFilters(int widgetId, Set newValue) => _set('$widgetCollectionFiltersPrefixKey$widgetId', newValue.map((filter) => filter.toJson()).toList()); WidgetOpenPage getWidgetOpenPage(int widgetId) => getEnumOrDefault('$widgetOpenPagePrefixKey$widgetId', SettingsDefaults.widgetOpenPage, WidgetOpenPage.values); - void setWidgetOpenPage(int widgetId, WidgetOpenPage newValue) => setAndNotify('$widgetOpenPagePrefixKey$widgetId', newValue.toString()); + void setWidgetOpenPage(int widgetId, WidgetOpenPage newValue) => _set('$widgetOpenPagePrefixKey$widgetId', newValue.toString()); WidgetDisplayedItem getWidgetDisplayedItem(int widgetId) => getEnumOrDefault('$widgetDisplayedItemPrefixKey$widgetId', SettingsDefaults.widgetDisplayedItem, WidgetDisplayedItem.values); - void setWidgetDisplayedItem(int widgetId, WidgetDisplayedItem newValue) => setAndNotify('$widgetDisplayedItemPrefixKey$widgetId', newValue.toString()); + void setWidgetDisplayedItem(int widgetId, WidgetDisplayedItem newValue) => _set('$widgetDisplayedItemPrefixKey$widgetId', newValue.toString()); String? getWidgetUri(int widgetId) => getString('$widgetUriPrefixKey$widgetId'); - void setWidgetUri(int widgetId, String? newValue) => setAndNotify('$widgetUriPrefixKey$widgetId', newValue); + void setWidgetUri(int widgetId, String? newValue) => _set('$widgetUriPrefixKey$widgetId', newValue); // convenience methods @@ -894,7 +904,7 @@ class Settings extends ChangeNotifier { return settingsStore.getStringList(key)?.map((s) => values.firstWhereOrNull((v) => v.toString() == s)).whereNotNull().toList() ?? defaultValue; } - void setAndNotify(String key, dynamic newValue) { + void _set(String key, dynamic newValue) { var oldValue = settingsStore.get(key); if (newValue == null) { settingsStore.remove(key); @@ -940,11 +950,11 @@ class Settings extends ChangeNotifier { bool get isRotationLocked => getBool(platformAccelerometerRotationKey) ?? SettingsDefaults.isRotationLocked; - set isRotationLocked(bool newValue) => setAndNotify(platformAccelerometerRotationKey, newValue); + set isRotationLocked(bool newValue) => _set(platformAccelerometerRotationKey, newValue); bool get areAnimationsRemoved => getBool(platformTransitionAnimationScaleKey) ?? SettingsDefaults.areAnimationsRemoved; - set areAnimationsRemoved(bool newValue) => setAndNotify(platformTransitionAnimationScaleKey, newValue); + set areAnimationsRemoved(bool newValue) => _set(platformTransitionAnimationScaleKey, newValue); // import/export @@ -1103,6 +1113,7 @@ class Settings extends ChangeNotifier { _updateStreamController.add(SettingsChangedEvent(key, oldValue, newValue)); } }); + await sanitize(); notifyListeners(); } } diff --git a/lib/services/accessibility_service.dart b/lib/services/accessibility_service.dart index 61ac1bb34..42a9f81f0 100644 --- a/lib/services/accessibility_service.dart +++ b/lib/services/accessibility_service.dart @@ -1,4 +1,5 @@ import 'package:aves/services/common/services.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; class AccessibilityService { @@ -24,14 +25,17 @@ class AccessibilityService { return false; } + static bool? _hasRecommendedTimeouts; + static Future hasRecommendedTimeouts() async { + if (_hasRecommendedTimeouts != null) return SynchronousFuture(_hasRecommendedTimeouts!); try { final result = await _platform.invokeMethod('hasRecommendedTimeouts'); - if (result != null) return result as bool; + _hasRecommendedTimeouts = result as bool?; } on PlatformException catch (e, stack) { await reportService.recordError(e, stack); } - return false; + return _hasRecommendedTimeouts ?? false; } static Future getRecommendedTimeToRead(Duration originalTimeoutDuration) async { diff --git a/lib/services/window_service.dart b/lib/services/window_service.dart index f9da6493c..576b832b8 100644 --- a/lib/services/window_service.dart +++ b/lib/services/window_service.dart @@ -1,4 +1,5 @@ import 'package:aves/services/common/services.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -79,15 +80,18 @@ class PlatformWindowService implements WindowService { } } + bool? _isCutoutAware; + @override Future isCutoutAware() async { + if (_isCutoutAware != null) return SynchronousFuture(_isCutoutAware!); try { final result = await _platform.invokeMethod('isCutoutAware'); - if (result != null) return result as bool; + _isCutoutAware = result as bool?; } on PlatformException catch (e, stack) { await reportService.recordError(e, stack); } - return false; + return _isCutoutAware ?? false; } @override diff --git a/lib/utils/dependencies.dart b/lib/utils/dependencies.dart index 354e113d3..9bb4babd0 100644 --- a/lib/utils/dependencies.dart +++ b/lib/utils/dependencies.dart @@ -177,9 +177,9 @@ class Dependencies { static const List flutterPackages = [ Dependency( - name: 'Charts', + name: 'Charts (fzyzcjy fork)', license: apache2, - sourceUrl: 'https://github.com/google/charts', + sourceUrl: 'https://github.com/fzyzcjy/charts', ), Dependency( name: 'Custom rounded rectangle border', diff --git a/lib/widgets/stats/filter_table.dart b/lib/widgets/stats/filter_table.dart index d94020345..145d54c79 100644 --- a/lib/widgets/stats/filter_table.dart +++ b/lib/widgets/stats/filter_table.dart @@ -2,9 +2,9 @@ import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/settings/enums/accessibility_animations.dart'; import 'package:aves/model/settings/enums/enums.dart'; import 'package:aves/model/settings/settings.dart'; -import 'package:aves/utils/constants.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/aves_filter_chip.dart'; +import 'package:aves/widgets/stats/percent_text.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; @@ -36,7 +36,6 @@ class FilterTable extends StatelessWidget { Widget build(BuildContext context) { final locale = context.l10n.localeName; final numberFormat = NumberFormat.decimalPattern(locale); - final percentFormat = NumberFormat.percentPattern(); final animate = context.select((v) => v.accessibilityAnimations.animate); final sortedEntries = entryCountMap.entries.toList(); @@ -91,12 +90,7 @@ class FilterTable extends StatelessWidget { animation: animate, isRTL: isRtl, barRadius: barRadius, - center: Text( - percentFormat.format(percent), - style: TextStyle( - shadows: theme.brightness == Brightness.dark ? Constants.embossShadows : null, - ), - ), + center: LinearPercentIndicatorText(percent: percent), padding: EdgeInsets.symmetric(horizontal: lineHeight), ); }, diff --git a/lib/widgets/stats/percent_text.dart b/lib/widgets/stats/percent_text.dart new file mode 100644 index 000000000..44681e02e --- /dev/null +++ b/lib/widgets/stats/percent_text.dart @@ -0,0 +1,30 @@ +import 'package:aves/utils/constants.dart'; +import 'package:aves/widgets/common/basic/text/outlined.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class LinearPercentIndicatorText extends StatelessWidget { + final double percent; + final percentFormat = NumberFormat.percentPattern(); + + LinearPercentIndicatorText({ + super.key, + required this.percent, + }); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return OutlinedText( + textSpans: [ + TextSpan( + text: percentFormat.format(percent), + style: TextStyle( + shadows: theme.brightness == Brightness.dark ? Constants.embossShadows : null, + ), + ) + ], + outlineColor: theme.scaffoldBackgroundColor, + ); + } +} diff --git a/lib/widgets/stats/stats_page.dart b/lib/widgets/stats/stats_page.dart index 23a543e3e..1edaad08a 100644 --- a/lib/widgets/stats/stats_page.dart +++ b/lib/widgets/stats/stats_page.dart @@ -23,11 +23,11 @@ import 'package:aves/widgets/filter_grids/common/action_delegates/chip.dart'; import 'package:aves/widgets/stats/date/histogram.dart'; import 'package:aves/widgets/stats/filter_table.dart'; import 'package:aves/widgets/stats/mime_donut.dart'; +import 'package:aves/widgets/stats/percent_text.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; -import 'package:intl/intl.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:provider/provider.dart'; @@ -105,7 +105,6 @@ class _StatsPageState extends State { if (!animating) { final durations = context.watch(); - final percentFormat = NumberFormat.percentPattern(); if (entries.isEmpty) { child = EmptyContent( @@ -114,7 +113,6 @@ class _StatsPageState extends State { ); } else { final theme = Theme.of(context); - final isDark = theme.brightness == Brightness.dark; final chartAnimationDuration = context.read().chartTransition; final byMimeTypes = groupBy(entries, (entry) => entry.mimeType).map((k, v) => MapEntry(k, v.length)); @@ -163,12 +161,7 @@ class _StatsPageState extends State { animation: context.select((v) => v.accessibilityAnimations.animate), isRTL: context.isRtl, barRadius: barRadius, - center: Text( - percentFormat.format(withGpsPercent), - style: TextStyle( - shadows: isDark ? Constants.embossShadows : null, - ), - ), + center: LinearPercentIndicatorText(percent: withGpsPercent), padding: EdgeInsets.symmetric(horizontal: lineHeight), ), ), diff --git a/pubspec.lock b/pubspec.lock index 3d535da95..54c463a4a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -123,9 +123,11 @@ packages: charts_flutter: dependency: "direct main" description: - name: charts_flutter - url: "https://pub.dartlang.org" - source: hosted + path: charts_flutter + ref: master + resolved-ref: de76a46c1908b0c35aaf60823100fe9bfa26ae4d + url: "https://github.com/fzyzcjy/charts.git" + source: git version: "0.12.0" clock: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index b932f6506..7a7d9c12f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,10 @@ dependencies: aves_ui: path: plugins/aves_ui charts_flutter: + git: + url: https://github.com/fzyzcjy/charts.git + ref: master + path: charts_flutter collection: connectivity_plus: country_code: