#29 no default map style for izzy and libre flavors

This commit is contained in:
Thibault Deckers 2022-11-20 18:32:16 +01:00
parent a8ba0e2679
commit e2b28a366e
14 changed files with 185 additions and 114 deletions

View file

@ -8,6 +8,11 @@ All notable changes to this project will be documented in this file.
- Info: export metadata to text file - Info: export metadata to text file
- Accessibility: apply bold font system setting - Accessibility: apply bold font system setting
- `libre` app flavor (no mobile service maps, no Crashlytics)
### Changed
- No default map style for `izzy` and `libre` flavors
### Fixed ### Fixed

View file

@ -11,4 +11,15 @@ extension ExtraAppFlavor on AppFlavor {
return false; return false;
} }
} }
bool get hasMapStyleDefault {
switch (this) {
case AppFlavor.play:
case AppFlavor.huawei:
return true;
case AppFlavor.izzy:
case AppFlavor.libre:
return false;
}
}
} }

View file

@ -7,7 +7,6 @@ import 'package:aves/model/source/enums/enums.dart';
import 'package:aves/widgets/filter_grids/albums_page.dart'; import 'package:aves/widgets/filter_grids/albums_page.dart';
import 'package:aves/widgets/filter_grids/countries_page.dart'; import 'package:aves/widgets/filter_grids/countries_page.dart';
import 'package:aves/widgets/filter_grids/tags_page.dart'; import 'package:aves/widgets/filter_grids/tags_page.dart';
import 'package:aves_map/aves_map.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SettingsDefaults { class SettingsDefaults {
@ -104,7 +103,6 @@ class SettingsDefaults {
static const subtitleBackgroundColor = Colors.transparent; static const subtitleBackgroundColor = Colors.transparent;
// info // info
static const infoMapStyle = EntryMapStyle.stamenWatercolor; // `infoMapStyle` has a contextual default value
static const infoMapZoom = 12.0; static const infoMapZoom = 12.0;
static const coordinateFormat = CoordinateFormat.dms; static const coordinateFormat = CoordinateFormat.dms;
static const unitSystem = UnitSystem.metric; static const unitSystem = UnitSystem.metric;

View file

@ -3,6 +3,19 @@ import 'package:aves_map/aves_map.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
extension ExtraEntryMapStyle on EntryMapStyle { extension ExtraEntryMapStyle on EntryMapStyle {
static bool isHeavy(EntryMapStyle? style) {
switch (style) {
case EntryMapStyle.googleNormal:
case EntryMapStyle.googleHybrid:
case EntryMapStyle.googleTerrain:
case EntryMapStyle.hmsNormal:
case EntryMapStyle.hmsTerrain:
return true;
default:
return false;
}
}
String getName(BuildContext context) { String getName(BuildContext context) {
switch (this) { switch (this) {
case EntryMapStyle.googleNormal: case EntryMapStyle.googleNormal:
@ -24,19 +37,6 @@ extension ExtraEntryMapStyle on EntryMapStyle {
} }
} }
bool get isHeavy {
switch (this) {
case EntryMapStyle.googleNormal:
case EntryMapStyle.googleHybrid:
case EntryMapStyle.googleTerrain:
case EntryMapStyle.hmsNormal:
case EntryMapStyle.hmsTerrain:
return true;
default:
return false;
}
}
bool get needMobileService { bool get needMobileService {
switch (this) { switch (this) {
case EntryMapStyle.osmHot: case EntryMapStyle.osmHot:

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:aves/app_flavor.dart';
import 'package:aves/model/actions/entry_actions.dart'; import 'package:aves/model/actions/entry_actions.dart';
import 'package:aves/model/actions/entry_set_actions.dart'; import 'package:aves/model/actions/entry_set_actions.dart';
import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/filters/filters.dart';
@ -202,12 +203,13 @@ class Settings extends ChangeNotifier {
bool isInternalKey(String key) => _internalKeys.contains(key) || key.startsWith(_widgetKeyPrefix); bool isInternalKey(String key) => _internalKeys.contains(key) || key.startsWith(_widgetKeyPrefix);
Future<void> setContextualDefaults() async { Future<void> setContextualDefaults(AppFlavor flavor) async {
// performance // performance
final performanceClass = await deviceService.getPerformanceClass(); final performanceClass = await deviceService.getPerformanceClass();
enableBlurEffect = performanceClass >= 29; enableBlurEffect = performanceClass >= 29;
// availability // availability
if (flavor.hasMapStyleDefault) {
final defaultMapStyle = mobileServices.defaultMapStyle; final defaultMapStyle = mobileServices.defaultMapStyle;
if (mobileServices.mapStyles.contains(defaultMapStyle)) { if (mobileServices.mapStyles.contains(defaultMapStyle)) {
mapStyle = defaultMapStyle; mapStyle = defaultMapStyle;
@ -216,6 +218,7 @@ class Settings extends ChangeNotifier {
mapStyle = styles[Random().nextInt(styles.length)]; mapStyle = styles[Random().nextInt(styles.length)];
} }
} }
}
// app // app
@ -598,13 +601,15 @@ class Settings extends ChangeNotifier {
// map // map
EntryMapStyle get mapStyle { EntryMapStyle? get mapStyle {
final preferred = getEnumOrDefault(mapStyleKey, SettingsDefaults.infoMapStyle, EntryMapStyle.values); final preferred = getEnumOrDefault(mapStyleKey, null, EntryMapStyle.values);
if (preferred == null) return null;
final available = availability.mapStyles; final available = availability.mapStyles;
return available.contains(preferred) ? preferred : available.first; return available.contains(preferred) ? preferred : available.first;
} }
set mapStyle(EntryMapStyle newValue) => setAndNotify(mapStyleKey, newValue.toString()); set mapStyle(EntryMapStyle? newValue) => setAndNotify(mapStyleKey, newValue?.toString());
LatLng? get mapDefaultCenter { LatLng? get mapDefaultCenter {
final json = getString(mapDefaultCenterKey); final json = getString(mapDefaultCenterKey);

View file

@ -6,7 +6,7 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class Attribution extends StatelessWidget { class Attribution extends StatelessWidget {
final EntryMapStyle style; final EntryMapStyle? style;
const Attribution({ const Attribution({
super.key, super.key,

View file

@ -128,7 +128,7 @@ class MapButtonPanel extends StatelessWidget {
icon: const Icon(AIcons.layers), icon: const Icon(AIcons.layers),
onPressed: () => showSelectionDialog<EntryMapStyle>( onPressed: () => showSelectionDialog<EntryMapStyle>(
context: context, context: context,
builder: (context) => AvesSelectionDialog<EntryMapStyle>( builder: (context) => AvesSelectionDialog<EntryMapStyle?>(
initialValue: settings.mapStyle, 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,

View file

@ -7,14 +7,18 @@ import 'package:aves/model/settings/enums/map_style.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.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/utils/change_notifier.dart'; import 'package:aves/utils/change_notifier.dart';
import 'package:aves/utils/constants.dart'; import 'package:aves/utils/constants.dart';
import 'package:aves/utils/math_utils.dart'; import 'package:aves/utils/math_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/map/attribution.dart'; import 'package:aves/widgets/common/map/attribution.dart';
import 'package:aves/widgets/common/map/buttons/panel.dart'; import 'package:aves/widgets/common/map/buttons/panel.dart';
import 'package:aves/widgets/common/map/decorator.dart'; import 'package:aves/widgets/common/map/decorator.dart';
import 'package:aves/widgets/common/map/leaflet/map.dart'; import 'package:aves/widgets/common/map/leaflet/map.dart';
import 'package:aves/widgets/common/thumbnail/image.dart'; import 'package:aves/widgets/common/thumbnail/image.dart';
import 'package:aves/widgets/dialogs/aves_selection_dialog.dart';
import 'package:aves/widgets/viewer/overlay/common.dart';
import 'package:aves_map/aves_map.dart'; import 'package:aves_map/aves_map.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:fluster/fluster.dart'; import 'package:fluster/fluster.dart';
@ -148,10 +152,10 @@ class _GeoMapState extends State<GeoMap> {
onTap(clusterAverageLocation, markerEntry, getClusterEntries); onTap(clusterAverageLocation, markerEntry, getClusterEntries);
} }
return Selector<Settings, EntryMapStyle>( return Selector<Settings, EntryMapStyle?>(
selector: (context, s) => s.mapStyle, selector: (context, s) => s.mapStyle,
builder: (context, mapStyle, child) { builder: (context, mapStyle, child) {
final isHeavy = mapStyle.isHeavy; final isHeavy = ExtraEntryMapStyle.isHeavy(mapStyle);
Widget _buildMarkerWidget(MarkerKey<AvesEntry> key) => ImageMarker( Widget _buildMarkerWidget(MarkerKey<AvesEntry> key) => ImageMarker(
key: key, key: key,
count: key.count, count: key.count,
@ -164,6 +168,7 @@ class _GeoMapState extends State<GeoMap> {
bool _isMarkerImageReady(MarkerKey<AvesEntry> key) => key.entry.isThumbnailReady(extent: MapThemeData.markerImageExtent); bool _isMarkerImageReady(MarkerKey<AvesEntry> key) => key.entry.isThumbnailReady(extent: MapThemeData.markerImageExtent);
Widget child = const SizedBox(); Widget child = const SizedBox();
if (mapStyle != null) {
switch (mapStyle) { switch (mapStyle) {
case EntryMapStyle.googleNormal: case EntryMapStyle.googleNormal:
case EntryMapStyle.googleHybrid: case EntryMapStyle.googleHybrid:
@ -219,6 +224,30 @@ class _GeoMapState extends State<GeoMap> {
); );
break; break;
} }
} else {
final overlay = Center(
child: OverlayTextButton(
onPressed: () => showSelectionDialog<EntryMapStyle>(
context: context,
builder: (context) => AvesSelectionDialog<EntryMapStyle?>(
initialValue: settings.mapStyle,
options: Map.fromEntries(availability.mapStyles.map((v) => MapEntry(v, v.getName(context)))),
title: context.l10n.mapStyleDialogTitle,
),
onSelection: (v) => settings.mapStyle = v,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(AIcons.layers),
const SizedBox(width: 8),
Text(context.l10n.mapStyleTooltip),
],
),
),
);
child = _decorateMap(context, overlay);
}
final mapHeight = context.select<MapThemeData, double?>((v) => v.mapHeight); final mapHeight = context.select<MapThemeData, double?>((v) => v.mapHeight);
child = Column( child = Column(
@ -308,7 +337,11 @@ class _GeoMapState extends State<GeoMap> {
} }
if (bounds == null) { if (bounds == null) {
// fallback to default center // fallback to default center
final center = settings.mapDefaultCenter ??= Constants.wonders[Random().nextInt(Constants.wonders.length)]; var center = settings.mapDefaultCenter;
if (center == null) {
center = Constants.wonders[Random().nextInt(Constants.wonders.length)];
WidgetsBinding.instance.addPostFrameCallback((_) => settings.mapDefaultCenter = center);
}
bounds = ZoomedBounds.fromPoints( bounds = ZoomedBounds.fromPoints(
points: {center}, 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.mapStyle.isHeavy) { if (ExtraEntryMapStyle.isHeavy(settings.mapStyle)) {
_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

@ -108,7 +108,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
void initState() { void initState() {
super.initState(); super.initState();
if (settings.mapStyle.isHeavy) { if (ExtraEntryMapStyle.isHeavy(settings.mapStyle)) {
_isPageAnimatingNotifier.value = true; _isPageAnimatingNotifier.value = true;
Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) { Future.delayed(Durations.pageTransitionAnimation * timeDilation).then((_) {
if (!mounted) return; if (!mounted) return;
@ -176,11 +176,11 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
} }
return true; return true;
}, },
child: Selector<Settings, EntryMapStyle>( child: Selector<Settings, EntryMapStyle?>(
selector: (context, s) => s.mapStyle, selector: (context, s) => s.mapStyle,
builder: (context, mapStyle, child) { builder: (context, mapStyle, child) {
late Widget scroller; late Widget scroller;
if (mapStyle.isHeavy) { if (ExtraEntryMapStyle.isHeavy(mapStyle)) {
// the map widget is too heavy for a smooth resizing animation // the map widget is too heavy for a smooth resizing animation
// so we just toggle visibility when overlay animation is done // so we just toggle visibility when overlay animation is done
scroller = ValueListenableBuilder<double>( scroller = ValueListenableBuilder<double>(

View file

@ -60,16 +60,38 @@ class OverlayButton extends StatelessWidget {
static double getSize(BuildContext context) => 48.0 + AvesBorder.curvedBorderWidth * 2; static double getSize(BuildContext context) => 48.0 + AvesBorder.curvedBorderWidth * 2;
} }
class OverlayTextButton extends StatelessWidget { class ScalingOverlayTextButton extends StatelessWidget {
final Animation<double> scale; final Animation<double> scale;
final String buttonLabel;
final VoidCallback? onPressed; final VoidCallback? onPressed;
final Widget child;
const ScalingOverlayTextButton({
super.key,
required this.scale,
this.onPressed,
required this.child,
});
@override
Widget build(BuildContext context) {
return SizeTransition(
sizeFactor: scale,
child: OverlayTextButton(
onPressed: onPressed,
child: child,
),
);
}
}
class OverlayTextButton extends StatelessWidget {
final VoidCallback? onPressed;
final Widget child;
const OverlayTextButton({ const OverlayTextButton({
super.key, super.key,
required this.scale,
required this.buttonLabel,
this.onPressed, this.onPressed,
required this.child,
}); });
static const _borderRadius = 123.0; static const _borderRadius = 123.0;
@ -79,9 +101,7 @@ class OverlayTextButton extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final blurred = settings.enableBlurEffect; final blurred = settings.enableBlurEffect;
final theme = Theme.of(context); final theme = Theme.of(context);
return SizeTransition( return BlurredRRect.all(
sizeFactor: scale,
child: BlurredRRect.all(
enabled: blurred, enabled: blurred,
borderRadius: _borderRadius, borderRadius: _borderRadius,
child: OutlinedButton( child: OutlinedButton(
@ -96,8 +116,7 @@ class OverlayTextButton extends StatelessWidget {
borderRadius: BorderRadius.all(Radius.circular(_borderRadius)), borderRadius: BorderRadius.all(Radius.circular(_borderRadius)),
)), )),
), ),
child: Text(buttonLabel), child: child,
),
), ),
); );
} }

View file

@ -22,9 +22,8 @@ class PanoramaOverlay extends StatelessWidget {
return Row( return Row(
children: [ children: [
const Spacer(), const Spacer(),
OverlayTextButton( ScalingOverlayTextButton(
scale: scale, scale: scale,
buttonLabel: context.l10n.viewerOpenPanoramaButtonLabel,
onPressed: () async { onPressed: () async {
final info = await metadataFetchService.getPanoramaInfo(entry); final info = await metadataFetchService.getPanoramaInfo(entry);
if (info != null) { if (info != null) {
@ -40,7 +39,8 @@ class PanoramaOverlay extends StatelessWidget {
)); ));
} }
}, },
) child: Text(context.l10n.viewerOpenPanoramaButtonLabel),
),
], ],
); );
} }

View file

@ -42,10 +42,10 @@ class WallpaperButtons extends StatelessWidget with FeedbackMixin {
const Spacer(), const Spacer(),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: padding / 2), padding: const EdgeInsets.symmetric(horizontal: padding / 2),
child: OverlayTextButton( child: ScalingOverlayTextButton(
scale: scale, scale: scale,
buttonLabel: context.l10n.viewerSetWallpaperButtonLabel,
onPressed: () => _setWallpaper(context), onPressed: () => _setWallpaper(context),
child: Text(context.l10n.viewerSetWallpaperButtonLabel),
), ),
), ),
], ],

View file

@ -31,7 +31,6 @@ class _WelcomePageState extends State<WelcomePage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
settings.setContextualDefaults();
_termsLoader = rootBundle.loadString(termsPath); _termsLoader = rootBundle.loadString(termsPath);
WidgetsBinding.instance.addPostFrameCallback((_) => _initWelcomeSettings()); WidgetsBinding.instance.addPostFrameCallback((_) => _initWelcomeSettings());
} }
@ -40,6 +39,7 @@ class _WelcomePageState extends State<WelcomePage> {
// so they are not subject to future default changes // so they are not subject to future default changes
void _initWelcomeSettings() { void _initWelcomeSettings() {
// this should be done outside of `initState`/`build` // this should be done outside of `initState`/`build`
settings.setContextualDefaults(context.read<AppFlavor>());
settings.isInstalledAppAccessAllowed = SettingsDefaults.isInstalledAppAccessAllowed; settings.isInstalledAppAccessAllowed = SettingsDefaults.isInstalledAppAccessAllowed;
settings.isErrorReportingAllowed = SettingsDefaults.isErrorReportingAllowed; settings.isErrorReportingAllowed = SettingsDefaults.isErrorReportingAllowed;
} }