map: improved initial state for info -> map
This commit is contained in:
parent
a7f4d89dc7
commit
35b10b3470
8 changed files with 62 additions and 37 deletions
|
@ -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": {},
|
||||||
|
|
|
@ -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": "열기",
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -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,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue