diff --git a/lib/main.dart b/lib/main.dart index c9fbe9537..d53214c9f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -47,11 +47,14 @@ class _HomePageState extends State { await metadataDb.init(); eventChannel.receiveBroadcastStream().cast().listen( - (entryMap) => setState(() => entries.add(ImageEntry.fromMap(entryMap))), + (entryMap) => entries.add(ImageEntry.fromMap(entryMap)), onDone: () async { debugPrint('mediastore stream done'); + await loadCatalogMetadata(); setState(() {}); await catalogEntries(); + setState(() {}); + await loadAddresses(); await locateEntries(); }, onError: (error) => debugPrint('mediastore stream error=$error'), @@ -69,10 +72,36 @@ class _HomePageState extends State { ); } + loadCatalogMetadata() async { + debugPrint('$runtimeType loadCatalogMetadata start'); + final start = DateTime.now(); + final saved = await metadataDb.loadMetadataEntries(); + entries.forEach((entry) { + final contentId = entry.contentId; + if (contentId != null) { + entry.catalogMetadata = saved.firstWhere((metadata) => metadata.contentId == contentId, orElse: () => null); + } + }); + debugPrint('$runtimeType loadCatalogMetadata complete in ${DateTime.now().difference(start).inSeconds}s with ${saved.length} saved entries'); + } + + loadAddresses() async { + debugPrint('$runtimeType loadAddresses start'); + final start = DateTime.now(); + final saved = await metadataDb.loadAddresses(); + entries.forEach((entry) { + final contentId = entry.contentId; + if (contentId != null) { + entry.addressDetails = saved.firstWhere((address) => address.contentId == contentId, orElse: () => null); + } + }); + debugPrint('$runtimeType loadAddresses complete in ${DateTime.now().difference(start).inSeconds}s with ${saved.length} saved entries'); + } + catalogEntries() async { debugPrint('$runtimeType catalogEntries start'); final start = DateTime.now(); - final uncataloguedEntries = entries.where((entry) => !entry.isCataloged); + final uncataloguedEntries = entries.where((entry) => !entry.isCatalogued); final newMetadata = List(); await Future.forEach(uncataloguedEntries, (entry) async { await entry.catalog(); @@ -82,7 +111,6 @@ class _HomePageState extends State { // sort with more accurate date entries.sort((a, b) => b.bestDate.compareTo(a.bestDate)); - setState(() {}); metadataDb.saveMetadata(List.unmodifiable(newMetadata)); } @@ -100,6 +128,6 @@ class _HomePageState extends State { newAddresses.clear(); } }); - debugPrint('$runtimeType locateEntries complete in ${DateTime.now().difference(start).inSeconds}s with ${newAddresses.length} new addresses'); + debugPrint('$runtimeType locateEntries complete in ${DateTime.now().difference(start).inSeconds}s'); } } diff --git a/lib/model/image_entry.dart b/lib/model/image_entry.dart index 6d19ed0dc..4d8804e67 100644 --- a/lib/model/image_entry.dart +++ b/lib/model/image_entry.dart @@ -86,11 +86,11 @@ class ImageEntry with ChangeNotifier { bool get isVideo => mimeType.startsWith(MimeTypes.MIME_VIDEO); - bool get isCataloged => catalogMetadata != null; + bool get isCatalogued => catalogMetadata != null; double get aspectRatio { if (width == 0 || height == 0) return 1; - if (isVideo && isCataloged) { + if (isVideo && isCatalogued) { if (catalogMetadata.videoRotation % 180 == 90) return height / width; } return width / height; @@ -125,18 +125,18 @@ class ImageEntry with ChangeNotifier { return '${d.inHours}:$twoDigitMinutes:$twoDigitSeconds'; } - bool get hasGps => isCataloged && catalogMetadata.latitude != null; + bool get hasGps => isCatalogued && catalogMetadata.latitude != null; bool get isLocated => addressDetails != null; - Tuple2 get latLng => isCataloged ? Tuple2(catalogMetadata.latitude, catalogMetadata.longitude) : null; + Tuple2 get latLng => isCatalogued ? Tuple2(catalogMetadata.latitude, catalogMetadata.longitude) : null; String get geoUri => hasGps ? 'geo:${catalogMetadata.latitude},${catalogMetadata.longitude}' : null; List get xmpSubjects => catalogMetadata?.xmpSubjects?.split(';')?.where((tag) => tag.isNotEmpty)?.toList() ?? []; catalog() async { - if (isCataloged) return; + if (isCatalogued) return; catalogMetadata = await MetadataService.getCatalogMetadata(this); notifyListeners(); } diff --git a/lib/model/metadata_db.dart b/lib/model/metadata_db.dart index 8faeee0f8..5dc3787e3 100644 --- a/lib/model/metadata_db.dart +++ b/lib/model/metadata_db.dart @@ -34,21 +34,13 @@ class MetadataDb { await init(); } - Future> getAllMetadata() async { - debugPrint('$runtimeType getAllMetadata'); + Future> loadMetadataEntries() async { + final start = DateTime.now(); final db = await _database; final maps = await db.query(metadataTable); - return maps.map((map) => CatalogMetadata.fromMap(map)).toList(); - } - - Future getMetadata(int contentId) async { - debugPrint('$runtimeType getMetadata contentId=$contentId'); - final db = await _database; - List maps = await db.query(metadataTable, where: 'contentId = ?', whereArgs: [contentId]); - if (maps.length > 0) { - return CatalogMetadata.fromMap(maps.first); - } - return null; + final metadataEntries = maps.map((map) => CatalogMetadata.fromMap(map)).toList(); + debugPrint('$runtimeType loadMetadataEntries complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${metadataEntries.length} entries'); + return metadataEntries; } saveMetadata(Iterable metadataEntries) async { @@ -65,21 +57,13 @@ class MetadataDb { debugPrint('$runtimeType saveMetadata complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${metadataEntries.length} entries'); } - Future> getAllAddresses() async { - debugPrint('$runtimeType getAllAddresses'); + Future> loadAddresses() async { + final start = DateTime.now(); final db = await _database; final maps = await db.query(addressTable); - return maps.map((map) => AddressDetails.fromMap(map)).toList(); - } - - Future getAddress(int contentId) async { - debugPrint('$runtimeType getAddress contentId=$contentId'); - final db = await _database; - List maps = await db.query(addressTable, where: 'contentId = ?', whereArgs: [contentId]); - if (maps.length > 0) { - return AddressDetails.fromMap(maps.first); - } - return null; + final addresses = maps.map((map) => AddressDetails.fromMap(map)).toList(); + debugPrint('$runtimeType loadAddresses complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${addresses.length} entries'); + return addresses; } saveAddresses(Iterable addresses) async { diff --git a/lib/widgets/debug_page.dart b/lib/widgets/debug_page.dart index 5968ca0dd..75eaa8382 100644 --- a/lib/widgets/debug_page.dart +++ b/lib/widgets/debug_page.dart @@ -22,15 +22,15 @@ class DebugPageState extends State { @override void initState() { super.initState(); - _dbMetadataLoader = metadataDb.getAllMetadata(); - _dbAddressLoader = metadataDb.getAllAddresses(); + _dbMetadataLoader = metadataDb.loadMetadataEntries(); + _dbAddressLoader = metadataDb.loadAddresses(); } @override Widget build(BuildContext context) { final Map> byMimeTypes = groupBy(entries, (entry) => entry.mimeType); - final cataloged = entries.where((entry) => entry.isCataloged); - final withGps = cataloged.where((entry) => entry.hasGps); + final catalogued = entries.where((entry) => entry.isCatalogued); + final withGps = catalogued.where((entry) => entry.hasGps); final located = withGps.where((entry) => entry.isLocated); return Scaffold( appBar: AppBar( @@ -41,7 +41,7 @@ class DebugPageState extends State { children: [ Text('Entries: ${entries.length}'), ...byMimeTypes.keys.map((mimeType) => Text('- $mimeType: ${byMimeTypes[mimeType].length}')), - Text('Cataloged: ${cataloged.length}'), + Text('Catalogued: ${catalogued.length}'), Text('With GPS: ${withGps.length}'), Text('With address: ${located.length}'), Divider(), diff --git a/lib/widgets/fullscreen/info/location_section.dart b/lib/widgets/fullscreen/info/location_section.dart index 09f738e7f..a613c8a72 100644 --- a/lib/widgets/fullscreen/info/location_section.dart +++ b/lib/widgets/fullscreen/info/location_section.dart @@ -41,6 +41,7 @@ class ImageMapState extends State with AutomaticKeepAliveClientMixin { @override Widget build(BuildContext context) { super.build(context); + final accentHue = HSVColor.fromColor(Theme.of(context).accentColor).hue; return SizedBox( height: 200, child: ClipRRect( @@ -55,7 +56,7 @@ class ImageMapState extends State with AutomaticKeepAliveClientMixin { markers: [ Marker( markerId: MarkerId(widget.markerId), - icon: BitmapDescriptor.defaultMarker, + icon: BitmapDescriptor.defaultMarkerWithHue(accentHue), position: widget.latLng, ) ].toSet(), diff --git a/lib/widgets/fullscreen/info/xmp_section.dart b/lib/widgets/fullscreen/info/xmp_section.dart index 5c10d6961..a1523f973 100644 --- a/lib/widgets/fullscreen/info/xmp_section.dart +++ b/lib/widgets/fullscreen/info/xmp_section.dart @@ -21,7 +21,7 @@ class XmpTagSection extends AnimatedWidget { .map((tag) => Padding( padding: EdgeInsets.symmetric(horizontal: 4.0), child: Chip( - backgroundColor: Colors.indigo, + backgroundColor: Theme.of(context).accentColor, label: Text(tag), ), ))