diff --git a/lib/model/metadata_db.dart b/lib/model/metadata_db.dart index 4fb1f07a8..fb26c0b78 100644 --- a/lib/model/metadata_db.dart +++ b/lib/model/metadata_db.dart @@ -98,7 +98,6 @@ class SqfliteMetadataDb implements MetadataDb { @override Future init() async { - debugPrint('$runtimeType init'); _database = openDatabase( await path, onCreate: (db, version) async { diff --git a/lib/model/source/collection_source.dart b/lib/model/source/collection_source.dart index a08d56cad..6fa4a30d7 100644 --- a/lib/model/source/collection_source.dart +++ b/lib/model/source/collection_source.dart @@ -70,9 +70,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM late Map _savedDates; Future loadDates() async { - final stopwatch = Stopwatch()..start(); _savedDates = Map.unmodifiable(await metadataDb.loadDates()); - debugPrint('$runtimeType loadDates complete in ${stopwatch.elapsed.inMilliseconds}ms for ${_savedDates.length} entries'); } Iterable _applyHiddenFilters(Iterable entries) { diff --git a/lib/model/source/media_store_source.dart b/lib/model/source/media_store_source.dart index 13e1d3955..d238846ab 100644 --- a/lib/model/source/media_store_source.dart +++ b/lib/model/source/media_store_source.dart @@ -38,7 +38,7 @@ class MediaStoreSource extends CollectionSource { } await loadDates(); _initialized = true; - debugPrint('$runtimeType init done, elapsed=${stopwatch.elapsed}'); + debugPrint('$runtimeType init complete in ${stopwatch.elapsed.inMilliseconds}ms'); } @override diff --git a/lib/utils/android_file_utils.dart b/lib/utils/android_file_utils.dart index 7132003f7..2e623d598 100644 --- a/lib/utils/android_file_utils.dart +++ b/lib/utils/android_file_utils.dart @@ -1,5 +1,4 @@ import 'package:aves/services/common/services.dart'; -import 'package:aves/utils/change_notifier.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:collection/collection.dart'; import 'package:equatable/equatable.dart'; @@ -15,7 +14,7 @@ class AndroidFileUtils { List _potentialAppDirs = []; bool _initialized = false; - AChangeNotifier appNameChangeNotifier = AChangeNotifier(); + ValueNotifier areAppNamesReadyNotifier = ValueNotifier(false); Iterable get _launcherPackages => _packages.where((package) => package.categoryLauncher); @@ -35,15 +34,15 @@ class AndroidFileUtils { // from Aves videoCapturesPath = pContext.join(dcimPath, 'Video Captures'); - // include package fetching in initialization - // to avoid app album color flickering + _initialized = true; + } + + Future initAppNames() async { if (_packages.isEmpty) { _packages = await androidAppService.getPackages(); _potentialAppDirs = _launcherPackages.expand((package) => package.potentialDirs).toList(); - appNameChangeNotifier.notifyListeners(); + areAppNamesReadyNotifier.value = true; } - - _initialized = true; } bool isCameraPath(String path) => path.startsWith(dcimPath) && (path.endsWith('${separator}Camera') || path.endsWith('${separator}100ANDRO')); diff --git a/lib/widgets/filter_grids/albums_page.dart b/lib/widgets/filter_grids/albums_page.dart index 28eee742d..4e798ed86 100644 --- a/lib/widgets/filter_grids/albums_page.dart +++ b/lib/widgets/filter_grids/albums_page.dart @@ -32,9 +32,9 @@ class AlbumListPage extends StatelessWidget { return !(eq.equals(t1.item1, t2.item1) && eq.equals(t1.item2, t2.item2) && eq.equals(t1.item3, t2.item3)); }, builder: (context, s, child) { - return AnimatedBuilder( - animation: androidFileUtils.appNameChangeNotifier, - builder: (context, child) => StreamBuilder( + return ValueListenableBuilder( + valueListenable: androidFileUtils.areAppNamesReadyNotifier, + builder: (context, areAppNamesReady, child) => StreamBuilder( stream: source.eventBus.on(), builder: (context, snapshot) { final gridItems = getAlbumGridItems(context, source); diff --git a/lib/widgets/filter_grids/common/covered_filter_chip.dart b/lib/widgets/filter_grids/common/covered_filter_chip.dart index 74d057f81..dc1375a7a 100644 --- a/lib/widgets/filter_grids/common/covered_filter_chip.dart +++ b/lib/widgets/filter_grids/common/covered_filter_chip.dart @@ -96,7 +96,14 @@ class CoveredFilterChip extends StatelessWidget { Widget _buildChip(BuildContext context, CollectionSource source) { final entry = coverEntry ?? source.coverEntry(filter); final titlePadding = min(4.0, extent / 32); + Key? chipKey; + if (filter is AlbumFilter) { + // when we asynchronously fetch installed app names, + // album filters themselves do not change, but decoration derived from it does + chipKey = ValueKey(androidFileUtils.areAppNamesReadyNotifier.value); + } return AvesFilterChip( + key: chipKey, filter: filter, showGenericIcon: false, decoration: AvesFilterDecoration( diff --git a/lib/widgets/home_page.dart b/lib/widgets/home_page.dart index af3a0ebaf..da2ffab34 100644 --- a/lib/widgets/home_page.dart +++ b/lib/widgets/home_page.dart @@ -55,6 +55,7 @@ class _HomePageState extends State { Widget build(BuildContext context) => const Scaffold(); Future _setup() async { + final stopwatch = Stopwatch()..start(); final permissions = await [ Permission.storage, // to access media with unredacted metadata with scoped storage (Android 10+) @@ -66,6 +67,7 @@ class _HomePageState extends State { } await androidFileUtils.init(); + unawaited(androidFileUtils.initAppNames()); var appMode = AppMode.main; final intentData = widget.intentData ?? await ViewerService.getIntentData(); @@ -107,6 +109,7 @@ class _HomePageState extends State { unawaited(reportService.setCustomKey('app_mode', appMode.toString())); if (appMode != AppMode.view) { + debugPrint('Storage check complete in ${stopwatch.elapsed.inMilliseconds}ms'); final source = context.read(); await source.init(); unawaited(source.refresh());