diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3491ee69d..7ae044544 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -869,8 +869,8 @@ "@mapAttributionOsmHot": {}, "mapAttributionStamen": "Map data © [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors • Tiles by [Stamen Design](http://stamen.com), [CC BY 3.0](http://creativecommons.org/licenses/by/3.0)", "@mapAttributionStamen": {}, - "openMapTooltip": "View on Map page", - "@openMapTooltip": {}, + "openMapPageTooltip": "View on Map page", + "@openMapPageTooltip": {}, "viewerInfoOpenEmbeddedFailureFeedback": "Failed to extract embedded data", "@viewerInfoOpenEmbeddedFailureFeedback": {}, diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 8221a6519..41f9434c4 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -424,7 +424,7 @@ "mapPointNorthUpTooltip": "북쪽을 위로 가리키기", "mapAttributionOsmHot": "지도 데이터 © [OpenStreetMap](https://www.openstreetmap.org/copyright) 기여자 • 타일 [HOT](https://www.hotosm.org/) • 호스팅 [OSM France](https://openstreetmap.fr/)", "mapAttributionStamen": "지도 데이터 © [OpenStreetMap](https://www.openstreetmap.org/copyright) 기여자 • 타일 [Stamen Design](http://stamen.com), [CC BY 3.0](http://creativecommons.org/licenses/by/3.0)", - "openMapTooltip": "지도 페이지에서 보기", + "openMapPageTooltip": "지도 페이지에서 보기", "viewerInfoOpenEmbeddedFailureFeedback": "첨부 데이터 추출 오류", "viewerInfoOpenLinkText": "열기", diff --git a/lib/widgets/common/map/buttons.dart b/lib/widgets/common/map/buttons.dart index 0045a63d0..cba10e573 100644 --- a/lib/widgets/common/map/buttons.dart +++ b/lib/widgets/common/map/buttons.dart @@ -1,7 +1,6 @@ import 'package:aves/model/settings/enums.dart'; import 'package:aves/model/settings/map_style.dart'; import 'package:aves/model/settings/settings.dart'; -import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/services/common/services.dart'; import 'package:aves/theme/durations.dart'; import 'package:aves/theme/icons.dart'; @@ -12,16 +11,18 @@ import 'package:aves/widgets/common/map/compass.dart'; import 'package:aves/widgets/common/map/theme.dart'; import 'package:aves/widgets/common/map/zoomed_bounds.dart'; import 'package:aves/widgets/dialogs/aves_selection_dialog.dart'; -import 'package:aves/widgets/map/map_page.dart'; import 'package:aves/widgets/viewer/overlay/common.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:latlong2/latlong.dart'; import 'package:provider/provider.dart'; +typedef MapOpener = void Function(BuildContext context); + class MapButtonPanel extends StatelessWidget { final ValueNotifier boundsNotifier; final Future Function(double amount)? zoomBy; + final MapOpener? openMapPage; final VoidCallback? resetRotation; static const double padding = 4; @@ -30,6 +31,7 @@ class MapButtonPanel extends StatelessWidget { Key? key, required this.boundsNotifier, this.zoomBy, + this.openMapPage, this.resetRotation, }) : super(key: key); @@ -48,12 +50,11 @@ class MapButtonPanel extends StatelessWidget { ); break; case MapNavigationButton.map: - final collection = context.read(); - if (collection != null) { + if (openMapPage != null) { navigationButton = MapOverlayButton( icon: const Icon(AIcons.map), - onPressed: () => _goToMap(context, collection), - tooltip: context.l10n.openMapTooltip, + onPressed: () => openMapPage?.call(context), + tooltip: context.l10n.openMapPageTooltip, ); } break; @@ -170,20 +171,6 @@ class MapButtonPanel extends StatelessWidget { ), ); } - - void _goToMap(BuildContext context, CollectionLens collection) { - final entries = collection.sortedEntries.where((entry) => entry.hasGps).toList(); - - Navigator.push( - context, - MaterialPageRoute( - settings: const RouteSettings(name: MapPage.routeName), - builder: (context) => MapPage( - entries: entries, - ), - ), - ); - } } class MapOverlayButton extends StatelessWidget { diff --git a/lib/widgets/common/map/geo_map.dart b/lib/widgets/common/map/geo_map.dart index bbbf01a3e..05f2d9453 100644 --- a/lib/widgets/common/map/geo_map.dart +++ b/lib/widgets/common/map/geo_map.dart @@ -28,9 +28,11 @@ import 'package:provider/provider.dart'; class GeoMap extends StatefulWidget { final AvesMapController? controller; final List entries; + final AvesEntry? initialEntry; final ValueNotifier isAnimatingNotifier; final UserZoomChangeCallback? onUserZoomChange; final MarkerTapCallback? onMarkerTap; + final MapOpener? openMapPage; static const markerImageExtent = 48.0; static const pointerSize = Size(8, 6); @@ -39,9 +41,11 @@ class GeoMap extends StatefulWidget { Key? key, this.controller, required this.entries, + this.initialEntry, required this.isAnimatingNotifier, this.onUserZoomChange, this.onMarkerTap, + this.openMapPage, }) : super(key: key); @override @@ -63,7 +67,8 @@ class _GeoMapState extends State { @override void initState() { super.initState(); - final points = entries.map((v) => v.latLng!).toSet(); + final initialEntry = widget.initialEntry; + final points = (initialEntry != null ? [initialEntry] : entries).map((v) => v.latLng!).toSet(); _boundsNotifier = ValueNotifier(ZoomedBounds.fromPoints( points: points.isNotEmpty ? points : {Constants.wonders[Random().nextInt(Constants.wonders.length)]}, collocationZoom: settings.infoMapZoom, @@ -136,6 +141,7 @@ class _GeoMapState extends State { markerWidgetBuilder: _buildMarkerWidget, onUserZoomChange: widget.onUserZoomChange, onMarkerTap: _onMarkerTap, + openMapPage: widget.openMapPage, ) : EntryLeafletMap( controller: widget.controller, @@ -151,6 +157,7 @@ class _GeoMapState extends State { ), onUserZoomChange: widget.onUserZoomChange, onMarkerTap: _onMarkerTap, + openMapPage: widget.openMapPage, ); final mapHeight = context.select((v) => v.mapHeight); @@ -182,6 +189,7 @@ class _GeoMapState extends State { const MapDecorator(), MapButtonPanel( boundsNotifier: _boundsNotifier, + openMapPage: widget.openMapPage, ), ], ); diff --git a/lib/widgets/common/map/google/map.dart b/lib/widgets/common/map/google/map.dart index e0be2d050..301dacef8 100644 --- a/lib/widgets/common/map/google/map.dart +++ b/lib/widgets/common/map/google/map.dart @@ -26,6 +26,7 @@ class EntryGoogleMap extends StatefulWidget { final MarkerWidgetBuilder markerWidgetBuilder; final UserZoomChangeCallback? onUserZoomChange; final void Function(GeoEntry geoEntry)? onMarkerTap; + final MapOpener? openMapPage; const EntryGoogleMap({ Key? key, @@ -38,6 +39,7 @@ class EntryGoogleMap extends StatefulWidget { required this.markerWidgetBuilder, this.onUserZoomChange, this.onMarkerTap, + this.openMapPage, }) : super(key: key); @override @@ -125,6 +127,7 @@ class _EntryGoogleMapState extends State with WidgetsBindingObse MapButtonPanel( boundsNotifier: boundsNotifier, zoomBy: _zoomBy, + openMapPage: widget.openMapPage, resetRotation: _resetRotation, ), ], diff --git a/lib/widgets/common/map/leaflet/map.dart b/lib/widgets/common/map/leaflet/map.dart index b2c72a771..b27893e06 100644 --- a/lib/widgets/common/map/leaflet/map.dart +++ b/lib/widgets/common/map/leaflet/map.dart @@ -28,6 +28,7 @@ class EntryLeafletMap extends StatefulWidget { final Size markerSize; final UserZoomChangeCallback? onUserZoomChange; final void Function(GeoEntry geoEntry)? onMarkerTap; + final MapOpener? openMapPage; const EntryLeafletMap({ Key? key, @@ -41,6 +42,7 @@ class EntryLeafletMap extends StatefulWidget { required this.markerSize, this.onUserZoomChange, this.onMarkerTap, + this.openMapPage, }) : super(key: key); @override @@ -106,6 +108,7 @@ class _EntryLeafletMapState extends State with TickerProviderSt MapButtonPanel( boundsNotifier: boundsNotifier, zoomBy: _zoomBy, + openMapPage: widget.openMapPage, resetRotation: _resetRotation, ), ], diff --git a/lib/widgets/map/map_page.dart b/lib/widgets/map/map_page.dart index a658f462e..c59e7215e 100644 --- a/lib/widgets/map/map_page.dart +++ b/lib/widgets/map/map_page.dart @@ -17,10 +17,12 @@ class MapPage extends StatefulWidget { static const routeName = '/collection/map'; final List entries; + final AvesEntry? initialEntry; const MapPage({ Key? key, required this.entries, + this.initialEntry, }) : super(key: key); @override @@ -38,6 +40,7 @@ class _MapPageState extends State { @override void initState() { super.initState(); + if (settings.infoMapStyle.isGoogleMaps) { _isAnimatingNotifier = ValueNotifier(true); Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) { @@ -47,6 +50,14 @@ class _MapPageState extends State { } else { _isAnimatingNotifier = ValueNotifier(false); } + + final initialEntry = widget.initialEntry; + if (initialEntry != null) { + final index = entries.indexOf(initialEntry); + if (index != -1) { + _selectedIndexNotifier.value = index; + } + } _selectedIndexNotifier.addListener(_onThumbnailIndexChange); } @@ -72,6 +83,7 @@ class _MapPageState extends State { child: GeoMap( controller: _mapController, entries: entries, + initialEntry: widget.initialEntry, isAnimatingNotifier: _isAnimatingNotifier, onMarkerTap: (markerEntry, getClusterEntries) { final index = entries.indexOf(markerEntry); diff --git a/lib/widgets/viewer/info/location_section.dart b/lib/widgets/viewer/info/location_section.dart index 25cdf0db9..a76dad72b 100644 --- a/lib/widgets/viewer/info/location_section.dart +++ b/lib/widgets/viewer/info/location_section.dart @@ -9,9 +9,9 @@ import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/aves_filter_chip.dart'; import 'package:aves/widgets/common/map/geo_map.dart'; import 'package:aves/widgets/common/map/theme.dart'; +import 'package:aves/widgets/map/map_page.dart'; import 'package:aves/widgets/viewer/info/common.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; class LocationSection extends StatefulWidget { final CollectionLens? collection; @@ -84,18 +84,16 @@ class _LocationSectionState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.showTitle) const SectionRow(icon: AIcons.location), - ChangeNotifierProvider.value( - value: collection, - child: MapTheme( - interactive: false, - navigationButton: MapNavigationButton.map, - visualDensity: VisualDensity.compact, - mapHeight: 200, - child: GeoMap( - entries: [entry], - isAnimatingNotifier: widget.isScrollingNotifier, - onUserZoomChange: (zoom) => settings.infoMapZoom = zoom, - ), + MapTheme( + interactive: false, + navigationButton: MapNavigationButton.map, + visualDensity: VisualDensity.compact, + mapHeight: 200, + child: GeoMap( + entries: [entry], + isAnimatingNotifier: widget.isScrollingNotifier, + onUserZoomChange: (zoom) => settings.infoMapZoom = zoom, + openMapPage: collection != null ? _openMapPage : null, ), ), _AddressInfoGroup(entry: entry), @@ -117,6 +115,20 @@ class _LocationSectionState extends State { ); } + void _openMapPage(BuildContext context) { + final entries = (collection?.sortedEntries ?? []).where((entry) => entry.hasGps).toList(); + Navigator.push( + context, + MaterialPageRoute( + settings: const RouteSettings(name: MapPage.routeName), + builder: (context) => MapPage( + entries: entries, + initialEntry: entry, + ), + ), + ); + } + void _handleChange() => setState(() {}); }