catalog & locate all entries on start

This commit is contained in:
Thibault Deckers 2019-08-11 00:23:08 +09:00
parent fac80d98b9
commit 21539b97bb
12 changed files with 113 additions and 60 deletions

View file

@ -183,6 +183,8 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
} }
} }
result.success(metadataMap); result.success(metadataMap);
} catch (ImageProcessingException e) {
result.error("getCatalogMetadata-imageprocessing", "failed to get metadata for path=" + path + " (" + e.getMessage() + ")", null);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
result.error("getCatalogMetadata-filenotfound", "failed to get metadata for path=" + path + " (" + e.getMessage() + ")", null); result.error("getCatalogMetadata-filenotfound", "failed to get metadata for path=" + path + " (" + e.getMessage() + ")", null);
} catch (Exception e) { } catch (Exception e) {

View file

@ -1,6 +1,6 @@
import 'package:aves/model/image_decode_service.dart'; import 'package:aves/model/image_decode_service.dart';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/model/metadata_storage_service.dart'; import 'package:aves/model/metadata_db.dart';
import 'package:aves/widgets/album/all_collection_page.dart'; import 'package:aves/widgets/album/all_collection_page.dart';
import 'package:aves/widgets/common/fake_app_bar.dart'; import 'package:aves/widgets/common/fake_app_bar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -50,6 +50,7 @@ class _HomePageState extends State<HomePage> {
onDone: () { onDone: () {
debugPrint('mediastore stream done'); debugPrint('mediastore stream done');
setState(() {}); setState(() {});
catalogEntries();
}, },
onError: (error) => debugPrint('mediastore stream error=$error'), onError: (error) => debugPrint('mediastore stream error=$error'),
); );
@ -65,4 +66,22 @@ class _HomePageState extends State<HomePage> {
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
); );
} }
catalogEntries() async {
debugPrint('$runtimeType catalogEntries cataloging start');
await Future.forEach<ImageEntry>(entries, (entry) async {
await entry.catalog();
});
debugPrint('$runtimeType catalogEntries cataloging complete');
// sort with more accurate date
entries.sort((a,b) => b.bestDate.compareTo(a.bestDate));
setState(() {});
debugPrint('$runtimeType catalogEntries locating start');
await Future.forEach<ImageEntry>(entries, (entry) async {
await entry.locate();
});
debugPrint('$runtimeType catalogEntries locating done');
}
} }

View file

@ -1,36 +0,0 @@
import 'package:geocoder/model.dart';
class CatalogMetadata {
final int contentId, dateMillis;
final String xmpSubjects;
final double latitude, longitude;
Address address;
CatalogMetadata({this.contentId, this.dateMillis, this.xmpSubjects, double latitude, double longitude})
// Geocoder throws an IllegalArgumentException when a coordinate has a funky values like 1.7056881853375E7
: this.latitude = latitude == null || latitude < -90.0 || latitude > 90.0 ? null : latitude,
this.longitude = longitude == null || longitude < -180.0 || longitude > 180.0 ? null : longitude;
factory CatalogMetadata.fromMap(Map map) {
return CatalogMetadata(
contentId: map['contentId'],
dateMillis: map['dateMillis'],
xmpSubjects: map['xmpSubjects'],
latitude: map['latitude'],
longitude: map['longitude'],
);
}
Map<String, dynamic> toMap() => {
'contentId': contentId,
'dateMillis': dateMillis,
'xmpSubjects': xmpSubjects,
'latitude': latitude,
'longitude': longitude,
};
@override
String toString() {
return 'CatalogMetadata{contentId=$contentId, dateMillis=$dateMillis, latitude=$latitude, longitude=$longitude, xmpSubjects=$xmpSubjects}';
}
}

View file

