diff --git a/lib/widgets/about/translators.dart b/lib/widgets/about/translators.dart index 2e582a454..37e4641bf 100644 --- a/lib/widgets/about/translators.dart +++ b/lib/widgets/about/translators.dart @@ -51,6 +51,7 @@ class _RandomTextSpanHighlighter extends StatefulWidget { class _RandomTextSpanHighlighterState extends State<_RandomTextSpanHighlighter> with SingleTickerProviderStateMixin { late final AnimationController _controller; + late final CurvedAnimation _animation; late final Animation _animatedStyle; late final TextStyle _baseStyle; int _highlightedIndex = 0; @@ -90,14 +91,16 @@ class _RandomTextSpanHighlighterState extends State<_RandomTextSpanHighlighter> } }) ..repeat(reverse: true); - _animatedStyle = ShadowedTextStyleTween(begin: _baseStyle, end: highlightStyle).animate(CurvedAnimation( + _animation = CurvedAnimation( parent: _controller, curve: Curves.easeInOutCubic, - )); + ); + _animatedStyle = ShadowedTextStyleTween(begin: _baseStyle, end: highlightStyle).animate(_animation); } @override void dispose() { + _animation.dispose(); _controller.dispose(); super.dispose(); } diff --git a/lib/widgets/common/action_controls/quick_choosers/common/button.dart b/lib/widgets/common/action_controls/quick_choosers/common/button.dart index b4d409d1f..5925099b7 100644 --- a/lib/widgets/common/action_controls/quick_choosers/common/button.dart +++ b/lib/widgets/common/action_controls/quick_choosers/common/button.dart @@ -22,7 +22,7 @@ abstract class ChooserQuickButton extends StatefulWidget { abstract class ChooserQuickButtonState, U> extends State with SingleTickerProviderStateMixin { AnimationController? _animationController; - Animation? _animation; + CurvedAnimation? _animation; OverlayEntry? _chooserOverlayEntry; final ValueNotifier _chooserValueNotifier = ValueNotifier(null); final StreamController _moveUpdateStreamController = StreamController.broadcast(); @@ -47,6 +47,7 @@ abstract class ChooserQuickButtonState, U> exten @override void dispose() { + _animation?.dispose(); _animationController?.dispose(); _clearChooserOverlayEntry(); _chooserValueNotifier.dispose(); diff --git a/lib/widgets/common/action_mixins/feedback.dart b/lib/widgets/common/action_mixins/feedback.dart index ad348f983..ef145603f 100644 --- a/lib/widgets/common/action_mixins/feedback.dart +++ b/lib/widgets/common/action_mixins/feedback.dart @@ -178,7 +178,7 @@ class ReportOverlay extends StatefulWidget { class _ReportOverlayState extends State> with SingleTickerProviderStateMixin { final processed = {}; late AnimationController _animationController; - late Animation _animation; + late CurvedAnimation _animation; Stream get opStream => widget.opStream; @@ -212,6 +212,7 @@ class _ReportOverlayState extends State> with SingleTickerPr @override void dispose() { + _animation.dispose(); _animationController.dispose(); super.dispose(); } @@ -317,6 +318,7 @@ class _FeedbackMessage extends StatefulWidget { class _FeedbackMessageState extends State<_FeedbackMessage> with SingleTickerProviderStateMixin { AnimationController? _animationController; + CurvedAnimation? _animation; Animation? _remainingDurationMillis; int? _totalDurationMillis; @@ -333,19 +335,21 @@ class _FeedbackMessageState extends State<_FeedbackMessage> with SingleTickerPro duration: effectiveDuration, vsync: this, ); + _animation = CurvedAnimation( + parent: _animationController!, + curve: Curves.linear, + ); _remainingDurationMillis = IntTween( begin: effectiveDuration.inMilliseconds, end: 0, - ).animate(CurvedAnimation( - parent: _animationController!, - curve: Curves.linear, - )); + ).animate(_animation!); _animationController!.forward(); } } @override void dispose() { + _animation?.dispose(); _animationController?.dispose(); super.dispose(); } diff --git a/lib/widgets/common/action_mixins/overlay_snack_bar.dart b/lib/widgets/common/action_mixins/overlay_snack_bar.dart index 97a71a97c..ed2d5a710 100644 --- a/lib/widgets/common/action_mixins/overlay_snack_bar.dart +++ b/lib/widgets/common/action_mixins/overlay_snack_bar.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; // adapted from Flutter `SnackBar` in `/material/snack_bar.dart` -// As of Flutter v3.0.1, `SnackBar` is not customizable enough to add margin +// As of Flutter v3.23.0, `SnackBar` is not customizable enough to add margin // and ignore pointers in that area, so we use an overlay entry instead. // This overlay entry is not under a `Scaffold` (which is expected by `SnackBar` // and `SnackBarAction`), and is not dismissed the same way. @@ -73,10 +73,17 @@ class OverlaySnackBar extends StatefulWidget { class _OverlaySnackBarState extends State { bool _wasVisible = false; + CurvedAnimation? _heightAnimation; + CurvedAnimation? _fadeInAnimation; + CurvedAnimation? _fadeInM3Animation; + CurvedAnimation? _fadeOutAnimation; + CurvedAnimation? _heightM3Animation; + @override void initState() { super.initState(); widget.animation!.addStatusListener(_onAnimationStatusChanged); + _setAnimations(); } @override @@ -85,26 +92,55 @@ class _OverlaySnackBarState extends State { if (widget.animation != oldWidget.animation) { oldWidget.animation!.removeStatusListener(_onAnimationStatusChanged); widget.animation!.addStatusListener(_onAnimationStatusChanged); + _disposeAnimations(); + _setAnimations(); } } + void _setAnimations() { + assert(widget.animation != null); + _heightAnimation = CurvedAnimation(parent: widget.animation!, curve: _snackBarHeightCurve); + _fadeInAnimation = CurvedAnimation(parent: widget.animation!, curve: _snackBarFadeInCurve); + _fadeInM3Animation = CurvedAnimation(parent: widget.animation!, curve: _snackBarM3FadeInCurve); + _fadeOutAnimation = CurvedAnimation( + parent: widget.animation!, + curve: _snackBarFadeOutCurve, + reverseCurve: const Threshold(0.0), + ); + // Material 3 Animation has a height animation on entry, but a direct fade out on exit. + _heightM3Animation = CurvedAnimation( + parent: widget.animation!, + curve: _snackBarM3HeightCurve, + reverseCurve: const Threshold(0.0), + ); + } + + void _disposeAnimations() { + _heightAnimation?.dispose(); + _fadeInAnimation?.dispose(); + _fadeInM3Animation?.dispose(); + _fadeOutAnimation?.dispose(); + _heightM3Animation?.dispose(); + _heightAnimation = null; + _fadeInAnimation = null; + _fadeInM3Animation = null; + _fadeOutAnimation = null; + _heightM3Animation = null; + } + @override void dispose() { widget.animation!.removeStatusListener(_onAnimationStatusChanged); + _disposeAnimations(); super.dispose(); } void _onAnimationStatusChanged(AnimationStatus animationStatus) { - switch (animationStatus) { - case AnimationStatus.dismissed: - case AnimationStatus.forward: - case AnimationStatus.reverse: - break; - case AnimationStatus.completed: - if (widget.onVisible != null && !_wasVisible) { - widget.onVisible!(); - } - _wasVisible = true; + if (animationStatus == AnimationStatus.completed) { + if (widget.onVisible != null && !_wasVisible) { + widget.onVisible!(); + } + _wasVisible = true; } } @@ -173,28 +209,13 @@ class _OverlaySnackBarState extends State { final double iconHorizontalMargin = (widget.padding?.resolve(TextDirection.ltr).right ?? horizontalPadding) / 12.0; - final CurvedAnimation heightAnimation = CurvedAnimation(parent: widget.animation!, curve: _snackBarHeightCurve); - final CurvedAnimation fadeInAnimation = CurvedAnimation(parent: widget.animation!, curve: _snackBarFadeInCurve); - final CurvedAnimation fadeInM3Animation = CurvedAnimation(parent: widget.animation!, curve: _snackBarM3FadeInCurve); - - final CurvedAnimation fadeOutAnimation = CurvedAnimation( - parent: widget.animation!, - curve: _snackBarFadeOutCurve, - reverseCurve: const Threshold(0.0), - ); - // Material 3 Animation has a height animation on entry, but a direct fade out on exit. - final CurvedAnimation heightM3Animation = CurvedAnimation( - parent: widget.animation!, - curve: _snackBarM3HeightCurve, - reverseCurve: const Threshold(0.0), - ); - final IconButton? iconButton = showCloseIcon ? IconButton( icon: const Icon(Icons.close), iconSize: 24.0, color: widget.closeIconColor ?? snackBarTheme.closeIconColor ?? defaults.closeIconColor, onPressed: () => ScaffoldMessenger.of(context).hideCurrentSnackBar(reason: SnackBarClosedReason.dismiss), + tooltip: MaterialLocalizations.of(context).closeButtonTooltip, ) : null; @@ -253,7 +274,7 @@ class _OverlaySnackBarState extends State { child: accessibleNavigation || theme.useMaterial3 ? snackBar : FadeTransition( - opacity: fadeOutAnimation, + opacity: _fadeOutAnimation!, child: snackBar, ), ), @@ -288,7 +309,7 @@ class _OverlaySnackBarState extends State { key: const Key('dismissible'), direction: widget.dismissDirection, resizeDuration: null, - behavior: widget.hitTestBehavior ?? (widget.margin != null ? HitTestBehavior.deferToChild : HitTestBehavior.opaque), + behavior: widget.hitTestBehavior ?? (widget.margin != null || snackBarTheme.insetPadding != null ? HitTestBehavior.deferToChild : HitTestBehavior.opaque), onDismissed: (direction) => widget.onDismiss(), child: snackBar, ), @@ -299,19 +320,19 @@ class _OverlaySnackBarState extends State { snackBarTransition = snackBar; } else if (isFloatingSnackBar && !theme.useMaterial3) { snackBarTransition = FadeTransition( - opacity: fadeInAnimation, + opacity: _fadeInAnimation!, child: snackBar, ); // Is Material 3 Floating Snack Bar. } else if (isFloatingSnackBar && theme.useMaterial3) { snackBarTransition = FadeTransition( - opacity: fadeInM3Animation, - child: AnimatedBuilder( - animation: heightM3Animation, - builder: (context, child) { + opacity: _fadeInM3Animation!, + child: ValueListenableBuilder( + valueListenable: _heightM3Animation!, + builder: (context, value, child) { return Align( - alignment: AlignmentDirectional.bottomStart, - heightFactor: heightM3Animation.value, + alignment: Alignment.bottomLeft, + heightFactor: value, child: child, ); }, @@ -319,12 +340,12 @@ class _OverlaySnackBarState extends State { ), ); } else { - snackBarTransition = AnimatedBuilder( - animation: heightAnimation, - builder: (context, child) { + snackBarTransition = ValueListenableBuilder( + valueListenable: _heightAnimation!, + builder: (context, value, child) { return Align( alignment: AlignmentDirectional.topStart, - heightFactor: heightAnimation.value, + heightFactor: value, child: child, ); }, diff --git a/lib/widgets/common/basic/draggable_scrollbar/scrollbar.dart b/lib/widgets/common/basic/draggable_scrollbar/scrollbar.dart index 40f91e8bc..eb42528bb 100644 --- a/lib/widgets/common/basic/draggable_scrollbar/scrollbar.dart +++ b/lib/widgets/common/basic/draggable_scrollbar/scrollbar.dart @@ -121,9 +121,9 @@ class _DraggableScrollbarState extends State with TickerProv late Offset _longPressLastGlobalPosition; late AnimationController _thumbAnimationController; - late Animation _thumbAnimation; + late CurvedAnimation _thumbAnimation; late AnimationController _labelAnimationController; - late Animation _labelAnimation; + late CurvedAnimation _labelAnimation; Timer? _fadeoutTimer; Map? _percentCrumbs; final Map _viewportCrumbs = {}; @@ -167,7 +167,9 @@ class _DraggableScrollbarState extends State with TickerProv @override void dispose() { + _thumbAnimation.dispose(); _thumbAnimationController.dispose(); + _labelAnimation.dispose(); _labelAnimationController.dispose(); _fadeoutTimer?.cancel(); super.dispose(); diff --git a/lib/widgets/common/basic/text/animated_diff.dart b/lib/widgets/common/basic/text/animated_diff.dart index a76726e25..fe37d428c 100644 --- a/lib/widgets/common/basic/text/animated_diff.dart +++ b/lib/widgets/common/basic/text/animated_diff.dart @@ -26,7 +26,7 @@ class AnimatedDiffText extends StatefulWidget { class _AnimatedDiffTextState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; - late final Animation _animation; + late final CurvedAnimation _animation; final List<_TextDiff> _diffs = []; TextStyle get _textStyle { @@ -66,6 +66,7 @@ class _AnimatedDiffTextState extends State with SingleTickerPr @override void dispose() { + _animation.dispose(); _controller.dispose(); super.dispose(); } diff --git a/lib/widgets/common/basic/text/change_highlight.dart b/lib/widgets/common/basic/text/change_highlight.dart index eaebecf12..cea4737a2 100644 --- a/lib/widgets/common/basic/text/change_highlight.dart +++ b/lib/widgets/common/basic/text/change_highlight.dart @@ -22,6 +22,7 @@ class ChangeHighlightText extends StatefulWidget { class _ChangeHighlightTextState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; + late final CurvedAnimation _animation; late final Animation _style; @override @@ -33,10 +34,11 @@ class _ChangeHighlightTextState extends State with SingleTi ) ..value = 1 ..addListener(() => setState(() {})); - _style = ShadowedTextStyleTween(begin: widget.changedStyle, end: widget.style).animate(CurvedAnimation( + _animation = CurvedAnimation( parent: _controller, curve: widget.curve, - )); + ); + _style = ShadowedTextStyleTween(begin: widget.changedStyle, end: widget.style).animate(_animation); } @override @@ -51,6 +53,7 @@ class _ChangeHighlightTextState extends State with SingleTi @override void dispose() { + _animation.dispose(); _controller.dispose(); super.dispose(); } diff --git a/lib/widgets/common/fx/sweeper.dart b/lib/widgets/common/fx/sweeper.dart index fc218fa3b..6ed6bdec8 100644 --- a/lib/widgets/common/fx/sweeper.dart +++ b/lib/widgets/common/fx/sweeper.dart @@ -31,6 +31,7 @@ class Sweeper extends StatefulWidget { class _SweeperState extends State with SingleTickerProviderStateMixin { late AnimationController _angleAnimationController; + late CurvedAnimation _angleAnimation; late Animation _angle; bool _isAppearing = false; @@ -46,13 +47,14 @@ class _SweeperState extends State with SingleTickerProviderStateMixin { final startAngle = widget.startAngle; final sweepAngle = widget.sweepAngle; final centerSweep = widget.centerSweep; + _angleAnimation = CurvedAnimation( + parent: _angleAnimationController, + curve: widget.curve, + ); _angle = Tween( begin: startAngle - sweepAngle * (centerSweep ? .5 : 0), end: startAngle + pi * 2 - sweepAngle * (centerSweep ? .5 : 1), - ).animate(CurvedAnimation( - parent: _angleAnimationController, - curve: widget.curve, - )); + ).animate(_angleAnimation); _angleAnimationController.addStatusListener(_onAnimationStatusChanged); _registerWidget(widget); } @@ -66,7 +68,7 @@ class _SweeperState extends State with SingleTickerProviderStateMixin { @override void dispose() { - _angleAnimationController.removeStatusListener(_onAnimationStatusChanged); + _angleAnimation.dispose(); _angleAnimationController.dispose(); _unregisterWidget(widget); super.dispose(); diff --git a/lib/widgets/common/map/leaflet/map.dart b/lib/widgets/common/map/leaflet/map.dart index 901ffe79e..84d87be05 100644 --- a/lib/widgets/common/map/leaflet/map.dart +++ b/lib/widgets/common/map/leaflet/map.dart @@ -286,9 +286,8 @@ class _EntryLeafletMapState extends State> with TickerProv final animation = CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn); controller.addListener(() => animate(animation)); animation.addStatusListener((status) { - if (status == AnimationStatus.completed) { - controller.dispose(); - } else if (status == AnimationStatus.dismissed) { + if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) { + animation.dispose(); controller.dispose(); } }); diff --git a/lib/widgets/editor/transform/cropper.dart b/lib/widgets/editor/transform/cropper.dart index 86447f735..c3abc7338 100644 --- a/lib/widgets/editor/transform/cropper.dart +++ b/lib/widgets/editor/transform/cropper.dart @@ -43,7 +43,7 @@ class _CropperState extends State with SingleTickerProviderStateMixin { final ValueNotifier _outlineNotifier = ValueNotifier(Rect.zero); final ValueNotifier _gridDivisionNotifier = ValueNotifier(0); late AnimationController _gridAnimationController; - late Animation _gridOpacity; + late CurvedAnimation _gridOpacity; static const double minDimension = Cropper.handleDimension; static const int panResizeGridDivision = 3; @@ -87,6 +87,7 @@ class _CropperState extends State with SingleTickerProviderStateMixin { _viewportSizeNotifier.dispose(); _outlineNotifier.dispose(); _gridDivisionNotifier.dispose(); + _gridOpacity.dispose(); _gridAnimationController.dispose(); _unregisterWidget(widget); super.dispose(); diff --git a/lib/widgets/map/map_page.dart b/lib/widgets/map/map_page.dart index 7d44c479a..528db5eb7 100644 --- a/lib/widgets/map/map_page.dart +++ b/lib/widgets/map/map_page.dart @@ -103,7 +103,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin final ValueNotifier _overlayOpacityNotifier = ValueNotifier(1); final ValueNotifier _overlayVisible = ValueNotifier(true); late AnimationController _overlayAnimationController; - late Animation _overlayScale, _scrollerSize; + late CurvedAnimation _overlayScale, _scrollerSize; CoordinateFilter? _regionFilter; CollectionLens? get regionCollection => _regionCollectionNotifier.value; @@ -170,6 +170,8 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin _dotEntryNotifier.dispose(); _overlayOpacityNotifier.dispose(); _overlayVisible.dispose(); + _overlayScale.dispose(); + _scrollerSize.dispose(); _overlayAnimationController.dispose(); // provided collection should be a new instance specifically created diff --git a/lib/widgets/navigation/nav_bar/floating.dart b/lib/widgets/navigation/nav_bar/floating.dart index 2c4f27ad7..63ffb53a4 100644 --- a/lib/widgets/navigation/nav_bar/floating.dart +++ b/lib/widgets/navigation/nav_bar/floating.dart @@ -25,7 +25,8 @@ class FloatingNavBar extends StatefulWidget { class _FloatingNavBarState extends State with SingleTickerProviderStateMixin { final List _subscriptions = []; late AnimationController _controller; - late Animation _offsetAnimation; + late CurvedAnimation _animation; + late Animation _offset; double? _lastOffset; bool _isDragging = false; @@ -36,13 +37,14 @@ class _FloatingNavBarState extends State with SingleTickerProvid duration: const Duration(milliseconds: 200), vsync: this, ); - _offsetAnimation = Tween( - begin: const Offset(0, 0), - end: const Offset(0, 1), - ).animate(CurvedAnimation( + _animation = CurvedAnimation( parent: _controller, curve: Curves.linear, - )) + ); + _offset = Tween( + begin: const Offset(0, 0), + end: const Offset(0, 1), + ).animate(_animation) ..addListener(() { if (!mounted) return; setState(() {}); @@ -63,6 +65,8 @@ class _FloatingNavBarState extends State with SingleTickerProvid @override void dispose() { _unregisterWidget(widget); + _animation.dispose(); + _controller.dispose(); super.dispose(); } @@ -82,7 +86,7 @@ class _FloatingNavBarState extends State with SingleTickerProvid @override Widget build(BuildContext context) { return SlideTransition( - position: _offsetAnimation, + position: _offset, child: widget.child, ); } diff --git a/lib/widgets/viewer/controls/controller.dart b/lib/widgets/viewer/controls/controller.dart index 0ee13ddbd..54bb798f7 100644 --- a/lib/widgets/viewer/controls/controller.dart +++ b/lib/widgets/viewer/controls/controller.dart @@ -22,7 +22,7 @@ class ViewerController with CastMixin { late final ValueNotifier _autopilotNotifier; Timer? _playTimer; final StreamController _streamController = StreamController.broadcast(); - final Map _autopilotAnimationControllers = {}; + final Map _autopilotAnimators = {}; ScaleLevel? _autopilotInitialScale; Stream get _events => _streamController.stream; @@ -94,9 +94,12 @@ class ViewerController with CastMixin { void _stopPlayTimer() => _playTimer?.cancel(); - void _clearAutopilotAnimations() => _autopilotAnimationControllers.keys.toSet().forEach((v) => stopAutopilotAnimation(vsync: v)); + void _clearAutopilotAnimations() => _autopilotAnimators.keys.toSet().forEach((v) => stopAutopilotAnimation(vsync: v)); - void stopAutopilotAnimation({required TickerProvider vsync}) => _autopilotAnimationControllers.remove(vsync)?.dispose(); + void stopAutopilotAnimation({required TickerProvider vsync}) { + final animationController = _autopilotAnimators.remove(vsync); + return animationController?.dispose(); + } void startAutopilotAnimation({ required TickerProvider vsync, @@ -113,16 +116,37 @@ class ViewerController with CastMixin { duration: autopilotInterval, vsync: vsync, ); - animationController.addListener(() => onUpdate.call( - scaleLevel: ScaleLevel( - ref: scaleLevelRef, - factor: scaleFactorTween.evaluate(CurvedAnimation( - parent: animationController, - curve: Curves.linear, - )), - ), - )); - _autopilotAnimationControllers[vsync] = animationController; - Future.delayed(ADurations.viewerHorizontalPageAnimation).then((_) => _autopilotAnimationControllers[vsync]?.forward()); + final animation = CurvedAnimation( + parent: animationController, + curve: Curves.linear, + ); + animationController.addListener(() { + return onUpdate.call( + scaleLevel: ScaleLevel( + ref: scaleLevelRef, + factor: scaleFactorTween.evaluate(animation), + ), + ); + }); + _autopilotAnimators[vsync] = _AutopilotAnimators( + controller: animationController, + animation: animation, + ); + Future.delayed(ADurations.viewerHorizontalPageAnimation).then((_) => _autopilotAnimators[vsync]?.controller.forward()); + } +} + +class _AutopilotAnimators { + final AnimationController controller; + final CurvedAnimation animation; + + _AutopilotAnimators({ + required this.controller, + required this.animation, + }); + + void dispose() { + animation.dispose(); + controller.dispose(); } } diff --git a/lib/widgets/viewer/entry_viewer_stack.dart b/lib/widgets/viewer/entry_viewer_stack.dart index afa511a45..16188cf7d 100644 --- a/lib/widgets/viewer/entry_viewer_stack.dart +++ b/lib/widgets/viewer/entry_viewer_stack.dart @@ -73,7 +73,7 @@ class _EntryViewerStackState extends State with EntryViewContr final ValueNotifier _viewLocked = ValueNotifier(false); final ValueNotifier _overlayExpandedNotifier = ValueNotifier(false); late AnimationController _verticalPageAnimationController, _overlayAnimationController; - late Animation _overlayButtonScale, _overlayVideoControlScale, _overlayOpacity; + late CurvedAnimation _overlayButtonScale, _overlayVideoControlScale, _overlayOpacity, _overlayTopOffsetAnimation; late Animation _overlayTopOffset; EdgeInsets? _frozenViewInsets, _frozenViewPadding; late VideoActionDelegate _videoActionDelegate; @@ -158,10 +158,11 @@ class _EntryViewerStackState extends State with EntryViewContr parent: _overlayAnimationController, curve: Curves.easeOutQuad, ); - _overlayTopOffset = Tween(begin: const Offset(0, -1), end: const Offset(0, 0)).animate(CurvedAnimation( + _overlayTopOffsetAnimation = CurvedAnimation( parent: _overlayAnimationController, curve: Curves.easeOutQuad, - )); + ); + _overlayTopOffset = Tween(begin: const Offset(0, -1), end: const Offset(0, 0)).animate(_overlayTopOffsetAnimation); _overlayVisible.value = settings.showOverlayOnOpening && !viewerController.autopilot; _overlayVisible.addListener(_onOverlayVisibleChanged); _viewLocked.addListener(_onViewLockedChanged); @@ -188,6 +189,10 @@ class _EntryViewerStackState extends State with EntryViewContr cleanEntryControllers(entryNotifier.value); _videoActionDelegate.dispose(); _verticalPageAnimationController.dispose(); + _overlayButtonScale.dispose(); + _overlayVideoControlScale.dispose(); + _overlayOpacity.dispose(); + _overlayTopOffsetAnimation.dispose(); _overlayAnimationController.dispose(); _overlayVisible.dispose(); _viewLocked.dispose(); diff --git a/lib/widgets/viewer/overlay/bottom.dart b/lib/widgets/viewer/overlay/bottom.dart index 728c530d5..9a6024f17 100644 --- a/lib/widgets/viewer/overlay/bottom.dart +++ b/lib/widgets/viewer/overlay/bottom.dart @@ -133,7 +133,7 @@ class _BottomOverlayContent extends StatefulWidget { class _BottomOverlayContentState extends State<_BottomOverlayContent> { final FocusScopeNode _buttonRowFocusScopeNode = FocusScopeNode(); - late Animation _buttonScale, _thumbnailOpacity; + late CurvedAnimation _buttonScale, _thumbnailOpacity; @override void initState() { @@ -170,7 +170,8 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> { } void _unregisterWidget(_BottomOverlayContent widget) { - // nothing + _buttonScale.dispose(); + _thumbnailOpacity.dispose(); } @override diff --git a/lib/widgets/viewer/overlay/locked.dart b/lib/widgets/viewer/overlay/locked.dart index 7c730708a..ed4afe749 100644 --- a/lib/widgets/viewer/overlay/locked.dart +++ b/lib/widgets/viewer/overlay/locked.dart @@ -25,7 +25,7 @@ class ViewerLockedOverlay extends StatefulWidget { } class _ViewerLockedOverlayState extends State { - late Animation _buttonScale; + late CurvedAnimation _buttonScale; @override void initState() { @@ -55,7 +55,7 @@ class _ViewerLockedOverlayState extends State { } void _unregisterWidget(ViewerLockedOverlay widget) { - // nothing + _buttonScale.dispose(); } @override diff --git a/lib/widgets/viewer/overlay/slideshow_buttons.dart b/lib/widgets/viewer/overlay/slideshow_buttons.dart index 5b84cc031..a34af9a6c 100644 --- a/lib/widgets/viewer/overlay/slideshow_buttons.dart +++ b/lib/widgets/viewer/overlay/slideshow_buttons.dart @@ -25,7 +25,7 @@ class SlideshowButtons extends StatefulWidget { class _SlideshowButtonsState extends State { final FocusScopeNode _buttonRowFocusScopeNode = FocusScopeNode(); - late Animation _buttonScale; + late CurvedAnimation _buttonScale; static const List _actions = [ SlideshowAction.resume, @@ -65,7 +65,7 @@ class _SlideshowButtonsState extends State { } void _unregisterWidget(SlideshowButtons widget) { - // nothing + _buttonScale.dispose(); } @override diff --git a/lib/widgets/wallpaper_page.dart b/lib/widgets/wallpaper_page.dart index 56b51a35b..10763ee5a 100644 --- a/lib/widgets/wallpaper_page.dart +++ b/lib/widgets/wallpaper_page.dart @@ -71,7 +71,7 @@ class EntryEditor extends StatefulWidget { class _EntryEditorState extends State with EntryViewControllerMixin, SingleTickerProviderStateMixin { final ValueNotifier _overlayVisible = ValueNotifier(true); late AnimationController _overlayAnimationController; - late Animation _overlayVideoControlScale; + late CurvedAnimation _overlayVideoControlScale; EdgeInsets? _frozenViewInsets, _frozenViewPadding; late VideoActionDelegate _videoActionDelegate; late final ViewerController _viewerController; @@ -120,6 +120,7 @@ class _EntryEditorState extends State with EntryViewControllerMixin void dispose() { cleanEntryControllers(entry); _overlayVisible.dispose(); + _overlayVideoControlScale.dispose(); _overlayAnimationController.dispose(); _videoActionDelegate.dispose(); _viewerController.dispose(); diff --git a/pubspec.yaml b/pubspec.yaml index eca07a22b..290936cf1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -176,7 +176,7 @@ flutter: # and `_PackageLicensePage` in `/material/about.dart` # # `OverlaySnackBar` in `/widgets/common/action_mixins/overlay_snack_bar.dart` -# adapts from Flutter v3.16.0 `SnackBar` in `/material/snack_bar.dart` +# adapts from Flutter v3.23.0 `SnackBar` in `/material/snack_bar.dart` # # `EagerScaleGestureRecognizer` in `/widgets/common/behaviour/eager_scale_gesture_recognizer.dart` # adapts from Flutter v3.16.0 `ScaleGestureRecognizer` in `/gestures/scale.dart`