#29 no default map style for izzy
and libre
flavors
This commit is contained in:
parent
a8ba0e2679
commit
e2b28a366e
14 changed files with 185 additions and 114 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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,18 +203,20 @@ 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
|
||||||
final defaultMapStyle = mobileServices.defaultMapStyle;
|
if (flavor.hasMapStyleDefault) {
|
||||||
if (mobileServices.mapStyles.contains(defaultMapStyle)) {
|
final defaultMapStyle = mobileServices.defaultMapStyle;
|
||||||
mapStyle = defaultMapStyle;
|
if (mobileServices.mapStyles.contains(defaultMapStyle)) {
|
||||||
} else {
|
mapStyle = defaultMapStyle;
|
||||||
final styles = EntryMapStyle.values.whereNot((v) => v.needMobileService).toList();
|
} else {
|
||||||
mapStyle = styles[Random().nextInt(styles.length)];
|
final styles = EntryMapStyle.values.whereNot((v) => v.needMobileService).toList();
|
||||||
|
mapStyle = styles[Random().nextInt(styles.length)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,60 +168,85 @@ 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();
|
||||||
switch (mapStyle) {
|
if (mapStyle != null) {
|
||||||
case EntryMapStyle.googleNormal:
|
switch (mapStyle) {
|
||||||
case EntryMapStyle.googleHybrid:
|
case EntryMapStyle.googleNormal:
|
||||||
case EntryMapStyle.googleTerrain:
|
case EntryMapStyle.googleHybrid:
|
||||||
case EntryMapStyle.hmsNormal:
|
case EntryMapStyle.googleTerrain:
|
||||||
case EntryMapStyle.hmsTerrain:
|
case EntryMapStyle.hmsNormal:
|
||||||
child = mobileServices.buildMap<AvesEntry>(
|
case EntryMapStyle.hmsTerrain:
|
||||||
controller: widget.controller,
|
child = mobileServices.buildMap<AvesEntry>(
|
||||||
clusterListenable: _clusterChangeNotifier,
|
controller: widget.controller,
|
||||||
boundsNotifier: _boundsNotifier,
|
clusterListenable: _clusterChangeNotifier,
|
||||||
style: mapStyle,
|
boundsNotifier: _boundsNotifier,
|
||||||
decoratorBuilder: _decorateMap,
|
style: mapStyle,
|
||||||
buttonPanelBuilder: _buildButtonPanel,
|
decoratorBuilder: _decorateMap,
|
||||||
markerClusterBuilder: _buildMarkerClusters,
|
buttonPanelBuilder: _buildButtonPanel,
|
||||||
markerWidgetBuilder: _buildMarkerWidget,
|
markerClusterBuilder: _buildMarkerClusters,
|
||||||
markerImageReadyChecker: _isMarkerImageReady,
|
markerWidgetBuilder: _buildMarkerWidget,
|
||||||
dotLocationNotifier: widget.dotLocationNotifier,
|
markerImageReadyChecker: _isMarkerImageReady,
|
||||||
overlayOpacityNotifier: widget.overlayOpacityNotifier,
|
dotLocationNotifier: widget.dotLocationNotifier,
|
||||||
overlayEntry: widget.overlayEntry,
|
overlayOpacityNotifier: widget.overlayOpacityNotifier,
|
||||||
onUserZoomChange: widget.onUserZoomChange,
|
overlayEntry: widget.overlayEntry,
|
||||||
onMapTap: widget.onMapTap,
|
onUserZoomChange: widget.onUserZoomChange,
|
||||||
onMarkerTap: _onMarkerTap,
|
onMapTap: widget.onMapTap,
|
||||||
);
|
onMarkerTap: _onMarkerTap,
|
||||||
break;
|
);
|
||||||
case EntryMapStyle.osmHot:
|
break;
|
||||||
case EntryMapStyle.stamenToner:
|
case EntryMapStyle.osmHot:
|
||||||
case EntryMapStyle.stamenWatercolor:
|
case EntryMapStyle.stamenToner:
|
||||||
child = EntryLeafletMap<AvesEntry>(
|
case EntryMapStyle.stamenWatercolor:
|
||||||
controller: widget.controller,
|
child = EntryLeafletMap<AvesEntry>(
|
||||||
clusterListenable: _clusterChangeNotifier,
|
controller: widget.controller,
|
||||||
boundsNotifier: _boundsNotifier,
|
clusterListenable: _clusterChangeNotifier,
|
||||||
minZoom: 2,
|
boundsNotifier: _boundsNotifier,
|
||||||
maxZoom: 16,
|
minZoom: 2,
|
||||||
style: mapStyle,
|
maxZoom: 16,
|
||||||
decoratorBuilder: _decorateMap,
|
style: mapStyle,
|
||||||
buttonPanelBuilder: _buildButtonPanel,
|
decoratorBuilder: _decorateMap,
|
||||||
markerClusterBuilder: _buildMarkerClusters,
|
buttonPanelBuilder: _buildButtonPanel,
|
||||||
markerWidgetBuilder: _buildMarkerWidget,
|
markerClusterBuilder: _buildMarkerClusters,
|
||||||
dotLocationNotifier: widget.dotLocationNotifier,
|
markerWidgetBuilder: _buildMarkerWidget,
|
||||||
markerSize: Size(
|
dotLocationNotifier: widget.dotLocationNotifier,
|
||||||
MapThemeData.markerImageExtent + MapThemeData.markerOuterBorderWidth * 2,
|
markerSize: Size(
|
||||||
MapThemeData.markerImageExtent + MapThemeData.markerOuterBorderWidth * 2 + MapThemeData.markerArrowSize.height,
|
MapThemeData.markerImageExtent + MapThemeData.markerOuterBorderWidth * 2,
|
||||||
|
MapThemeData.markerImageExtent + MapThemeData.markerOuterBorderWidth * 2 + MapThemeData.markerArrowSize.height,
|
||||||
|
),
|
||||||
|
dotMarkerSize: const Size(
|
||||||
|
DotMarker.diameter + MapThemeData.markerOuterBorderWidth * 2,
|
||||||
|
DotMarker.diameter + MapThemeData.markerOuterBorderWidth * 2,
|
||||||
|
),
|
||||||
|
overlayOpacityNotifier: widget.overlayOpacityNotifier,
|
||||||
|
overlayEntry: widget.overlayEntry,
|
||||||
|
onUserZoomChange: widget.onUserZoomChange,
|
||||||
|
onMapTap: widget.onMapTap,
|
||||||
|
onMarkerTap: _onMarkerTap,
|
||||||
|
);
|
||||||
|
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,
|
||||||
),
|
),
|
||||||
dotMarkerSize: const Size(
|
child: Row(
|
||||||
DotMarker.diameter + MapThemeData.markerOuterBorderWidth * 2,
|
mainAxisSize: MainAxisSize.min,
|
||||||
DotMarker.diameter + MapThemeData.markerOuterBorderWidth * 2,
|
children: [
|
||||||
|
const Icon(AIcons.layers),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(context.l10n.mapStyleTooltip),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
overlayOpacityNotifier: widget.overlayOpacityNotifier,
|
),
|
||||||
overlayEntry: widget.overlayEntry,
|
);
|
||||||
onUserZoomChange: widget.onUserZoomChange,
|
child = _decorateMap(context, overlay);
|
||||||
onMapTap: widget.onMapTap,
|
|
||||||
onMarkerTap: _onMarkerTap,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final mapHeight = context.select<MapThemeData, double?>((v) => v.mapHeight);
|
final mapHeight = context.select<MapThemeData, double?>((v) => v.mapHeight);
|
||||||
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>(
|
||||||
|
|
|
@ -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,25 +101,22 @@ 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,
|
enabled: blurred,
|
||||||
child: BlurredRRect.all(
|
borderRadius: _borderRadius,
|
||||||
enabled: blurred,
|
child: OutlinedButton(
|
||||||
borderRadius: _borderRadius,
|
onPressed: onPressed,
|
||||||
child: OutlinedButton(
|
style: ButtonStyle(
|
||||||
onPressed: onPressed,
|
backgroundColor: MaterialStateProperty.all<Color>(Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred)),
|
||||||
style: ButtonStyle(
|
foregroundColor: MaterialStateProperty.all<Color>(theme.colorScheme.onSurface),
|
||||||
backgroundColor: MaterialStateProperty.all<Color>(Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred)),
|
overlayColor: theme.brightness == Brightness.dark ? MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.12)) : null,
|
||||||
foregroundColor: MaterialStateProperty.all<Color>(theme.colorScheme.onSurface),
|
minimumSize: _minSize,
|
||||||
overlayColor: theme.brightness == Brightness.dark ? MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.12)) : null,
|
side: MaterialStateProperty.all<BorderSide>(AvesBorder.curvedSide(context)),
|
||||||
minimumSize: _minSize,
|
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder(
|
||||||
side: MaterialStateProperty.all<BorderSide>(AvesBorder.curvedSide(context)),
|
borderRadius: BorderRadius.all(Radius.circular(_borderRadius)),
|
||||||
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder(
|
)),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(_borderRadius)),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
child: Text(buttonLabel),
|
|
||||||
),
|
),
|
||||||
|
child: child,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue