diff --git a/mobile/lib/presentation/widgets/map/map.widget.dart b/mobile/lib/presentation/widgets/map/map.widget.dart index 49af53f1eb..0c3b37a3b4 100644 --- a/mobile/lib/presentation/widgets/map/map.widget.dart +++ b/mobile/lib/presentation/widgets/map/map.widget.dart @@ -47,10 +47,12 @@ class _DriftMapState extends ConsumerState { MapLibreMapController? mapController; final _reloadMutex = AsyncMutex(); final _debouncer = Debouncer(interval: const Duration(milliseconds: 500), maxWaitTime: const Duration(seconds: 2)); + final ValueNotifier bottomSheetOffset = ValueNotifier(0.25); @override void dispose() { _debouncer.dispose(); + bottomSheetOffset.dispose(); super.dispose(); } @@ -157,8 +159,8 @@ class _DriftMapState extends ConsumerState { return Stack( children: [ _Map(initialLocation: widget.initialLocation, onMapCreated: onMapCreated, onMapReady: onMapReady), - _MyLocationButton(onZoomToLocation: onZoomToLocation), - const MapBottomSheet(), + _DynamicBottomSheet(bottomSheetOffset: bottomSheetOffset), + _DynamicMyLocationButton(onZoomToLocation: onZoomToLocation, bottomSheetOffset: bottomSheetOffset), ], ); } @@ -191,21 +193,53 @@ class _Map extends StatelessWidget { } } -class _MyLocationButton extends StatelessWidget { - const _MyLocationButton({required this.onZoomToLocation}); +class _DynamicBottomSheet extends StatefulWidget { + final ValueNotifier bottomSheetOffset; - final VoidCallback onZoomToLocation; + const _DynamicBottomSheet({required this.bottomSheetOffset}); + @override + State<_DynamicBottomSheet> createState() => _DynamicBottomSheetState(); +} + +class _DynamicBottomSheetState extends State<_DynamicBottomSheet> { @override Widget build(BuildContext context) { - return Positioned( - right: 0, - bottom: context.padding.bottom + 16, - child: ElevatedButton( - onPressed: onZoomToLocation, - style: ElevatedButton.styleFrom(shape: const CircleBorder()), - child: const Icon(Icons.my_location), - ), + return NotificationListener( + onNotification: (notification) { + widget.bottomSheetOffset.value = notification.extent; + return true; + }, + child: const MapBottomSheet(), + ); + } +} + +class _DynamicMyLocationButton extends StatelessWidget { + const _DynamicMyLocationButton({required this.onZoomToLocation, required this.bottomSheetOffset}); + + final VoidCallback onZoomToLocation; + final ValueNotifier bottomSheetOffset; + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: bottomSheetOffset, + builder: (context, offset, child) { + return Positioned( + right: 16, + bottom: context.height * (offset - 0.02) + context.padding.bottom, + child: AnimatedOpacity( + opacity: offset < 0.8 ? 1 : 0, + duration: const Duration(milliseconds: 150), + child: ElevatedButton( + onPressed: onZoomToLocation, + style: ElevatedButton.styleFrom(shape: const CircleBorder()), + child: const Icon(Icons.my_location), + ), + ), + ); + }, ); } }