map: improved default center

This commit is contained in:
Thibault Deckers 2022-09-03 15:25:50 +02:00
parent c5f8981a7e
commit 785e093e84
6 changed files with 52 additions and 20 deletions

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:aves/l10n/l10n.dart'; import 'package:aves/l10n/l10n.dart';
@ -15,6 +16,7 @@ import 'package:aves_map/aves_map.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:latlong2/latlong.dart';
final Settings settings = Settings._private(); final Settings settings = Settings._private();
@ -121,11 +123,14 @@ class Settings extends ChangeNotifier {
static const subtitleBackgroundColorKey = 'subtitle_background_color'; static const subtitleBackgroundColorKey = 'subtitle_background_color';
// info // info
static const infoMapStyleKey = 'info_map_style';
static const infoMapZoomKey = 'info_map_zoom'; static const infoMapZoomKey = 'info_map_zoom';
static const coordinateFormatKey = 'coordinates_format'; static const coordinateFormatKey = 'coordinates_format';
static const unitSystemKey = 'unit_system'; static const unitSystemKey = 'unit_system';
// map
static const mapStyleKey = 'info_map_style';
static const mapDefaultCenterKey = 'map_default_center';
// search // search
static const saveSearchHistoryKey = 'save_search_history'; static const saveSearchHistoryKey = 'save_search_history';
static const searchHistoryKey = 'search_history'; static const searchHistoryKey = 'search_history';
@ -198,10 +203,10 @@ class Settings extends ChangeNotifier {
// availability // availability
final defaultMapStyle = mobileServices.defaultMapStyle; final defaultMapStyle = mobileServices.defaultMapStyle;
if (mobileServices.mapStyles.contains(defaultMapStyle)) { if (mobileServices.mapStyles.contains(defaultMapStyle)) {
infoMapStyle = defaultMapStyle; mapStyle = defaultMapStyle;
} else { } else {
final styles = EntryMapStyle.values.whereNot((v) => v.needMobileService).toList(); final styles = EntryMapStyle.values.whereNot((v) => v.needMobileService).toList();
infoMapStyle = styles[Random().nextInt(styles.length)]; mapStyle = styles[Random().nextInt(styles.length)];
} }
} }
@ -556,14 +561,6 @@ class Settings extends ChangeNotifier {
// info // info
EntryMapStyle get infoMapStyle {
final preferred = getEnumOrDefault(infoMapStyleKey, SettingsDefaults.infoMapStyle, EntryMapStyle.values);
final available = availability.mapStyles;
return available.contains(preferred) ? preferred : available.first;
}
set infoMapStyle(EntryMapStyle newValue) => setAndNotify(infoMapStyleKey, newValue.toString());
double get infoMapZoom => getDouble(infoMapZoomKey) ?? SettingsDefaults.infoMapZoom; double get infoMapZoom => getDouble(infoMapZoomKey) ?? SettingsDefaults.infoMapZoom;
set infoMapZoom(double newValue) => setAndNotify(infoMapZoomKey, newValue); set infoMapZoom(double newValue) => setAndNotify(infoMapZoomKey, newValue);
@ -576,6 +573,23 @@ class Settings extends ChangeNotifier {
set unitSystem(UnitSystem newValue) => setAndNotify(unitSystemKey, newValue.toString()); set unitSystem(UnitSystem newValue) => setAndNotify(unitSystemKey, newValue.toString());
// map
EntryMapStyle get mapStyle {
final preferred = getEnumOrDefault(mapStyleKey, SettingsDefaults.infoMapStyle, EntryMapStyle.values);
final available = availability.mapStyles;
return available.contains(preferred) ? preferred : available.first;
}
set mapStyle(EntryMapStyle newValue) => setAndNotify(mapStyleKey, newValue.toString());
LatLng? get mapDefaultCenter {
final json = getString(mapDefaultCenterKey);
return json != null ? LatLng.fromJson(jsonDecode(json)) : null;
}
set mapDefaultCenter(LatLng? newValue) => setAndNotify(mapDefaultCenterKey, newValue != null ? jsonEncode(newValue.toJson()) : null);
// search // search
bool get saveSearchHistory => getBoolOrDefault(saveSearchHistoryKey, SettingsDefaults.saveSearchHistory); bool get saveSearchHistory => getBoolOrDefault(saveSearchHistoryKey, SettingsDefaults.saveSearchHistory);
@ -863,7 +877,8 @@ class Settings extends ChangeNotifier {
case videoLoopModeKey: case videoLoopModeKey:
case videoControlsKey: case videoControlsKey:
case subtitleTextAlignmentKey: case subtitleTextAlignmentKey:
case infoMapStyleKey: case mapStyleKey:
case mapDefaultCenterKey:
case coordinateFormatKey: case coordinateFormatKey:
case unitSystemKey: case unitSystemKey:
case accessibilityAnimationsKey: case accessibilityAnimationsKey:

View file

@ -129,11 +129,11 @@ class MapButtonPanel extends StatelessWidget {
onPressed: () => showSelectionDialog<EntryMapStyle>( onPressed: () => showSelectionDialog<EntryMapStyle>(
context: context, context: context,
builder: (context) => AvesSelectionDialog<EntryMapStyle>( builder: (context) => AvesSelectionDialog<EntryMapStyle>(
initialValue: settings.infoMapStyle, initialValue: settings.mapStyle,
options: Map.fromEntries(availability.mapStyles.map((v) => MapEntry(v, v.getName(context)))), options: Map.fromEntries(availability.mapStyles.map((v) => MapEntry(v, v.getName(context)))),
title: context.l10n.mapStyleDialogTitle, title: context.l10n.mapStyleDialogTitle,
), ),
onSelection: (v) => settings.infoMapStyle = v, onSelection: (v) => settings.mapStyle = v,
), ),
tooltip: context.l10n.mapStyleTooltip, tooltip: context.l10n.mapStyleTooltip,
), ),

View file

@ -149,7 +149,7 @@ class _GeoMapState extends State<GeoMap> {
} }
return Selector<Settings, EntryMapStyle>( return Selector<Settings, EntryMapStyle>(
selector: (context, s) => s.infoMapStyle, selector: (context, s) => s.mapStyle,
builder: (context, mapStyle, child) { builder: (context, mapStyle, child) {
final isHeavy = mapStyle.isHeavy; final isHeavy = mapStyle.isHeavy;
Widget _buildMarkerWidget(MarkerKey<AvesEntry> key) => ImageMarker( Widget _buildMarkerWidget(MarkerKey<AvesEntry> key) => ImageMarker(
@ -281,6 +281,7 @@ class _GeoMapState extends State<GeoMap> {
final overlayEntry = widget.overlayEntry; final overlayEntry = widget.overlayEntry;
if (overlayEntry != null) { if (overlayEntry != null) {
// fit map to overlaid item
final corner1 = overlayEntry.topLeft; final corner1 = overlayEntry.topLeft;
final corner2 = overlayEntry.bottomRight; final corner2 = overlayEntry.bottomRight;
if (corner1 != null && corner2 != null) { if (corner1 != null && corner2 != null) {
@ -290,10 +291,26 @@ class _GeoMapState extends State<GeoMap> {
} }
} }
if (bounds == null) { if (bounds == null) {
// fit map to located items
final initialCenter = widget.initialCenter; final initialCenter = widget.initialCenter;
final points = initialCenter != null ? {initialCenter} : entries.map((v) => v.latLng!).toSet(); final points = initialCenter != null ? {initialCenter} : entries.map((v) => v.latLng!).toSet();
if (points.isNotEmpty) {
bounds = ZoomedBounds.fromPoints(
points: points,
collocationZoom: settings.infoMapZoom,
);
final center = bounds.projectedCenter;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
settings.mapDefaultCenter = center;
});
}
}
if (bounds == null) {
// fallback to default center
final center = settings.mapDefaultCenter ??= Constants.wonders[Random().nextInt(Constants.wonders.length)];
bounds = ZoomedBounds.fromPoints( bounds = ZoomedBounds.fromPoints(
points: points.isNotEmpty ? points : {Constants.wonders[Random().nextInt(Constants.wonders.length)]}, points: {center},
collocationZoom: settings.infoMapZoom, collocationZoom: settings.infoMapZoom,
); );
} }

View file

@ -78,7 +78,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
void initState() { void initState() {
super.initState(); super.initState();
if (settings.infoMapStyle.isHeavy) { if (settings.mapStyle.isHeavy) {
_isPageAnimatingNotifier = ValueNotifier(true); _isPageAnimatingNotifier = ValueNotifier(true);
Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) { Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) {
if (!mounted) return; if (!mounted) return;

View file

@ -107,7 +107,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
void initState() { void initState() {
super.initState(); super.initState();
if (settings.infoMapStyle.isHeavy) { if (settings.mapStyle.isHeavy) {
_isPageAnimatingNotifier.value = true; _isPageAnimatingNotifier.value = true;
Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) { Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) {
if (!mounted) return; if (!mounted) return;
@ -170,7 +170,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
return true; return true;
}, },
child: Selector<Settings, EntryMapStyle>( child: Selector<Settings, EntryMapStyle>(
selector: (context, s) => s.infoMapStyle, selector: (context, s) => s.mapStyle,
builder: (context, mapStyle, child) { builder: (context, mapStyle, child) {
late Widget scroller; late Widget scroller;
if (mapStyle.isHeavy) { if (mapStyle.isHeavy) {

View file

@ -38,6 +38,6 @@ Future<void> configureAndLaunch() async {
..showOverlayThumbnailPreview = true ..showOverlayThumbnailPreview = true
..imageBackground = EntryBackground.checkered ..imageBackground = EntryBackground.checkered
// info // info
..infoMapStyle = EntryMapStyle.googleNormal; ..mapStyle = EntryMapStyle.googleNormal;
app.main(); app.main();
} }