Show MapView if GPS data exists in exif

This commit is contained in:
Ming Ming 2021-04-10 23:21:34 +08:00
parent 4a8784f508
commit d7269a1cba
6 changed files with 119 additions and 0 deletions

View file

@ -46,5 +46,9 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="" />
</application> </application>
</manifest> </manifest>

View file

@ -89,6 +89,12 @@ class Exif {
/// 0x920a FocalLength /// 0x920a FocalLength
Rational get focalLength => data["FocalLength"]; Rational get focalLength => data["FocalLength"];
/// 0x8825 GPS tags
String get gpsLatitudeRef => data["GPSLatitudeRef"];
List<Rational> get gpsLatitude => data["GPSLatitude"].cast<Rational>();
String get gpsLongitudeRef => data["GPSLongitudeRef"];
List<Rational> get gpsLongitude => data["GPSLongitude"].cast<Rational>();
static final dateTimeFormat = DateFormat("yyyy:MM:dd HH:mm:ss"); static final dateTimeFormat = DateFormat("yyyy:MM:dd HH:mm:ss");
final Map<String, dynamic> data; final Map<String, dynamic> data;

View file

@ -0,0 +1,3 @@
import 'dart:io';
final isSupportMapView = Platform.isAndroid;

View file

@ -1,9 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'package:android_intent/android_intent.dart';
import 'package:exifdart/exifdart.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
@ -13,6 +16,7 @@ import 'package:nc_photos/entity/exif.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/platform/features.dart' as features;
import 'package:nc_photos/snack_bar_manager.dart'; import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart'; import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/remove.dart'; import 'package:nc_photos/use_case/remove.dart';
@ -135,6 +139,36 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
title: Text(_model), title: Text(_model),
subtitle: cameraSubStr.isNotEmpty ? Text(cameraSubStr) : null, subtitle: cameraSubStr.isNotEmpty ? Text(cameraSubStr) : null,
), ),
if (features.isSupportMapView && _gps != null)
SizedBox(
height: 256,
child: GoogleMap(
compassEnabled: false,
mapToolbarEnabled: false,
rotateGesturesEnabled: false,
scrollGesturesEnabled: false,
zoomControlsEnabled: false,
zoomGesturesEnabled: false,
tiltGesturesEnabled: false,
myLocationButtonEnabled: false,
buildingsEnabled: false,
// liteModeEnabled: true,
initialCameraPosition: CameraPosition(
target: _gps,
zoom: 16,
),
markers: {
Marker(
markerId: MarkerId("at"),
position: _gps,
// for some reason, GoogleMap's onTap is not triggered if
// tapped on top of the marker
onTap: _onMapTap,
),
},
onTap: (_) => _onMapTap(),
),
),
], ],
); );
} }
@ -207,6 +241,16 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
} }
} }
void _onMapTap() {
if (Platform.isAndroid) {
final intent = AndroidIntent(
action: "action_view",
data: Uri.encodeFull("geo:${_gps.latitude},${_gps.longitude}?z=16"),
);
intent.launch();
}
}
void _updateMetadata(int imageWidth, int imageHeight, Exif exif) { void _updateMetadata(int imageWidth, int imageHeight, Exif exif) {
if (imageWidth != null && imageHeight != null) { if (imageWidth != null && imageHeight != null) {
setState(() { setState(() {
@ -255,6 +299,30 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
_isoSpeedRatings = exif.isoSpeedRatings; _isoSpeedRatings = exif.isoSpeedRatings;
}); });
} }
if (exif.gpsLatitudeRef != null &&
exif.gpsLatitude != null &&
exif.gpsLongitudeRef != null &&
exif.gpsLongitude != null) {
final lat = _gpsDmsToDouble(exif.gpsLatitude) *
(exif.gpsLatitudeRef == "S" ? -1 : 1);
final lng = _gpsDmsToDouble(exif.gpsLongitude) *
(exif.gpsLongitudeRef == "W" ? -1 : 1);
_log.fine("GPS: ($lat, $lng)");
setState(() {
_gps = LatLng(lat, lng);
});
}
}
static double _gpsDmsToDouble(List<Rational> dms) {
double product = dms[0].toDouble();
if (dms.length > 1) {
product += dms[1].toDouble() / 60;
}
if (dms.length > 2) {
product += dms[2].toDouble() / 3600;
}
return product;
} }
Future<void> _addToAlbum(BuildContext context, Album album) async { Future<void> _addToAlbum(BuildContext context, Album album) async {
@ -287,6 +355,7 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
String _exposureTime; String _exposureTime;
double _focalLength; double _focalLength;
int _isoSpeedRatings; int _isoSpeedRatings;
LatLng _gps;
static final _log = static final _log =
Logger("widget.viewer_detail_pane._ViewerDetailPaneState"); Logger("widget.viewer_detail_pane._ViewerDetailPaneState");

View file

@ -1,6 +1,13 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
android_intent:
dependency: "direct main"
description:
name: android_intent
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -153,6 +160,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
flutter_staggered_grid_view: flutter_staggered_grid_view:
dependency: "direct main" dependency: "direct main"
description: description:
@ -165,6 +179,20 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
google_maps_flutter:
dependency: "direct main"
description:
name: google_maps_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
google_maps_flutter_platform_interface:
dependency: transitive
description:
name: google_maps_flutter_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
hashcodes: hashcodes:
dependency: transitive dependency: transitive
description: description:
@ -459,6 +487,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.10.0" version: "1.10.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:

View file

@ -26,6 +26,7 @@ dependencies:
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
android_intent: ^2.0.0
bloc: ^7.0.0 bloc: ^7.0.0
cached_network_image: ^3.0.0 cached_network_image: ^3.0.0
connectivity: ^3.0.2 connectivity: ^3.0.2
@ -38,6 +39,7 @@ dependencies:
ref: 1.0.0 ref: 1.0.0
flutter_bloc: ^7.0.0 flutter_bloc: ^7.0.0
flutter_staggered_grid_view: ^0.3.3 flutter_staggered_grid_view: ^0.3.3
google_maps_flutter: ^2.0.3
http: ^0.13.1 http: ^0.13.1
idb_shim: ^2.0.0 idb_shim: ^2.0.0
idb_sqflite: ^1.0.0 idb_sqflite: ^1.0.0