load metadata/address on startup

This commit is contained in:
Thibault Deckers 2019-08-11 23:12:08 +09:00
parent 27bf3f4dad
commit 6206dbde62
6 changed files with 55 additions and 42 deletions

View file

@ -47,11 +47,14 @@ class _HomePageState extends State<HomePage> {
await metadataDb.init();
eventChannel.receiveBroadcastStream().cast<Map>().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<HomePage> {
);
}
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<CatalogMetadata>();
await Future.forEach<ImageEntry>(uncataloguedEntries, (entry) async {
await entry.catalog();
@ -82,7 +111,6 @@ class _HomePageState extends State<HomePage> {
// 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<HomePage> {
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');
}
}

View file

@ -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<double, double> get latLng => isCataloged ? Tuple2(catalogMetadata.latitude, catalogMetadata.longitude) : null;
Tuple2<double, double> get latLng => isCatalogued ? Tuple2(catalogMetadata.latitude, catalogMetadata.longitude) : null;
String get geoUri => hasGps ? 'geo:${catalogMetadata.latitude},${catalogMetadata.longitude}' : null;
List<String> get xmpSubjects => catalogMetadata?.xmpSubjects?.split(';')?.where((tag) => tag.isNotEmpty)?.toList() ?? [];
catalog() async {
if (isCataloged) return;
if (isCatalogued) return;
catalogMetadata = await MetadataService.getCatalogMetadata(this);
notifyListeners();
}

View file

@ -34,21 +34,13 @@ class MetadataDb {
await init();
}
Future<List<CatalogMetadata>> getAllMetadata() async {
debugPrint('$runtimeType getAllMetadata');
Future<List<CatalogMetadata>> 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<CatalogMetadata> getMetadata(int contentId) async {
debugPrint('$runtimeType getMetadata contentId=$contentId');
final db = await _database;
List<Map> 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<CatalogMetadata> metadataEntries) async {
@ -65,21 +57,13 @@ class MetadataDb {
debugPrint('$runtimeType saveMetadata complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${metadataEntries.length} entries');
}
Future<List<AddressDetails>> getAllAddresses() async {
debugPrint('$runtimeType getAllAddresses');
Future<List<AddressDetails>> 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<AddressDetails> getAddress(int contentId) async {
debugPrint('$runtimeType getAddress contentId=$contentId');
final db = await _database;
List<Map> 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<AddressDetails> addresses) async {

View file

@ -22,15 +22,15 @@ class DebugPageState extends State<DebugPage> {
@override
void initState() {
super.initState();
_dbMetadataLoader = metadataDb.getAllMetadata();
_dbAddressLoader = metadataDb.getAllAddresses();
_dbMetadataLoader = metadataDb.loadMetadataEntries();
_dbAddressLoader = metadataDb.loadAddresses();
}
@override
Widget build(BuildContext context) {
final Map<String, List<ImageEntry>> 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<DebugPage> {
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(),

View file

@ -41,6 +41,7 @@ class ImageMapState extends State<ImageMap> 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<ImageMap> with AutomaticKeepAliveClientMixin {
markers: [
Marker(
markerId: MarkerId(widget.markerId),
icon: BitmapDescriptor.defaultMarker,
icon: BitmapDescriptor.defaultMarkerWithHue(accentHue),
position: widget.latLng,
)
].toSet(),

View file

@ -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),
),
))