From da1031261f5fa7910c2c9b4aa27a41964d874e5d Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:42:22 +0100 Subject: [PATCH 01/17] add `TickerProvider` to controller --- .../map/controller/map_controller_impl.dart | 20 ++++++++++++++++++- lib/src/map/widget.dart | 5 +++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index 5117be15d..5d40cc155 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -17,11 +17,12 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> late final MapInteractiveViewerState _interactiveViewerState; - MapControllerImpl([MapOptions? options]) + MapControllerImpl({MapOptions? options, TickerProvider? vsync}) : super( _MapControllerState( options: options, camera: options == null ? null : MapCamera.initialCamera(options), + vsync: vsync, ), ); @@ -340,9 +341,14 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> value = _MapControllerState( options: newOptions, camera: newCamera, + vsync: value.vsync, ); } + set vsync(TickerProvider tickerProvider) { + value = value.withVsync(tickerProvider); + } + /// To be called when a gesture that causes movement starts. void moveStarted(MapEventSource source) { _emitMapEvent( @@ -508,6 +514,8 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> ); } + void moveAnimated(LatLng center, double zoom) {} + void _emitMapEvent(MapEvent event) { if (event.source == MapEventSource.mapController && event is MapEventMove) { _interactiveViewerState.interruptAnimatedMovement(event); @@ -529,14 +537,24 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> class _MapControllerState { final MapCamera? camera; final MapOptions? options; + final TickerProvider? vsync; const _MapControllerState({ required this.options, required this.camera, + required this.vsync, }); _MapControllerState withMapCamera(MapCamera camera) => _MapControllerState( options: options, camera: camera, + vsync: vsync, + ); + + _MapControllerState withVsync(TickerProvider tickerProvider) => + _MapControllerState( + options: options, + camera: camera, + vsync: tickerProvider, ); } diff --git a/lib/src/map/widget.dart b/lib/src/map/widget.dart index 76d7291fa..2ae1bc666 100644 --- a/lib/src/map/widget.dart +++ b/lib/src/map/widget.dart @@ -51,7 +51,7 @@ class FlutterMap extends StatefulWidget { } class _FlutterMapStateContainer extends State - with AutomaticKeepAliveClientMixin { + with AutomaticKeepAliveClientMixin, TickerProviderStateMixin { bool _initialCameraFitApplied = false; late MapControllerImpl _mapController; @@ -184,10 +184,11 @@ class _FlutterMapStateContainer extends State void _setMapController() { if (_controllerCreatedInternally) { - _mapController = MapControllerImpl(widget.options); + _mapController = MapControllerImpl(options: widget.options, vsync: this); } else { _mapController = widget.mapController! as MapControllerImpl; _mapController.options = widget.options; + _mapController.vsync = this; } } } From e8e63079d7cd8bbf361bcaaed6900c16431b18c9 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Fri, 8 Dec 2023 00:44:45 +0100 Subject: [PATCH 02/17] use central `AnimationController` --- .../map/controller/map_controller_impl.dart | 124 +++++++++++++----- lib/src/map/widget.dart | 2 +- 2 files changed, 92 insertions(+), 34 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index 5d40cc155..b6d9b8b05 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -17,12 +17,17 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> late final MapInteractiveViewerState _interactiveViewerState; + late Animation _moveAnimation; + late Animation _zoomAnimation; + late Animation _rotationAnimation; + MapControllerImpl({MapOptions? options, TickerProvider? vsync}) : super( _MapControllerState( options: options, camera: options == null ? null : MapCamera.initialCamera(options), - vsync: vsync, + animationController: + vsync == null ? null : AnimationController(vsync: vsync), ), ); @@ -51,6 +56,12 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> 'least once before using the MapController.')); } + AnimationController get animationController { + return value.animationController ?? + (throw Exception('You need to have the FlutterMap widget rendered at ' + 'least once before using the MapController.')); + } + /// This setter should only be called in this class or within tests. Changes /// to the [_MapControllerState] should be done via methods in this class. @visibleForTesting @@ -180,29 +191,27 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> required MapEventSource source, String? id, }) { - if (newRotation != camera.rotation) { - final newCamera = options.cameraConstraint.constrain( - camera.withRotation(newRotation), - ); - if (newCamera == null) return false; + if (newRotation == camera.rotation) return false; - final oldCamera = camera; + final newCamera = options.cameraConstraint.constrain( + camera.withRotation(newRotation), + ); + if (newCamera == null) return false; - // Update camera then emit events and callbacks - value = value.withMapCamera(newCamera); + final oldCamera = camera; - _emitMapEvent( - MapEventRotate( - id: id, - source: source, - oldCamera: oldCamera, - camera: camera, - ), - ); - return true; - } + // Update camera then emit events and callbacks + value = value.withMapCamera(newCamera); - return false; + _emitMapEvent( + MapEventRotate( + id: id, + source: source, + oldCamera: oldCamera, + camera: camera, + ), + ); + return true; } MoveAndRotateResult rotateAroundPointRaw( @@ -341,12 +350,20 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> value = _MapControllerState( options: newOptions, camera: newCamera, - vsync: value.vsync, + animationController: value.animationController, ); } set vsync(TickerProvider tickerProvider) { - value = value.withVsync(tickerProvider); + if (value.animationController == null) { + value = _MapControllerState( + options: value.options, + camera: value.camera, + animationController: AnimationController(vsync: tickerProvider), + ); + } else { + animationController.resync(tickerProvider); + } } /// To be called when a gesture that causes movement starts. @@ -514,7 +531,54 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> ); } - void moveAnimated(LatLng center, double zoom) {} + void moveAndRotateAnimatedRaw( + LatLng newCenter, + double newZoom, + double newRotation, { + required Offset offset, + required bool hasGesture, + required MapEventSource source, + }) { + if (newRotation == camera.rotation && + newCenter == camera.center && + newZoom == camera.zoom) return; + // TODO + } + + void moveAnimatedRaw( + LatLng newCenter, + double newZoom, { + Offset offset = Offset.zero, + Duration duration = const Duration(milliseconds: 500), + required Curve curve, + required bool hasGesture, + required MapEventSource source, + }) { + // cancel all ongoing animation + if (animationController.isAnimating) animationController.stop(); + + // create the new animation + _moveAnimation = LatLngTween(begin: camera.center, end: newCenter) + .chain(CurveTween(curve: curve)) + .animate(animationController); + _zoomAnimation = Tween(begin: camera.zoom, end: newZoom) + .chain(CurveTween(curve: curve)) + .animate(animationController); + + animationController.duration = duration; + animationController.addListener(() { + moveRaw( + _moveAnimation!.value, + _zoomAnimation!.value, + hasGesture: hasGesture, + source: MapEventSource.mapController, + offset: offset, + ); + }); + + // start the animation from its start + animationController.forward(from: 0); + } void _emitMapEvent(MapEvent event) { if (event.source == MapEventSource.mapController && event is MapEventMove) { @@ -529,6 +593,7 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> @override void dispose() { _mapEventStreamController.close(); + value.animationController?.dispose(); super.dispose(); } } @@ -537,24 +602,17 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> class _MapControllerState { final MapCamera? camera; final MapOptions? options; - final TickerProvider? vsync; + final AnimationController? animationController; const _MapControllerState({ required this.options, required this.camera, - required this.vsync, + required this.animationController, }); _MapControllerState withMapCamera(MapCamera camera) => _MapControllerState( options: options, camera: camera, - vsync: vsync, - ); - - _MapControllerState withVsync(TickerProvider tickerProvider) => - _MapControllerState( - options: options, - camera: camera, - vsync: tickerProvider, + animationController: animationController, ); } diff --git a/lib/src/map/widget.dart b/lib/src/map/widget.dart index 2ae1bc666..958f0cdb9 100644 --- a/lib/src/map/widget.dart +++ b/lib/src/map/widget.dart @@ -187,8 +187,8 @@ class _FlutterMapStateContainer extends State _mapController = MapControllerImpl(options: widget.options, vsync: this); } else { _mapController = widget.mapController! as MapControllerImpl; - _mapController.options = widget.options; _mapController.vsync = this; + _mapController.options = widget.options; } } } From b32278b5c73a78f60f1c83c857bdf5389cd4714e Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Fri, 8 Dec 2023 01:03:41 +0100 Subject: [PATCH 03/17] implement `moveAndRotateAnimated()` --- .../map/controller/map_controller_impl.dart | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index b6d9b8b05..09c06e43d 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -536,24 +536,56 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> double newZoom, double newRotation, { required Offset offset, + required Duration duration, + required Curve curve, required bool hasGesture, required MapEventSource source, }) { if (newRotation == camera.rotation && newCenter == camera.center && newZoom == camera.zoom) return; - // TODO + + // cancel all ongoing animation + if (animationController.isAnimating) animationController.stop(); + + // create the new animation + _moveAnimation = LatLngTween(begin: camera.center, end: newCenter) + .chain(CurveTween(curve: curve)) + .animate(animationController); + _zoomAnimation = Tween(begin: camera.zoom, end: newZoom) + .chain(CurveTween(curve: curve)) + .animate(animationController); + _rotationAnimation = Tween(begin: camera.rotation, end: newRotation) + .chain(CurveTween(curve: curve)) + .animate(animationController); + + animationController.duration = duration; + animationController.addListener(() { + moveAndRotateRaw( + _moveAnimation.value, + _zoomAnimation.value, + _rotationAnimation.value, + hasGesture: hasGesture, + source: MapEventSource.mapController, + offset: offset, + ); + }); + + // start the animation from its start + animationController.forward(from: 0); } void moveAnimatedRaw( LatLng newCenter, double newZoom, { Offset offset = Offset.zero, - Duration duration = const Duration(milliseconds: 500), + required Duration duration, required Curve curve, required bool hasGesture, required MapEventSource source, }) { + if (newCenter == camera.center && newZoom == camera.zoom) return; + // cancel all ongoing animation if (animationController.isAnimating) animationController.stop(); @@ -568,8 +600,8 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> animationController.duration = duration; animationController.addListener(() { moveRaw( - _moveAnimation!.value, - _zoomAnimation!.value, + _moveAnimation.value, + _zoomAnimation.value, hasGesture: hasGesture, source: MapEventSource.mapController, offset: offset, From 27d4096bf422f0b5d6962a140ed298886dc38e1e Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Sun, 10 Dec 2023 23:42:19 +0100 Subject: [PATCH 04/17] add fling and stop function --- .../map/controller/map_controller_impl.dart | 66 ++++++++++++++----- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index 09c06e43d..143b1a0f1 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -20,6 +20,7 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> late Animation _moveAnimation; late Animation _zoomAnimation; late Animation _rotationAnimation; + late Animation _flingAnimation; MapControllerImpl({MapOptions? options, TickerProvider? vsync}) : super( @@ -56,7 +57,7 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> 'least once before using the MapController.')); } - AnimationController get animationController { + AnimationController get _animationController { return value.animationController ?? (throw Exception('You need to have the FlutterMap widget rendered at ' 'least once before using the MapController.')); @@ -362,7 +363,7 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> animationController: AnimationController(vsync: tickerProvider), ); } else { - animationController.resync(tickerProvider); + _animationController.resync(tickerProvider); } } @@ -546,21 +547,21 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> newZoom == camera.zoom) return; // cancel all ongoing animation - if (animationController.isAnimating) animationController.stop(); + if (_animationController.isAnimating) _animationController.stop(); // create the new animation _moveAnimation = LatLngTween(begin: camera.center, end: newCenter) .chain(CurveTween(curve: curve)) - .animate(animationController); + .animate(_animationController); _zoomAnimation = Tween(begin: camera.zoom, end: newZoom) .chain(CurveTween(curve: curve)) - .animate(animationController); + .animate(_animationController); _rotationAnimation = Tween(begin: camera.rotation, end: newRotation) .chain(CurveTween(curve: curve)) - .animate(animationController); + .animate(_animationController); - animationController.duration = duration; - animationController.addListener(() { + _animationController.duration = duration; + _animationController.addListener(() { moveAndRotateRaw( _moveAnimation.value, _zoomAnimation.value, @@ -572,7 +573,42 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> }); // start the animation from its start - animationController.forward(from: 0); + _animationController.forward(from: 0); + } + + void stopAnimationRaw() => _animationController.stop(); + + void flingAnimatedRaw({ + required double velocity, + required Offset direction, + required Offset offset, + double mass = 1, + double stiffness = 1000, + double ratio = 5, + }) { + if (!InteractiveFlag.hasFlingAnimation(options.interactionOptions.flags)) { + return; + } + if (_animationController.isAnimating) _animationController.stop(); + + final distance = + (Offset.zero & Size(camera.nonRotatedSize.x, camera.nonRotatedSize.y)) + .shortestSide; + + _flingAnimation = Tween( + begin: offset, + end: offset - direction * distance, + ).animate(_animationController); + + _animationController.value = 0; + _animationController.fling( + velocity: velocity, + springDescription: SpringDescription.withDampingRatio( + mass: mass, + stiffness: stiffness, + ratio: ratio, + ), + ); } void moveAnimatedRaw( @@ -587,18 +623,18 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> if (newCenter == camera.center && newZoom == camera.zoom) return; // cancel all ongoing animation - if (animationController.isAnimating) animationController.stop(); + if (_animationController.isAnimating) _animationController.stop(); // create the new animation _moveAnimation = LatLngTween(begin: camera.center, end: newCenter) .chain(CurveTween(curve: curve)) - .animate(animationController); + .animate(_animationController); _zoomAnimation = Tween(begin: camera.zoom, end: newZoom) .chain(CurveTween(curve: curve)) - .animate(animationController); + .animate(_animationController); - animationController.duration = duration; - animationController.addListener(() { + _animationController.duration = duration; + _animationController.addListener(() { moveRaw( _moveAnimation.value, _zoomAnimation.value, @@ -609,7 +645,7 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> }); // start the animation from its start - animationController.forward(from: 0); + _animationController.forward(from: 0); } void _emitMapEvent(MapEvent event) { From bdb5f45aef4d96b5e969d4fffa993a42c55a664d Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Mon, 11 Dec 2023 00:53:45 +0100 Subject: [PATCH 05/17] register listeners only a single time --- .../map/controller/map_controller_impl.dart | 72 ++++++++++++------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index 143b1a0f1..6fee06338 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -17,10 +17,13 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> late final MapInteractiveViewerState _interactiveViewerState; - late Animation _moveAnimation; - late Animation _zoomAnimation; - late Animation _rotationAnimation; - late Animation _flingAnimation; + Animation? _moveAnimation; + Animation? _zoomAnimation; + Animation? _rotationAnimation; + Animation? _flingAnimation; + late bool _animationHasGesture; + late Offset _animationOffset; + late Point _flingMapCenterStartPoint; MapControllerImpl({MapOptions? options, TickerProvider? vsync}) : super( @@ -30,7 +33,10 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> animationController: vsync == null ? null : AnimationController(vsync: vsync), ), - ); + ) { + value.animationController?.addListener(_handleAnimation); + value.animationController?.addStatusListener(_handleAnimationStatus); + } /// Link the viewer state with the controller. This should be done once when /// the FlutterMapInteractiveViewerState is initialized. @@ -360,7 +366,9 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> value = _MapControllerState( options: value.options, camera: value.camera, - animationController: AnimationController(vsync: tickerProvider), + animationController: AnimationController(vsync: tickerProvider) + ..addListener(_handleAnimation) + ..addStatusListener(_handleAnimationStatus), ); } else { _animationController.resync(tickerProvider); @@ -561,16 +569,8 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> .animate(_animationController); _animationController.duration = duration; - _animationController.addListener(() { - moveAndRotateRaw( - _moveAnimation.value, - _zoomAnimation.value, - _rotationAnimation.value, - hasGesture: hasGesture, - source: MapEventSource.mapController, - offset: offset, - ); - }); + _animationHasGesture = hasGesture; + _animationOffset = offset; // start the animation from its start _animationController.forward(from: 0); @@ -590,6 +590,8 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> return; } if (_animationController.isAnimating) _animationController.stop(); + _animationHasGesture = true; + _flingMapCenterStartPoint = camera.project(camera.center); final distance = (Offset.zero & Size(camera.nonRotatedSize.x, camera.nonRotatedSize.y)) @@ -634,15 +636,8 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> .animate(_animationController); _animationController.duration = duration; - _animationController.addListener(() { - moveRaw( - _moveAnimation.value, - _zoomAnimation.value, - hasGesture: hasGesture, - source: MapEventSource.mapController, - offset: offset, - ); - }); + _animationHasGesture = hasGesture; + _animationOffset = offset; // start the animation from its start _animationController.forward(from: 0); @@ -658,6 +653,33 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> _mapEventSink.add(event); } + void _handleAnimation() { + if (_flingAnimation != null) { + final newCenterPoint = _flingMapCenterStartPoint + + _flingAnimation!.value.toPoint().rotate(camera.rotationRad); + moveRaw( + camera.unproject(newCenterPoint), + camera.zoom, + hasGesture: true, + source: MapEventSource.flingAnimationController, + ); + } + + moveAndRotateRaw( + _moveAnimation?.value ?? camera.center, + _zoomAnimation?.value ?? camera.zoom, + _rotationAnimation?.value ?? camera.rotation, + hasGesture: _animationHasGesture, + source: MapEventSource.mapController, + offset: _animationOffset, + ); + } + + void _handleAnimationStatus(AnimationStatus status) { + const endStates = [AnimationStatus.completed, AnimationStatus.dismissed]; + if (!endStates.contains(status)) return; + } + @override void dispose() { _mapEventStreamController.close(); From 1afe8dbdea735912eb15cee25e1834157fe897bb Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Mon, 11 Dec 2023 01:06:32 +0100 Subject: [PATCH 06/17] clean up --- .../map/controller/map_controller_impl.dart | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index 6fee06338..7d1c93d43 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -581,7 +581,8 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> void flingAnimatedRaw({ required double velocity, required Offset direction, - required Offset offset, + required Offset begin, + Offset offset = Offset.zero, double mass = 1, double stiffness = 1000, double ratio = 5, @@ -591,6 +592,7 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> } if (_animationController.isAnimating) _animationController.stop(); _animationHasGesture = true; + _animationOffset = offset; _flingMapCenterStartPoint = camera.project(camera.center); final distance = @@ -598,8 +600,8 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> .shortestSide; _flingAnimation = Tween( - begin: offset, - end: offset - direction * distance, + begin: begin, + end: begin - direction * distance, ).animate(_animationController); _animationController.value = 0; @@ -654,25 +656,39 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> } void _handleAnimation() { + // fling animation if (_flingAnimation != null) { final newCenterPoint = _flingMapCenterStartPoint + _flingAnimation!.value.toPoint().rotate(camera.rotationRad); moveRaw( camera.unproject(newCenterPoint), camera.zoom, - hasGesture: true, + hasGesture: _animationHasGesture, source: MapEventSource.flingAnimationController, + offset: _animationOffset, ); + return; } - moveAndRotateRaw( - _moveAnimation?.value ?? camera.center, - _zoomAnimation?.value ?? camera.zoom, - _rotationAnimation?.value ?? camera.rotation, - hasGesture: _animationHasGesture, - source: MapEventSource.mapController, - offset: _animationOffset, - ); + // animated movement + if (_rotationAnimation != null) { + moveAndRotateRaw( + _moveAnimation?.value ?? camera.center, + _zoomAnimation?.value ?? camera.zoom, + _rotationAnimation?.value ?? camera.rotation, + hasGesture: _animationHasGesture, + source: MapEventSource.mapController, + offset: _animationOffset, + ); + } else { + moveRaw( + _moveAnimation?.value ?? camera.center, + _zoomAnimation?.value ?? camera.zoom, + hasGesture: _animationHasGesture, + source: MapEventSource.mapController, + offset: _animationOffset, + ); + } } void _handleAnimationStatus(AnimationStatus status) { From b11e319bbf6787604f6b454f158ac4a26f30c3f5 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Mon, 11 Dec 2023 01:13:42 +0100 Subject: [PATCH 07/17] sneaky change to codecov --- codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index 8a7e33b11..494a22c0a 100644 --- a/codecov.yml +++ b/codecov.yml @@ -4,7 +4,7 @@ codecov: project: default: target: 0% - threshold: 0% + threshold: 100% ignore: - "**/*.g.dart" From 26b59590a5f18609a28afad6f97eab2d2ff2e690 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Mon, 11 Dec 2023 01:37:22 +0100 Subject: [PATCH 08/17] dont rotate if rotation is 0 --- lib/src/map/controller/map_controller_impl.dart | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index 7d1c93d43..44e502213 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -550,9 +550,18 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> required bool hasGesture, required MapEventSource source, }) { - if (newRotation == camera.rotation && - newCenter == camera.center && - newZoom == camera.zoom) return; + if (newRotation == camera.rotation) { + moveAnimatedRaw( + newCenter, + newZoom, + duration: duration, + curve: curve, + hasGesture: hasGesture, + source: source, + ); + return; + } + if (newCenter == camera.center && newZoom == camera.zoom) return; // cancel all ongoing animation if (_animationController.isAnimating) _animationController.stop(); From 72f330b725352e81ba86d2bb89e833fd49eedfcd Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:12:08 +0100 Subject: [PATCH 09/17] clean up --- lib/src/map/controller/map_controller_impl.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index 44e502213..d6f05a590 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -595,12 +595,10 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> double mass = 1, double stiffness = 1000, double ratio = 5, + required bool hasGesture, }) { - if (!InteractiveFlag.hasFlingAnimation(options.interactionOptions.flags)) { - return; - } if (_animationController.isAnimating) _animationController.stop(); - _animationHasGesture = true; + _animationHasGesture = hasGesture; _animationOffset = offset; _flingMapCenterStartPoint = camera.project(camera.center); From 6e11baf5230f9643982e4ef8f587ccbd3a40c405 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 12 Dec 2023 01:01:35 +0100 Subject: [PATCH 10/17] fix reset animation --- .../map/controller/map_controller_impl.dart | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index d6f05a590..82e49aa75 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -35,7 +35,6 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> ), ) { value.animationController?.addListener(_handleAnimation); - value.animationController?.addStatusListener(_handleAnimationStatus); } /// Link the viewer state with the controller. This should be done once when @@ -367,8 +366,7 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> options: value.options, camera: value.camera, animationController: AnimationController(vsync: tickerProvider) - ..addListener(_handleAnimation) - ..addStatusListener(_handleAnimationStatus), + ..addListener(_handleAnimation), ); } else { _animationController.resync(tickerProvider); @@ -561,10 +559,11 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> ); return; } - if (newCenter == camera.center && newZoom == camera.zoom) return; - // cancel all ongoing animation - if (_animationController.isAnimating) _animationController.stop(); + _animationController.stop(); + _resetAnimations(); + + if (newCenter == camera.center && newZoom == camera.zoom) return; // create the new animation _moveAnimation = LatLngTween(begin: camera.center, end: newCenter) @@ -585,7 +584,18 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> _animationController.forward(from: 0); } - void stopAnimationRaw() => _animationController.stop(); + void stopAnimationRaw({bool canceled = true}) { + if (_animationController.isAnimating) { + _animationController.stop(canceled: canceled); + } + } + + void _resetAnimations() { + _moveAnimation = null; + _rotationAnimation = null; + _zoomAnimation = null; + _flingAnimation = null; + } void flingAnimatedRaw({ required double velocity, @@ -597,7 +607,10 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> double ratio = 5, required bool hasGesture, }) { - if (_animationController.isAnimating) _animationController.stop(); + // cancel all ongoing animation + _animationController.stop(); + _resetAnimations(); + _animationHasGesture = hasGesture; _animationOffset = offset; _flingMapCenterStartPoint = camera.project(camera.center); @@ -631,10 +644,11 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> required bool hasGesture, required MapEventSource source, }) { - if (newCenter == camera.center && newZoom == camera.zoom) return; - // cancel all ongoing animation - if (_animationController.isAnimating) _animationController.stop(); + _animationController.stop(); + _resetAnimations(); + + if (newCenter == camera.center && newZoom == camera.zoom) return; // create the new animation _moveAnimation = LatLngTween(begin: camera.center, end: newCenter) @@ -698,11 +712,6 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> } } - void _handleAnimationStatus(AnimationStatus status) { - const endStates = [AnimationStatus.completed, AnimationStatus.dismissed]; - if (!endStates.contains(status)) return; - } - @override void dispose() { _mapEventStreamController.close(); From 12a36848e7497ecedd353ac0bb002a82f620a042 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 12 Dec 2023 01:04:58 +0100 Subject: [PATCH 11/17] clean up --- lib/src/map/controller/map_controller_impl.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index 82e49aa75..c75085d45 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -696,7 +696,7 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> moveAndRotateRaw( _moveAnimation?.value ?? camera.center, _zoomAnimation?.value ?? camera.zoom, - _rotationAnimation?.value ?? camera.rotation, + _rotationAnimation!.value, hasGesture: _animationHasGesture, source: MapEventSource.mapController, offset: _animationOffset, From af9bb8d6e10c490daabeb05dfa632171e5f7b153 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 12 Dec 2023 01:21:30 +0100 Subject: [PATCH 12/17] add `rotateAnimatedRaw`, `isAnimating` --- .../map/controller/map_controller_impl.dart | 69 +++++++++++++++---- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/lib/src/map/controller/map_controller_impl.dart b/lib/src/map/controller/map_controller_impl.dart index c75085d45..a618ae67a 100644 --- a/lib/src/map/controller/map_controller_impl.dart +++ b/lib/src/map/controller/map_controller_impl.dart @@ -584,12 +584,39 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> _animationController.forward(from: 0); } + void rotateAnimatedRaw( + double newRotation, { + required Offset offset, + required Duration duration, + required Curve curve, + required bool hasGesture, + required MapEventSource source, + }) { + // cancel all ongoing animation + _animationController.stop(); + _resetAnimations(); + + if (newRotation == camera.rotation) return; + + // create the new animation + _rotationAnimation = Tween(begin: camera.rotation, end: newRotation) + .chain(CurveTween(curve: curve)) + .animate(_animationController); + + _animationController.duration = duration; + _animationHasGesture = hasGesture; + _animationOffset = offset; + + // start the animation from its start + _animationController.forward(from: 0); + } + void stopAnimationRaw({bool canceled = true}) { - if (_animationController.isAnimating) { - _animationController.stop(canceled: canceled); - } + if (isAnimating) _animationController.stop(canceled: canceled); } + bool get isAnimating => _animationController.isAnimating; + void _resetAnimations() { _moveAnimation = null; _rotationAnimation = null; @@ -692,22 +719,34 @@ class MapControllerImpl extends ValueNotifier<_MapControllerState> } // animated movement + if (_moveAnimation != null) { + if (_rotationAnimation != null) { + moveAndRotateRaw( + _moveAnimation?.value ?? camera.center, + _zoomAnimation?.value ?? camera.zoom, + _rotationAnimation!.value, + hasGesture: _animationHasGesture, + source: MapEventSource.mapController, + offset: _animationOffset, + ); + } else { + moveRaw( + _moveAnimation!.value, + _zoomAnimation?.value ?? camera.zoom, + hasGesture: _animationHasGesture, + source: MapEventSource.mapController, + offset: _animationOffset, + ); + } + return; + } + + // animated rotation if (_rotationAnimation != null) { - moveAndRotateRaw( - _moveAnimation?.value ?? camera.center, - _zoomAnimation?.value ?? camera.zoom, + rotateRaw( _rotationAnimation!.value, hasGesture: _animationHasGesture, source: MapEventSource.mapController, - offset: _animationOffset, - ); - } else { - moveRaw( - _moveAnimation?.value ?? camera.center, - _zoomAnimation?.value ?? camera.zoom, - hasGesture: _animationHasGesture, - source: MapEventSource.mapController, - offset: _animationOffset, ); } } From 7dcd22e3373b59a5e9a39070e91cd8fd6b3f13aa Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 12 Dec 2023 01:25:20 +0100 Subject: [PATCH 13/17] sneaky fix to codecov --- codecov.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/codecov.yml b/codecov.yml index 494a22c0a..069a104c3 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,14 +1,16 @@ codecov: require_ci_to_pass: true + +coverage: status: project: default: + # the required coverage value target: 0% + # the leniency in hitting the target threshold: 100% ignore: - "**/*.g.dart" - "example" - - "benchmark" - -comment: false \ No newline at end of file + - "benchmark" \ No newline at end of file From acdd919f68bf78ce2ccac50805367608a7fb8ce3 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 12 Dec 2023 01:32:25 +0100 Subject: [PATCH 14/17] Update codecov.yml --- codecov.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/codecov.yml b/codecov.yml index 069a104c3..4d5856c9c 100644 --- a/codecov.yml +++ b/codecov.yml @@ -9,6 +9,11 @@ coverage: target: 0% # the leniency in hitting the target threshold: 100% + patch: + # the required coverage value + target: 0% + # the leniency in hitting the target + threshold: 100% ignore: - "**/*.g.dart" From 17635474d5308f744c25a330faa094ac1a0dbe69 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 12 Dec 2023 01:40:46 +0100 Subject: [PATCH 15/17] Update codecov.yml --- codecov.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/codecov.yml b/codecov.yml index 4d5856c9c..65763892f 100644 --- a/codecov.yml +++ b/codecov.yml @@ -9,11 +9,11 @@ coverage: target: 0% # the leniency in hitting the target threshold: 100% - patch: - # the required coverage value - target: 0% - # the leniency in hitting the target - threshold: 100% + patch: + # the required coverage value + target: 0% + # the leniency in hitting the target + threshold: 100% ignore: - "**/*.g.dart" From 22db560d0526e18cce3cab636b0d7c808526ab2d Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 12 Dec 2023 01:43:22 +0100 Subject: [PATCH 16/17] Update codecov.yml --- codecov.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/codecov.yml b/codecov.yml index 65763892f..89035d1a0 100644 --- a/codecov.yml +++ b/codecov.yml @@ -10,10 +10,11 @@ coverage: # the leniency in hitting the target threshold: 100% patch: - # the required coverage value - target: 0% - # the leniency in hitting the target - threshold: 100% + default: + # the required coverage value + target: 0% + # the leniency in hitting the target + threshold: 100% ignore: - "**/*.g.dart" From 8f61c733b1fee1bdffb9098a7e13e2bd1765d28e Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 12 Dec 2023 13:45:27 +0100 Subject: [PATCH 17/17] disable patch warnings --- codecov.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/codecov.yml b/codecov.yml index 89035d1a0..1ede16543 100644 --- a/codecov.yml +++ b/codecov.yml @@ -9,12 +9,7 @@ coverage: target: 0% # the leniency in hitting the target threshold: 100% - patch: - default: - # the required coverage value - target: 0% - # the leniency in hitting the target - threshold: 100% + patch: off ignore: - "**/*.g.dart"