diff --git a/lib/mobile/map_widget.dart b/lib/mobile/map_widget.dart new file mode 100644 index 00000000..dca4a96b --- /dev/null +++ b/lib/mobile/map_widget.dart @@ -0,0 +1,50 @@ +import 'dart:math'; + +import 'package:flutter/widgets.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:tuple/tuple.dart'; + +class Map extends StatelessWidget { + const Map({ + Key key, + this.center, + this.zoom, + this.onTap, + }) : super(key: key); + + @override + build(BuildContext context) { + final centerLl = LatLng(center.item1, center.item2); + return GoogleMap( + compassEnabled: false, + mapToolbarEnabled: false, + rotateGesturesEnabled: false, + scrollGesturesEnabled: false, + zoomControlsEnabled: false, + zoomGesturesEnabled: false, + tiltGesturesEnabled: false, + myLocationButtonEnabled: false, + buildingsEnabled: false, + // liteModeEnabled: true, + initialCameraPosition: CameraPosition( + target: centerLl, + zoom: zoom, + ), + markers: { + Marker( + markerId: MarkerId("at"), + position: centerLl, + // for some reason, GoogleMap's onTap is not triggered if + // tapped on top of the marker + onTap: onTap, + ), + }, + onTap: (_) => onTap?.call(), + ); + } + + /// A pair of latitude and longitude coordinates, stored as degrees + final Tuple2 center; + final double zoom; + final void Function() onTap; +} diff --git a/lib/mobile/platform.dart b/lib/mobile/platform.dart index 604bf631..70daffc3 100644 --- a/lib/mobile/platform.dart +++ b/lib/mobile/platform.dart @@ -1,3 +1,4 @@ export 'db_util.dart'; export 'downloader.dart'; +export 'map_widget.dart'; export 'metadata_loader.dart'; diff --git a/lib/mobile/ui_hack.dart b/lib/mobile/ui_hack.dart new file mode 100644 index 00000000..13f23e05 --- /dev/null +++ b/lib/mobile/ui_hack.dart @@ -0,0 +1,5 @@ +// See: https://github.com/flutter/flutter/issues/41563 +// ignore: camel_case_types +class platformViewRegistry { + static registerViewFactory(String viewId, dynamic cb) {} +} diff --git a/lib/platform/features.dart b/lib/platform/features.dart index bd8d7b71..72b767fa 100644 --- a/lib/platform/features.dart +++ b/lib/platform/features.dart @@ -2,4 +2,4 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; -final isSupportMapView = !kIsWeb && Platform.isAndroid; +final isSupportMapView = kIsWeb || Platform.isAndroid; diff --git a/lib/web/map_widget.dart b/lib/web/map_widget.dart new file mode 100644 index 00000000..3c1df57b --- /dev/null +++ b/lib/web/map_widget.dart @@ -0,0 +1,49 @@ +// ignore: avoid_web_libraries_in_flutter +import 'dart:html'; + +import 'package:/nc_photos/mobile/ui_hack.dart' if (dart.library.html) 'dart:ui' + as ui; +import 'package:flutter/widgets.dart'; +import 'package:tuple/tuple.dart'; + +class Map extends StatefulWidget { + const Map({ + Key key, + this.center, + this.zoom, + this.onTap, + }) : super(key: key); + + @override + createState() => _MapState(); + + /// A pair of latitude and longitude coordinates, stored as degrees + final Tuple2 center; + final double zoom; + final void Function() onTap; +} + +class _MapState extends State { + @override + initState() { + super.initState(); + final iframe = IFrameElement() + ..src = "https://www.google.com/maps/embed/v1/place?key=$_apiKey" + "&q=${widget.center.item1},${widget.center.item2}" + "&zoom=${widget.zoom}" + ..style.border = "none"; + ui.platformViewRegistry.registerViewFactory(viewType, (viewId) => iframe); + } + + @override + build(BuildContext context) { + return HtmlElementView( + viewType: viewType, + ); + } + + static const _apiKey = ""; + + String get viewType => + "mapIframe(${widget.center.item1},${widget.center.item2})"; +} diff --git a/lib/web/platform.dart b/lib/web/platform.dart index 604bf631..70daffc3 100644 --- a/lib/web/platform.dart +++ b/lib/web/platform.dart @@ -1,3 +1,4 @@ export 'db_util.dart'; export 'downloader.dart'; +export 'map_widget.dart'; export 'metadata_loader.dart'; diff --git a/lib/widget/viewer_detail_pane.dart b/lib/widget/viewer_detail_pane.dart index 30c0ed99..6ccd32fd 100644 --- a/lib/widget/viewer_detail_pane.dart +++ b/lib/widget/viewer_detail_pane.dart @@ -6,7 +6,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.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:logging/logging.dart'; import 'package:nc_photos/account.dart'; @@ -17,6 +16,8 @@ import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/k.dart' as k; +import 'package:nc_photos/mobile/platform.dart' + if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform; import 'package:nc_photos/platform/features.dart' as features; import 'package:nc_photos/snack_bar_manager.dart'; import 'package:nc_photos/theme.dart'; @@ -24,6 +25,7 @@ import 'package:nc_photos/use_case/remove.dart'; import 'package:nc_photos/use_case/update_album.dart'; import 'package:nc_photos/widget/album_picker_dialog.dart'; import 'package:path/path.dart'; +import 'package:tuple/tuple.dart'; class ViewerDetailPane extends StatefulWidget { const ViewerDetailPane({ @@ -158,31 +160,10 @@ class _ViewerDetailPaneState extends State { 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(), + child: platform.Map( + center: _gps, + zoom: 16, + onTap: _onMapTap, ), ), ], @@ -261,7 +242,7 @@ class _ViewerDetailPaneState extends State { if (Platform.isAndroid) { final intent = AndroidIntent( action: "action_view", - data: Uri.encodeFull("geo:${_gps.latitude},${_gps.longitude}?z=16"), + data: Uri.encodeFull("geo:${_gps.item1},${_gps.item2}?z=16"), ); intent.launch(); } @@ -325,7 +306,7 @@ class _ViewerDetailPaneState extends State { (exif.gpsLongitudeRef == "W" ? -1 : 1); _log.fine("GPS: ($lat, $lng)"); setState(() { - _gps = LatLng(lat, lng); + _gps = Tuple2(lat, lng); }); } } @@ -384,7 +365,7 @@ class _ViewerDetailPaneState extends State { String _exposureTime; double _focalLength; int _isoSpeedRatings; - LatLng _gps; + Tuple2 _gps; static final _log = Logger("widget.viewer_detail_pane._ViewerDetailPaneState");