diff --git a/lib/theme/icons.dart b/lib/theme/icons.dart index 485ffa8e2..42cb7de5c 100644 --- a/lib/theme/icons.dart +++ b/lib/theme/icons.dart @@ -148,7 +148,8 @@ class AIcons { static final setCover = MdiIcons.imageEditOutline; static const share = Icons.share_outlined; static const show = Icons.visibility_outlined; - static final showFullscreen = MdiIcons.arrowExpand; + static final showFullscreenArrows = MdiIcons.arrowExpand; + static const showFullscreenCorners = Icons.fullscreen_outlined; static const slideshow = Icons.slideshow_outlined; static const speed = Icons.speed_outlined; static const stats = Icons.donut_small_outlined; diff --git a/lib/widgets/common/map/buttons/button.dart b/lib/widgets/common/map/buttons/button.dart index f7f383522..f939cf96b 100644 --- a/lib/widgets/common/map/buttons/button.dart +++ b/lib/widgets/common/map/buttons/button.dart @@ -1,7 +1,4 @@ -import 'package:aves/model/settings/settings.dart'; -import 'package:aves/theme/themes.dart'; -import 'package:aves/widgets/common/fx/blurred.dart'; -import 'package:aves/widgets/common/fx/borders.dart'; +import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; import 'package:aves_map/aves_map.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -22,45 +19,21 @@ class MapOverlayButton extends StatelessWidget { @override Widget build(BuildContext context) { - final theme = Theme.of(context); - final colorScheme = theme.colorScheme; - final blurred = settings.enableBlurEffect; - - return Theme( - data: theme.copyWith( - colorScheme: colorScheme.copyWith( - onSurfaceVariant: colorScheme.onSurface, - ), + return Selector>( + selector: (context, v) => v.scale, + builder: (context, scale, child) => OverlayButton( + scale: scale, + child: child!, ), - child: Selector>( - selector: (context, v) => v.scale, - builder: (context, scale, child) => ScaleTransition( - scale: scale, - child: child, - ), - child: BlurredOval( - enabled: blurred, - child: Material( - type: MaterialType.circle, - color: Themes.overlayBackgroundColor(brightness: Theme.of(context).brightness, blurred: blurred), - child: Ink( - decoration: BoxDecoration( - border: AvesBorder.border(context), - shape: BoxShape.circle, - ), - child: Selector( - selector: (context, v) => v.visualDensity, - builder: (context, visualDensity, child) => IconButton( - key: buttonKey, - iconSize: 20, - visualDensity: visualDensity, - icon: icon, - onPressed: onPressed, - tooltip: tooltip, - ), - ), - ), - ), + child: Selector( + selector: (context, v) => v.visualDensity, + builder: (context, visualDensity, child) => IconButton( + key: buttonKey, + iconSize: 20 + 1.5 * visualDensity.horizontal, + visualDensity: visualDensity, + icon: icon, + onPressed: onPressed, + tooltip: tooltip, ), ), ); diff --git a/lib/widgets/common/map/buttons/panel.dart b/lib/widgets/common/map/buttons/panel.dart index 29340beb9..b57ce502f 100644 --- a/lib/widgets/common/map/buttons/panel.dart +++ b/lib/widgets/common/map/buttons/panel.dart @@ -52,7 +52,7 @@ class MapButtonPanel extends StatelessWidget { case MapNavigationButton.map: if (openMapPage != null) { navigationButton = MapOverlayButton( - icon: const Icon(AIcons.map), + icon: const Icon(AIcons.showFullscreenCorners), onPressed: () => openMapPage?.call(context), tooltip: context.l10n.openMapPageTooltip, ); @@ -62,8 +62,8 @@ class MapButtonPanel extends StatelessWidget { } final showCoordinateFilter = context.select((v) => v.showCoordinateFilter); - final visualDensity = context.select((v) => v.visualDensity); - final double padding = visualDensity == VisualDensity.compact ? 4 : 8; + final visualDensity = context.select((v) => v.visualDensity); + final double padding = 8 + visualDensity.horizontal * 2; return Positioned.fill( child: TooltipTheme( @@ -133,9 +133,9 @@ class MapButtonPanel extends StatelessWidget { // key is expected by test driver child: Column( children: [ - _buildButton(context, MapAction.selectStyle, buttonKey: const Key('map-menu-layers')), + _buildActionButton(context, MapAction.openMapApp), SizedBox(height: padding), - _buildButton(context, MapAction.openMapApp), + _buildActionButton(context, MapAction.selectStyle, buttonKey: const Key('map-menu-layers')), ], ), ), @@ -148,9 +148,9 @@ class MapButtonPanel extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - _buildButton(context, MapAction.zoomIn), + _buildActionButton(context, MapAction.zoomIn), SizedBox(height: padding), - _buildButton(context, MapAction.zoomOut), + _buildActionButton(context, MapAction.zoomOut), ], ), ), @@ -161,7 +161,7 @@ class MapButtonPanel extends StatelessWidget { ); } - Widget _buildButton(BuildContext context, MapAction action, {Key? buttonKey}) => MapOverlayButton( + Widget _buildActionButton(BuildContext context, MapAction action, {Key? buttonKey}) => MapOverlayButton( buttonKey: buttonKey, icon: action.getIcon(), onPressed: () => MapActionDelegate(controller).onActionSelected(context, action), diff --git a/lib/widgets/common/map/geo_map.dart b/lib/widgets/common/map/geo_map.dart index 5e21bbaeb..486a13a9e 100644 --- a/lib/widgets/common/map/geo_map.dart +++ b/lib/widgets/common/map/geo_map.dart @@ -20,6 +20,7 @@ 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/providers/map_theme_provider.dart'; import 'package:aves/widgets/common/thumbnail/image.dart'; import 'package:aves/widgets/dialogs/selection_dialogs/common.dart'; import 'package:aves/widgets/dialogs/selection_dialogs/single_selection.dart'; @@ -245,6 +246,50 @@ class _GeoMapState extends State { child = _decorateMap(context, overlay); } + child = Hero( + tag: 'map', + flightShuttleBuilder: (flightContext, animation, flightDirection, fromHeroContext, toHeroContext) { + final pushing = flightDirection == HeroFlightDirection.push; + final fromMediaQuery = MediaQuery.of(fromHeroContext); + final toMediaQuery = MediaQuery.of(toHeroContext); + final fromRenderBox = fromHeroContext.findRenderObject()! as RenderBox; + final toRenderBox = toHeroContext.findRenderObject()! as RenderBox; + final fromTheme = fromHeroContext.read(); + final toTheme = toHeroContext.read(); + + return DefaultTextStyle( + style: DefaultTextStyle.of(toHeroContext).style, + child: AnimatedBuilder( + animation: animation, + builder: (context, child) { + final t = pushing ? animation.value : 1 - animation.value; + return MapTheme( + interactive: false, + showCoordinateFilter: false, + navigationButton: toTheme.navigationButton, + visualDensity: VisualDensity.lerp(fromTheme.visualDensity, toTheme.visualDensity, t), + child: MediaQuery( + data: toMediaQuery.copyWith( + padding: EdgeInsets.lerp(fromMediaQuery.padding, toMediaQuery.padding, t), + viewPadding: EdgeInsets.lerp(fromMediaQuery.viewPadding, toMediaQuery.viewPadding, t), + ), + child: Align( + alignment: Alignment.topCenter, + child: SizedBox.fromSize( + size: Size.lerp(fromRenderBox.size, toRenderBox.size, t), + child: child, + ), + ), + ), + ); + }, + child: toHeroContext.widget, + ), + ); + }, + child: child, + ); + final mapHeight = context.select((v) => v.mapHeight); child = Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -258,7 +303,10 @@ class _GeoMapState extends State { SafeArea( top: false, bottom: false, - child: Attribution(style: mapStyle), + child: Padding( + padding: context.select((v) => v.attributionPadding), + child: Attribution(style: mapStyle), + ), ), ], ); diff --git a/lib/widgets/common/providers/map_theme_provider.dart b/lib/widgets/common/providers/map_theme_provider.dart index 96a5d785a..065e423f7 100644 --- a/lib/widgets/common/providers/map_theme_provider.dart +++ b/lib/widgets/common/providers/map_theme_provider.dart @@ -7,8 +7,9 @@ class MapTheme extends StatelessWidget { final bool interactive, showCoordinateFilter; final MapNavigationButton navigationButton; final Animation scale; - final VisualDensity? visualDensity; + final VisualDensity visualDensity; final double? mapHeight; + final EdgeInsets attributionPadding; final Widget child; const MapTheme({ @@ -17,8 +18,9 @@ class MapTheme extends StatelessWidget { required this.showCoordinateFilter, required this.navigationButton, this.scale = kAlwaysCompleteAnimation, - this.visualDensity, + this.visualDensity = VisualDensity.standard, this.mapHeight, + this.attributionPadding = EdgeInsets.zero, required this.child, }); @@ -33,6 +35,7 @@ class MapTheme extends StatelessWidget { scale: scale, visualDensity: visualDensity, mapHeight: mapHeight, + attributionPadding: attributionPadding, ); }, child: child, diff --git a/lib/widgets/common/thumbnail/overlay.dart b/lib/widgets/common/thumbnail/overlay.dart index 28050d13f..44ffe840f 100644 --- a/lib/widgets/common/thumbnail/overlay.dart +++ b/lib/widgets/common/thumbnail/overlay.dart @@ -108,7 +108,7 @@ class ThumbnailZoomOverlay extends StatelessWidget { width: interactiveDimension, height: interactiveDimension, child: Icon( - AIcons.showFullscreen, + AIcons.showFullscreenArrows, size: context.select((t) => t.iconSize), color: Colors.white70, ), diff --git a/lib/widgets/dialogs/pick_dialogs/location_pick_page.dart b/lib/widgets/dialogs/pick_dialogs/location_pick_page.dart index 3d1c821b5..8dbbc5f1c 100644 --- a/lib/widgets/dialogs/pick_dialogs/location_pick_page.dart +++ b/lib/widgets/dialogs/pick_dialogs/location_pick_page.dart @@ -133,6 +133,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin interactive: true, showCoordinateFilter: false, navigationButton: MapNavigationButton.back, + attributionPadding: const EdgeInsets.symmetric(horizontal: 8), child: GeoMap( controller: _mapController, collection: openingCollection, diff --git a/lib/widgets/map/map_page.dart b/lib/widgets/map/map_page.dart index 382314cac..388612406 100644 --- a/lib/widgets/map/map_page.dart +++ b/lib/widgets/map/map_page.dart @@ -153,6 +153,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin _selectedIndexNotifier.addListener(_onThumbnailIndexChanged); Future.delayed(ADurations.pageTransitionLoose * timeDilation + const Duration(seconds: 1), () { + if (!mounted) return; final regionEntries = regionCollection?.sortedEntries ?? []; final initialEntry = widget.initialEntry ?? regionEntries.firstOrNull; if (initialEntry != null) { @@ -268,6 +269,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin showCoordinateFilter: true, navigationButton: canPop ? MapNavigationButton.back : MapNavigationButton.close, scale: _overlayScale, + attributionPadding: const EdgeInsets.symmetric(horizontal: 8), child: GeoMap( // key is expected by test driver key: const Key('map_view'), diff --git a/plugins/aves_map/lib/src/theme.dart b/plugins/aves_map/lib/src/theme.dart index dd188c8a2..97679da69 100644 --- a/plugins/aves_map/lib/src/theme.dart +++ b/plugins/aves_map/lib/src/theme.dart @@ -6,8 +6,9 @@ class MapThemeData { final bool interactive, showCoordinateFilter; final MapNavigationButton navigationButton; final Animation scale; - final VisualDensity? visualDensity; + final VisualDensity visualDensity; final double? mapHeight; + final EdgeInsets attributionPadding; const MapThemeData({ required this.interactive, @@ -16,6 +17,7 @@ class MapThemeData { required this.scale, required this.visualDensity, required this.mapHeight, + required this.attributionPadding, }); static const double markerOuterBorderWidth = 1.5;