@ -16,7 +16,7 @@ class ImageDecodeService {
} }
static Future<Uint8List> getImageBytes(ImageEntry entry, int width, int height) async { static Future<Uint8List> getImageBytes(ImageEntry entry, int width, int height) async {
debugPrint('getImageBytes with path=${entry.path} contentId=${entry.contentId}'); // debugPrint('getImageBytes with path=${entry.path} contentId=${entry.contentId}');
if (width > 0 && height > 0) { if (width > 0 && height > 0) {
try { try {
final result = await platform.invokeMethod('getImageBytes', <String, dynamic>{ final result = await platform.invokeMethod('getImageBytes', <String, dynamic>{

View file

@ -1,4 +1,4 @@
import 'package:aves/model/catalog_metadata.dart'; import 'package:aves/model/image_metadata.dart';
import 'package:aves/model/metadata_service.dart'; import 'package:aves/model/metadata_service.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:geocoder/geocoder.dart'; import 'package:geocoder/geocoder.dart';

View file

@ -0,0 +1,67 @@
import 'package:geocoder/model.dart';
class CatalogMetadata {
final int contentId, dateMillis;
final String xmpSubjects;
final double latitude, longitude;
Address address;
CatalogMetadata({
this.contentId,
this.dateMillis,
this.xmpSubjects,
double latitude,
double longitude,
})
// Geocoder throws an IllegalArgumentException when a coordinate has a funky values like 1.7056881853375E7
: this.latitude = latitude == null || latitude < -90.0 || latitude > 90.0 ? null : latitude,
this.longitude = longitude == null || longitude < -180.0 || longitude > 180.0 ? null : longitude;
factory CatalogMetadata.fromMap(Map map) {
return CatalogMetadata(
contentId: map['contentId'],
dateMillis: map['dateMillis'],
xmpSubjects: map['xmpSubjects'],
latitude: map['latitude'],
longitude: map['longitude'],
);
}
Map<String, dynamic> toMap() => {
'contentId': contentId,
'dateMillis': dateMillis,
'xmpSubjects': xmpSubjects,
'latitude': latitude,
'longitude': longitude,
};
@override
String toString() {
return 'CatalogMetadata{contentId=$contentId, dateMillis=$dateMillis, latitude=$latitude, longitude=$longitude, xmpSubjects=$xmpSubjects}';
}
}
class OverlayMetadata {
final String aperture, exposureTime, focalLength, iso;
OverlayMetadata({
String aperture,
this.exposureTime,
this.focalLength,
this.iso,
}) : this.aperture = aperture.replaceFirst('f', 'ƒ');
factory OverlayMetadata.fromMap(Map map) {
return OverlayMetadata(
aperture: map['aperture'],
exposureTime: map['exposureTime'],
focalLength: map['focalLength'],
iso: map['iso'],
);
}
@override
String toString() {
return 'OverlayMetadata{aperture=$aperture, exposureTime=$exposureTime, focalLength=$focalLength, iso=$iso}';
}
}

View file

@ -1,4 +1,4 @@
import 'package:aves/model/catalog_metadata.dart'; import 'package:aves/model/image_metadata.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:path/path.dart'; import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart'; import 'package:sqflite/sqflite.dart';
@ -52,7 +52,7 @@ class MetadataDb {
} }
insert(CatalogMetadata metadata) async { insert(CatalogMetadata metadata) async {
debugPrint('$runtimeType insert metadata=$metadata'); // debugPrint('$runtimeType insert metadata=$metadata');
final db = await _database; final db = await _database;
await db.insert( await db.insert(
table, table,

View file

@ -1,5 +1,5 @@
import 'package:aves/model/catalog_metadata.dart'; import 'package:aves/model/image_metadata.dart';
import 'package:aves/model/metadata_storage_service.dart'; import 'package:aves/model/metadata_db.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -40,16 +40,16 @@ class MetadataService {
return null; return null;
} }
// return map with string descriptions for: 'aperture' 'exposureTime' 'focalLength' 'iso' static Future<OverlayMetadata> getOverlayMetadata(String path) async {
static Future<Map> getOverlayMetadata(String path) async {
try { try {
// return map with string descriptions for: 'aperture' 'exposureTime' 'focalLength' 'iso'
final result = await platform.invokeMethod('getOverlayMetadata', <String, dynamic>{ final result = await platform.invokeMethod('getOverlayMetadata', <String, dynamic>{
'path': path, 'path': path,
}); }) as Map;
return result as Map; return OverlayMetadata.fromMap(result);
} on PlatformException catch (e) { } on PlatformException catch (e) {
debugPrint('getOverlayMetadata failed with exception=${e.message}'); debugPrint('getOverlayMetadata failed with exception=${e.message}');
} }
return Map(); return null;
} }
} }

View file

@ -1,5 +1,5 @@
import 'package:aves/model/catalog_metadata.dart'; import 'package:aves/model/image_metadata.dart';
import 'package:aves/model/metadata_storage_service.dart'; import 'package:aves/model/metadata_db.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class DebugPage extends StatefulWidget { class DebugPage extends StatefulWidget {

View file

@ -1,8 +1,8 @@
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:aves/model/android_app_service.dart';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/utils/android_app_service.dart';
import 'package:aves/widgets/fullscreen/info/info_page.dart'; import 'package:aves/widgets/fullscreen/info/info_page.dart';
import 'package:aves/widgets/fullscreen/overlay_bottom.dart'; import 'package:aves/widgets/fullscreen/overlay_bottom.dart';
import 'package:aves/widgets/fullscreen/overlay_top.dart'; import 'package:aves/widgets/fullscreen/overlay_top.dart';

View file

@ -2,6 +2,7 @@ import 'dart:math';
import 'dart:ui'; import 'dart:ui';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/model/image_metadata.dart';
import 'package:aves/model/metadata_service.dart'; import 'package:aves/model/metadata_service.dart';
import 'package:aves/widgets/common/blurred.dart'; import 'package:aves/widgets/common/blurred.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -25,9 +26,9 @@ class FullscreenBottomOverlay extends StatefulWidget {
} }
class _FullscreenBottomOverlayState extends State<FullscreenBottomOverlay> { class _FullscreenBottomOverlayState extends State<FullscreenBottomOverlay> {
Future<Map> _detailLoader; Future<OverlayMetadata> _detailLoader;
ImageEntry _lastEntry; ImageEntry _lastEntry;
Map _lastDetails; OverlayMetadata _lastDetails;
ImageEntry get entry => widget.entries[widget.index]; ImageEntry get entry => widget.entries[widget.index];
@ -63,7 +64,7 @@ class _FullscreenBottomOverlayState extends State<FullscreenBottomOverlay> {
padding: innerPadding, padding: innerPadding,
child: FutureBuilder( child: FutureBuilder(
future: _detailLoader, future: _detailLoader,
builder: (futureContext, AsyncSnapshot<Map> snapshot) { builder: (futureContext, AsyncSnapshot<OverlayMetadata> snapshot) {
if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) { if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) {
_lastDetails = snapshot.data; _lastDetails = snapshot.data;
_lastEntry = entry; _lastEntry = entry;
@ -87,7 +88,7 @@ class _FullscreenBottomOverlayState extends State<FullscreenBottomOverlay> {
class _FullscreenBottomOverlayContent extends StatelessWidget { class _FullscreenBottomOverlayContent extends StatelessWidget {
final ImageEntry entry; final ImageEntry entry;
final Map details; final OverlayMetadata details;
final String position; final String position;
final double maxWidth; final double maxWidth;
@ -129,7 +130,7 @@ class _FullscreenBottomOverlayContent extends StatelessWidget {
], ],
), ),
), ),
if (details != null && details.isNotEmpty) ...[ if (details != null) ...[
SizedBox(height: 4), SizedBox(height: 4),
SizedBox( SizedBox(
width: subRowWidth, width: subRowWidth,
@ -137,10 +138,10 @@ class _FullscreenBottomOverlayContent extends StatelessWidget {
children: [ children: [
Icon(Icons.camera, size: 16), Icon(Icons.camera, size: 16),
SizedBox(width: 8), SizedBox(width: 8),
Expanded(child: Text((details['aperture'] as String).replaceAll('f', 'ƒ'))), Expanded(child: Text(details.aperture)),
Expanded(child: Text(details['exposureTime'])), Expanded(child: Text(details.exposureTime)),
Expanded(child: Text(details['focalLength'])), Expanded(child: Text(details.focalLength)),
Expanded(child: Text(details['iso'])), Expanded(child: Text(details.iso)),
], ],
), ),
), ),