diff --git a/lib/screens/LocationsOverviewScreen.dart b/lib/screens/LocationsOverviewScreen.dart index 1b6c7b9a..7d2700ff 100644 --- a/lib/screens/LocationsOverviewScreen.dart +++ b/lib/screens/LocationsOverviewScreen.dart @@ -45,7 +45,6 @@ import 'package:locus/widgets/LocationsMap.dart'; import 'package:locus/widgets/LocusFlutterMap.dart'; import 'package:locus/widgets/CompassMapAction.dart'; import 'package:locus/widgets/Paper.dart'; -import 'package:locus/widgets/PlatformFlavorWidget.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; import 'package:provider/provider.dart'; @@ -607,6 +606,41 @@ class _LocationsOverviewScreenState extends State } } + Future _animateToPosition( + final Position position, + ) async { + if (flutterMapController != null) { + final zoom = max(13, flutterMapController!.zoom).toDouble(); + + flutterMapController?.move( + LatLng( + position.latitude, + position.longitude, + ), + zoom, + ); + } + + if (appleMapController != null) { + final zoom = max( + 13, + (await appleMapController!.getZoomLevel())!, + ).toDouble(); + + appleMapController?.animateCamera( + apple_maps.CameraUpdate.newCameraPosition( + apple_maps.CameraPosition( + target: apple_maps.LatLng( + position!.latitude, + position!.longitude, + ), + zoom: zoom, + ), + ), + ); + } + } + void goToCurrentPosition({ final bool askPermissions = false, final bool showErrorMessage = true, @@ -637,39 +671,6 @@ class _LocationsOverviewScreenState extends State _initLiveLocationUpdate(); - if (lastPosition != null) { - if (flutterMapController != null) { - final zoom = max(13, flutterMapController!.zoom).toDouble(); - - flutterMapController?.move( - LatLng( - lastPosition!.latitude, - lastPosition!.longitude, - ), - zoom, - ); - } - - if (appleMapController != null) { - final zoom = max( - 13, - (await appleMapController!.getZoomLevel())!, - ).toDouble(); - - appleMapController?.animateCamera( - apple_maps.CameraUpdate.newCameraPosition( - apple_maps.CameraPosition( - target: apple_maps.LatLng( - lastPosition!.latitude, - lastPosition!.longitude, - ), - zoom: zoom, - ), - ), - ); - } - } - FlutterLogs.logInfo( LOG_TAG, "LocationOverviewScreen", @@ -687,6 +688,8 @@ class _LocationsOverviewScreenState extends State ), ); + _animateToPosition(latestPosition); + setState(() { lastPosition = latestPosition; locationStatus = LocationStatus.active; @@ -768,18 +771,7 @@ class _LocationsOverviewScreenState extends State appleMapController = controller; if (lastPosition != null) { - appleMapController?.moveCamera( - apple_maps.CameraUpdate.newCameraPosition( - apple_maps.CameraPosition( - target: apple_maps.LatLng( - lastPosition!.latitude, - lastPosition!.longitude, - ), - zoom: 13, - ), - ), - ); - + _animateToPosition(lastPosition!); _hasGoneToInitialPosition = true; } }, @@ -1350,6 +1342,7 @@ class _LocationsOverviewScreenState extends State ), const SizedBox(height: SMALL_SPACE), GoToMyLocationMapAction( + animate: locationStatus == LocationStatus.fetching, onGoToMyLocation: () { goToCurrentPosition(askPermissions: true); }, diff --git a/lib/widgets/GoToMyLocationMapAction.dart b/lib/widgets/GoToMyLocationMapAction.dart index 6840a8f8..cc31fcf2 100644 --- a/lib/widgets/GoToMyLocationMapAction.dart +++ b/lib/widgets/GoToMyLocationMapAction.dart @@ -1,5 +1,8 @@ +import 'dart:math'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:locus/utils/theme.dart'; @@ -7,18 +10,59 @@ import 'package:locus/utils/theme.dart'; import '../constants/spacing.dart'; import 'Paper.dart'; -class GoToMyLocationMapAction extends StatelessWidget { +class GoToMyLocationMapAction extends StatefulWidget { final double dimension; final double tooltipSpacing; final VoidCallback onGoToMyLocation; + final bool animate; const GoToMyLocationMapAction({ this.dimension = 50.0, this.tooltipSpacing = 10.0, + this.animate = false, required this.onGoToMyLocation, super.key, }); + @override + State createState() => + _GoToMyLocationMapActionState(); +} + +class _GoToMyLocationMapActionState extends State + with SingleTickerProviderStateMixin { + late final AnimationController rotationController = + AnimationController(vsync: this, duration: 2.seconds); + + void _updateAnimation() { + if (widget.animate) { + rotationController.repeat(); + } else { + rotationController.reset(); + } + } + + @override + void initState() { + super.initState(); + + _updateAnimation(); + } + + @override + void didUpdateWidget(covariant GoToMyLocationMapAction oldWidget) { + super.didUpdateWidget(oldWidget); + + _updateAnimation(); + } + + @override + void dispose() { + rotationController.dispose(); + + super.dispose(); + } + @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); @@ -27,9 +71,9 @@ class GoToMyLocationMapAction extends StatelessWidget { return Tooltip( message: l10n.mapAction_goToCurrentPosition, preferBelow: false, - margin: EdgeInsets.only(bottom: tooltipSpacing), + margin: EdgeInsets.only(bottom: widget.tooltipSpacing), child: SizedBox.square( - dimension: dimension, + dimension: widget.dimension, child: Center( child: PlatformWidget( material: (context, _) => Paper( @@ -38,15 +82,29 @@ class GoToMyLocationMapAction extends StatelessWidget { padding: EdgeInsets.zero, child: IconButton( color: shades[400], - icon: const Icon(Icons.my_location), - onPressed: onGoToMyLocation, + icon: AnimatedBuilder( + animation: rotationController, + builder: (context, child) => Transform.rotate( + angle: rotationController.value * 2 * pi, + child: child, + ), + child: const Icon(Icons.my_location), + ), + onPressed: widget.onGoToMyLocation, ), ), cupertino: (context, _) => CupertinoButton( color: shades[400], padding: EdgeInsets.zero, - onPressed: onGoToMyLocation, - child: const Icon(Icons.my_location), + onPressed: widget.onGoToMyLocation, + child: AnimatedBuilder( + animation: rotationController, + builder: (context, child) => Transform.rotate( + angle: rotationController.value * 2 * pi, + child: child, + ), + child: const Icon(Icons.my_location), + ), ), ), ),