mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-02 06:46:22 +01:00
Show MapView if GPS data exists in exif
This commit is contained in:
parent
4a8784f508
commit
d7269a1cba
6 changed files with 119 additions and 0 deletions
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
3
lib/platform/features.dart
Normal file
3
lib/platform/features.dart
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
final isSupportMapView = Platform.isAndroid;
|
|
@ -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");
|
||||||
|
|
35
pubspec.lock
35
pubspec.lock
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue