catalog & locate all entries on start
This commit is contained in:
parent
fac80d98b9
commit
21539b97bb
12 changed files with 113 additions and 60 deletions
|
@ -183,6 +183,8 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
|||
}
|
||||
}
|
||||
result.success(metadataMap);
|
||||
} catch (ImageProcessingException e) {
|
||||
result.error("getCatalogMetadata-imageprocessing", "failed to get metadata for path=" + path + " (" + e.getMessage() + ")", null);
|
||||
} catch (FileNotFoundException e) {
|
||||
result.error("getCatalogMetadata-filenotfound", "failed to get metadata for path=" + path + " (" + e.getMessage() + ")", null);
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:aves/model/image_decode_service.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/common/fake_app_bar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -50,6 +50,7 @@ class _HomePageState extends State<HomePage> {
|
|||
onDone: () {
|
||||
debugPrint('mediastore stream done');
|
||||
setState(() {});
|
||||
catalogEntries();
|
||||
},
|
||||
onError: (error) => debugPrint('mediastore stream error=$error'),
|
||||
);
|
||||
|
@ -65,4 +66,22 @@ class _HomePageState extends State<HomePage> {
|
|||
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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}';
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ class ImageDecodeService {
|
|||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
final result = await platform.invokeMethod('getImageBytes', <String, dynamic>{
|
||||
|
|
|
@ -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:flutter/material.dart';
|
||||
import 'package:geocoder/geocoder.dart';
|
||||
|
|
67
lib/model/image_metadata.dart
Normal file
67
lib/model/image_metadata.dart
Normal 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}';
|
||||
}
|
||||
}
|
|
@ -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:path/path.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
@ -52,7 +52,7 @@ class MetadataDb {
|
|||
}
|
||||
|
||||
insert(CatalogMetadata metadata) async {
|
||||
debugPrint('$runtimeType insert metadata=$metadata');
|
||||
// debugPrint('$runtimeType insert metadata=$metadata');
|
||||
final db = await _database;
|
||||
await db.insert(
|
||||
table,
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/catalog_metadata.dart';
|
||||
import 'package:aves/model/metadata_storage_service.dart';
|
||||
import 'package:aves/model/image_metadata.dart';
|
||||
import 'package:aves/model/metadata_db.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
|
@ -40,16 +40,16 @@ class MetadataService {
|
|||
return null;
|
||||
}
|
||||
|
||||
// return map with string descriptions for: 'aperture' 'exposureTime' 'focalLength' 'iso'
|
||||
static Future<Map> getOverlayMetadata(String path) async {
|
||||
static Future<OverlayMetadata> getOverlayMetadata(String path) async {
|
||||
try {
|
||||
// return map with string descriptions for: 'aperture' 'exposureTime' 'focalLength' 'iso'
|
||||
final result = await platform.invokeMethod('getOverlayMetadata', <String, dynamic>{
|
||||
'path': path,
|
||||
});
|
||||
return result as Map;
|
||||
}) as Map;
|
||||
return OverlayMetadata.fromMap(result);
|
||||
} on PlatformException catch (e) {
|
||||
debugPrint('getOverlayMetadata failed with exception=${e.message}');
|
||||
}
|
||||
return Map();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/catalog_metadata.dart';
|
||||
import 'package:aves/model/metadata_storage_service.dart';
|
||||
import 'package:aves/model/image_metadata.dart';
|
||||
import 'package:aves/model/metadata_db.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DebugPage extends StatefulWidget {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/android_app_service.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/overlay_bottom.dart';
|
||||
import 'package:aves/widgets/fullscreen/overlay_top.dart';
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:math';
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:aves/model/image_entry.dart';
|
||||
import 'package:aves/model/image_metadata.dart';
|
||||
import 'package:aves/model/metadata_service.dart';
|
||||
import 'package:aves/widgets/common/blurred.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -25,9 +26,9 @@ class FullscreenBottomOverlay extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _FullscreenBottomOverlayState extends State<FullscreenBottomOverlay> {
|
||||
Future<Map> _detailLoader;
|
||||
Future<OverlayMetadata> _detailLoader;
|
||||
ImageEntry _lastEntry;
|
||||
Map _lastDetails;
|
||||
OverlayMetadata _lastDetails;
|
||||
|
||||
ImageEntry get entry => widget.entries[widget.index];
|
||||
|
||||
|
@ -63,7 +64,7 @@ class _FullscreenBottomOverlayState extends State<FullscreenBottomOverlay> {
|
|||
padding: innerPadding,
|
||||
child: FutureBuilder(
|
||||
future: _detailLoader,
|
||||
builder: (futureContext, AsyncSnapshot<Map> snapshot) {
|
||||
builder: (futureContext, AsyncSnapshot<OverlayMetadata> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) {
|
||||
_lastDetails = snapshot.data;
|
||||
_lastEntry = entry;
|
||||
|
@ -87,7 +88,7 @@ class _FullscreenBottomOverlayState extends State<FullscreenBottomOverlay> {
|
|||
|
||||
class _FullscreenBottomOverlayContent extends StatelessWidget {
|
||||
final ImageEntry entry;
|
||||
final Map details;
|
||||
final OverlayMetadata details;
|
||||
final String position;
|
||||
final double maxWidth;
|
||||
|
||||
|
@ -129,7 +130,7 @@ class _FullscreenBottomOverlayContent extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
if (details != null && details.isNotEmpty) ...[
|
||||
if (details != null) ...[
|
||||
SizedBox(height: 4),
|
||||
SizedBox(
|
||||
width: subRowWidth,
|
||||
|
@ -137,10 +138,10 @@ class _FullscreenBottomOverlayContent extends StatelessWidget {
|
|||
children: [
|
||||
Icon(Icons.camera, size: 16),
|
||||
SizedBox(width: 8),
|
||||
Expanded(child: Text((details['aperture'] as String).replaceAll('f', 'ƒ'))),
|
||||
Expanded(child: Text(details['exposureTime'])),
|
||||
Expanded(child: Text(details['focalLength'])),
|
||||
Expanded(child: Text(details['iso'])),
|
||||
Expanded(child: Text(details.aperture)),
|
||||
Expanded(child: Text(details.exposureTime)),
|
||||
Expanded(child: Text(details.focalLength)),
|
||||
Expanded(child: Text(details.iso)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue