map: improved initial state for info -> map

This commit is contained in:
Thibault Deckers 2021-09-15 14:20:47 +09:00
parent a7f4d89dc7
commit 35b10b3470
8 changed files with 62 additions and 37 deletions

View file

@ -869,8 +869,8 @@
"@mapAttributionOsmHot": {}, "@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": "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": {}, "@mapAttributionStamen": {},
"openMapTooltip": "View on Map page", "openMapPageTooltip": "View on Map page",
"@openMapTooltip": {}, "@openMapPageTooltip": {},
"viewerInfoOpenEmbeddedFailureFeedback": "Failed to extract embedded data", "viewerInfoOpenEmbeddedFailureFeedback": "Failed to extract embedded data",
"@viewerInfoOpenEmbeddedFailureFeedback": {}, "@viewerInfoOpenEmbeddedFailureFeedback": {},

View file

@ -424,7 +424,7 @@
"mapPointNorthUpTooltip": "북쪽을 위로 가리키기", "mapPointNorthUpTooltip": "북쪽을 위로 가리키기",
"mapAttributionOsmHot": "지도 데이터 © [OpenStreetMap](https://www.openstreetmap.org/copyright) 기여자 • 타일 [HOT](https://www.hotosm.org/) • 호스팅 [OSM France](https://openstreetmap.fr/)", "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)", "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": "첨부 데이터 추출 오류", "viewerInfoOpenEmbeddedFailureFeedback": "첨부 데이터 추출 오류",
"viewerInfoOpenLinkText": "열기", "viewerInfoOpenLinkText": "열기",

View file

@ -1,7 +1,6 @@
import 'package:aves/model/settings/enums.dart'; import 'package:aves/model/settings/enums.dart';
import 'package:aves/model/settings/map_style.dart'; import 'package:aves/model/settings/map_style.dart';
import 'package:aves/model/settings/settings.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/services/common/services.dart';
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.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/theme.dart';
import 'package:aves/widgets/common/map/zoomed_bounds.dart'; import 'package:aves/widgets/common/map/zoomed_bounds.dart';
import 'package:aves/widgets/dialogs/aves_selection_dialog.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:aves/widgets/viewer/overlay/common.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
typedef MapOpener = void Function(BuildContext context);
class MapButtonPanel extends StatelessWidget { class MapButtonPanel extends StatelessWidget {
final ValueNotifier<ZoomedBounds> boundsNotifier; final ValueNotifier<ZoomedBounds> boundsNotifier;
final Future<void> Function(double amount)? zoomBy; final Future<void> Function(double amount)? zoomBy;
final MapOpener? openMapPage;
final VoidCallback? resetRotation; final VoidCallback? resetRotation;
static const double padding = 4; static const double padding = 4;
@ -30,6 +31,7 @@ class MapButtonPanel extends StatelessWidget {
Key? key, Key? key,
required this.boundsNotifier, required this.boundsNotifier,
this.zoomBy, this.zoomBy,
this.openMapPage,
this.resetRotation, this.resetRotation,
}) : super(key: key); }) : super(key: key);
@ -48,12 +50,11 @@ class MapButtonPanel extends StatelessWidget {
); );
break; break;
case MapNavigationButton.map: case MapNavigationButton.map:
final collection = context.read<CollectionLens?>(); if (openMapPage != null) {
if (collection != null) {
navigationButton = MapOverlayButton( navigationButton = MapOverlayButton(
icon: const Icon(AIcons.map), icon: const Icon(AIcons.map),
onPressed: () => _goToMap(context, collection), onPressed: () => openMapPage?.call(context),
tooltip: context.l10n.openMapTooltip, tooltip: context.l10n.openMapPageTooltip,
); );
} }
break; 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 { class MapOverlayButton extends StatelessWidget {

View file

@ -28,9 +28,11 @@ import 'package:provider/provider.dart';
class GeoMap extends StatefulWidget { class GeoMap extends StatefulWidget {
final AvesMapController? controller; final AvesMapController? controller;
final List<AvesEntry> entries; final List<AvesEntry> entries;
final AvesEntry? initialEntry;
final ValueNotifier<bool> isAnimatingNotifier; final ValueNotifier<bool> isAnimatingNotifier;
final UserZoomChangeCallback? onUserZoomChange; final UserZoomChangeCallback? onUserZoomChange;
final MarkerTapCallback? onMarkerTap; final MarkerTapCallback? onMarkerTap;
final MapOpener? openMapPage;
static const markerImageExtent = 48.0; static const markerImageExtent = 48.0;
static const pointerSize = Size(8, 6); static const pointerSize = Size(8, 6);
@ -39,9 +41,11 @@ class GeoMap extends StatefulWidget {
Key? key, Key? key,
this.controller, this.controller,
required this.entries, required this.entries,
this.initialEntry,
required this.isAnimatingNotifier, required this.isAnimatingNotifier,
this.onUserZoomChange, this.onUserZoomChange,
this.onMarkerTap, this.onMarkerTap,
this.openMapPage,
}) : super(key: key); }) : super(key: key);
@override @override
@ -63,7 +67,8 @@ class _GeoMapState extends State<GeoMap> {
@override @override
void initState() { void initState() {
super.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( _boundsNotifier = ValueNotifier(ZoomedBounds.fromPoints(
points: points.isNotEmpty ? points : {Constants.wonders[Random().nextInt(Constants.wonders.length)]}, points: points.isNotEmpty ? points : {Constants.wonders[Random().nextInt(Constants.wonders.length)]},
collocationZoom: settings.infoMapZoom, collocationZoom: settings.infoMapZoom,
@ -136,6 +141,7 @@ class _GeoMapState extends State<GeoMap> {
markerWidgetBuilder: _buildMarkerWidget, markerWidgetBuilder: _buildMarkerWidget,
onUserZoomChange: widget.onUserZoomChange, onUserZoomChange: widget.onUserZoomChange,
onMarkerTap: _onMarkerTap, onMarkerTap: _onMarkerTap,
openMapPage: widget.openMapPage,
) )
: EntryLeafletMap( : EntryLeafletMap(
controller: widget.controller, controller: widget.controller,
@ -151,6 +157,7 @@ class _GeoMapState extends State<GeoMap> {
), ),
onUserZoomChange: widget.onUserZoomChange, onUserZoomChange: widget.onUserZoomChange,
onMarkerTap: _onMarkerTap, onMarkerTap: _onMarkerTap,
openMapPage: widget.openMapPage,
); );
final mapHeight = context.select<MapThemeData, double?>((v) => v.mapHeight); final mapHeight = context.select<MapThemeData, double?>((v) => v.mapHeight);
@ -182,6 +189,7 @@ class _GeoMapState extends State<GeoMap> {
const MapDecorator(), const MapDecorator(),
MapButtonPanel( MapButtonPanel(
boundsNotifier: _boundsNotifier, boundsNotifier: _boundsNotifier,
openMapPage: widget.openMapPage,
), ),
], ],
); );

View file

@ -26,6 +26,7 @@ class EntryGoogleMap extends StatefulWidget {
final MarkerWidgetBuilder markerWidgetBuilder; final MarkerWidgetBuilder markerWidgetBuilder;
final UserZoomChangeCallback? onUserZoomChange; final UserZoomChangeCallback? onUserZoomChange;
final void Function(GeoEntry geoEntry)? onMarkerTap; final void Function(GeoEntry geoEntry)? onMarkerTap;
final MapOpener? openMapPage;
const EntryGoogleMap({ const EntryGoogleMap({
Key? key, Key? key,
@ -38,6 +39,7 @@ class EntryGoogleMap extends StatefulWidget {
required this.markerWidgetBuilder, required this.markerWidgetBuilder,
this.onUserZoomChange, this.onUserZoomChange,
this.onMarkerTap, this.onMarkerTap,
this.openMapPage,
}) : super(key: key); }) : super(key: key);
@override @override
@ -125,6 +127,7 @@ class _EntryGoogleMapState extends State<EntryGoogleMap> with WidgetsBindingObse
MapButtonPanel( MapButtonPanel(
boundsNotifier: boundsNotifier, boundsNotifier: boundsNotifier,
zoomBy: _zoomBy, zoomBy: _zoomBy,
openMapPage: widget.openMapPage,
resetRotation: _resetRotation, resetRotation: _resetRotation,
), ),
], ],

View file

@ -28,6 +28,7 @@ class EntryLeafletMap extends StatefulWidget {
final Size markerSize; final Size markerSize;
final UserZoomChangeCallback? onUserZoomChange; final UserZoomChangeCallback? onUserZoomChange;
final void Function(GeoEntry geoEntry)? onMarkerTap; final void Function(GeoEntry geoEntry)? onMarkerTap;
final MapOpener? openMapPage;
const EntryLeafletMap({ const EntryLeafletMap({
Key? key, Key? key,
@ -41,6 +42,7 @@ class EntryLeafletMap extends StatefulWidget {
required this.markerSize, required this.markerSize,
this.onUserZoomChange, this.onUserZoomChange,
this.onMarkerTap, this.onMarkerTap,
this.openMapPage,
}) : super(key: key); }) : super(key: key);
@override @override
@ -106,6 +108,7 @@ class _EntryLeafletMapState extends State<EntryLeafletMap> with TickerProviderSt
MapButtonPanel( MapButtonPanel(
boundsNotifier: boundsNotifier, boundsNotifier: boundsNotifier,
zoomBy: _zoomBy, zoomBy: _zoomBy,
openMapPage: widget.openMapPage,
resetRotation: _resetRotation, resetRotation: _resetRotation,
), ),
], ],

View file

@ -17,10 +17,12 @@ class MapPage extends StatefulWidget {
static const routeName = '/collection/map'; static const routeName = '/collection/map';
final List<AvesEntry> entries; final List<AvesEntry> entries;
final AvesEntry? initialEntry;
const MapPage({ const MapPage({
Key? key, Key? key,
required this.entries, required this.entries,
this.initialEntry,
}) : super(key: key); }) : super(key: key);
@override @override
@ -38,6 +40,7 @@ class _MapPageState extends State<MapPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
if (settings.infoMapStyle.isGoogleMaps) { if (settings.infoMapStyle.isGoogleMaps) {
_isAnimatingNotifier = ValueNotifier(true); _isAnimatingNotifier = ValueNotifier(true);
Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) { Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) {
@ -47,6 +50,14 @@ class _MapPageState extends State<MapPage> {
} else { } else {
_isAnimatingNotifier = ValueNotifier(false); _isAnimatingNotifier = ValueNotifier(false);
} }
final initialEntry = widget.initialEntry;
if (initialEntry != null) {
final index = entries.indexOf(initialEntry);
if (index != -1) {
_selectedIndexNotifier.value = index;
}
}
_selectedIndexNotifier.addListener(_onThumbnailIndexChange); _selectedIndexNotifier.addListener(_onThumbnailIndexChange);
} }
@ -72,6 +83,7 @@ class _MapPageState extends State<MapPage> {
child: GeoMap( child: GeoMap(
controller: _mapController, controller: _mapController,
entries: entries, entries: entries,
initialEntry: widget.initialEntry,
isAnimatingNotifier: _isAnimatingNotifier, isAnimatingNotifier: _isAnimatingNotifier,
onMarkerTap: (markerEntry, getClusterEntries) { onMarkerTap: (markerEntry, getClusterEntries) {
final index = entries.indexOf(markerEntry); final index = entries.indexOf(markerEntry);

View file

@ -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/identity/aves_filter_chip.dart';
import 'package:aves/widgets/common/map/geo_map.dart'; import 'package:aves/widgets/common/map/geo_map.dart';
import 'package:aves/widgets/common/map/theme.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:aves/widgets/viewer/info/common.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class LocationSection extends StatefulWidget { class LocationSection extends StatefulWidget {
final CollectionLens? collection; final CollectionLens? collection;
@ -84,9 +84,7 @@ class _LocationSectionState extends State<LocationSection> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (widget.showTitle) const SectionRow(icon: AIcons.location), if (widget.showTitle) const SectionRow(icon: AIcons.location),
ChangeNotifierProvider<CollectionLens?>.value( MapTheme(
value: collection,
child: MapTheme(
interactive: false, interactive: false,
navigationButton: MapNavigationButton.map, navigationButton: MapNavigationButton.map,
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
@ -95,7 +93,7 @@ class _LocationSectionState extends State<LocationSection> {
entries: [entry], entries: [entry],
isAnimatingNotifier: widget.isScrollingNotifier, isAnimatingNotifier: widget.isScrollingNotifier,
onUserZoomChange: (zoom) => settings.infoMapZoom = zoom, onUserZoomChange: (zoom) => settings.infoMapZoom = zoom,
), openMapPage: collection != null ? _openMapPage : null,
), ),
), ),
_AddressInfoGroup(entry: entry), _AddressInfoGroup(entry: entry),
@ -117,6 +115,20 @@ class _LocationSectionState extends State<LocationSection> {
); );
} }
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(() {}); void _handleChange() => setState(() {});
} }