#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
- 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

View file

@ -11,4 +11,15 @@ extension ExtraAppFlavor on AppFlavor {
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/countries_page.dart';
import 'package:aves/widgets/filter_grids/tags_page.dart';
import 'package:aves_map/aves_map.dart';
import 'package:flutter/material.dart';
class SettingsDefaults {
@ -104,7 +103,6 @@ class SettingsDefaults {
static const subtitleBackgroundColor = Colors.transparent;
// info
static const infoMapStyle = EntryMapStyle.stamenWatercolor; // `infoMapStyle` has a contextual default value
static const infoMapZoom = 12.0;
static const coordinateFormat = CoordinateFormat.dms;
static const unitSystem = UnitSystem.metric;

View file

@ -3,6 +3,19 @@ import 'package:aves_map/aves_map.dart';
import 'package:flutter/widgets.dart';
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) {
switch (this) {
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 {
switch (this) {
case EntryMapStyle.osmHot:

View file

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

View file

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

View file

@ -128,7 +128,7 @@ class MapButtonPanel extends StatelessWidget {
icon: const Icon(AIcons.layers),
onPressed: () => showSelectionDialog<EntryMapStyle>(
context: context,
builder: (context) => AvesSelectionDialog<EntryMapStyle>(
builder: (context) => AvesSelectionDialog<EntryMapStyle?>(
initialValue: settings.mapStyle,
options: Map.fromEntries(availability.mapStyles.map((v) => MapEntry(v, v.getName(context)))),
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/services/common/services.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/change_notifier.dart';
import 'package:aves/utils/constants.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/buttons/panel.dart';
import 'package:aves/widgets/common/map/decorator.dart';
import 'package:aves/widgets/common/map/leaflet/map.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:collection/collection.dart';
import 'package:fluster/fluster.dart';
@ -148,10 +152,10 @@ class _GeoMapState extends State<GeoMap> {
onTap(clusterAverageLocation, markerEntry, getClusterEntries);
}
return Selector<Settings, EntryMapStyle>(
return Selector<Settings, EntryMapStyle?>(
selector: (context, s) => s.mapStyle,
builder: (context, mapStyle, child) {
final isHeavy = mapStyle.isHeavy;
final isHeavy = ExtraEntryMapStyle.isHeavy(mapStyle);
Widget _buildMarkerWidget(MarkerKey<AvesEntry> key) => ImageMarker(
key: key,
count: key.count,
@ -164,6 +168,7 @@ class _GeoMapState extends State<GeoMap> {
bool _isMarkerImageReady(MarkerKey<AvesEntry> key) => key.entry.isThumbnailReady(extent: MapThemeData.markerImageExtent);
Widget child = const SizedBox();
if (mapStyle != null) {
switch (mapStyle) {
case EntryMapStyle.googleNormal:
case EntryMapStyle.googleHybrid:
@ -219,6 +224,30 @@ class _GeoMapState extends State<GeoMap> {
);
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);
child = Column(
@ -308,7 +337,11 @@ class _GeoMapState extends State<GeoMap> {
}
if (bounds == null) {
// 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(
points: {center},
collocationZoom: settings.infoMapZoom,

View file

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

View file

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

View file

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

View file

@ -22,9 +22,8 @@ class PanoramaOverlay extends StatelessWidget {
return Row(
children: [
const Spacer(),
OverlayTextButton(
ScalingOverlayTextButton(
scale: scale,
buttonLabel: context.l10n.viewerOpenPanoramaButtonLabel,
onPressed: () async {
final info = await metadataFetchService.getPanoramaInfo(entry);
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(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: padding / 2),
child: OverlayTextButton(
child: ScalingOverlayTextButton(
scale: scale,
buttonLabel: context.l10n.viewerSetWallpaperButtonLabel,
onPressed: () => _setWallpaper(context),
child: Text(context.l10n.viewerSetWallpaperButtonLabel),
),
),
],

View file

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