From 7034690720ec40d308462fb2482e0472e5fc6fee Mon Sep 17 00:00:00 2001 From: MritunjayTiwari14 Date: Wed, 29 Oct 2025 18:20:19 +0530 Subject: [PATCH] button: Replace GestureDetector with Listener for `AnimatedScaleOnTap` Fixes #1953. Latter provides instant scaleDown animation on tap, unlike GestureDetector which has a `kPressTimeOut` causing delay of 100ms https://main-api.flutter.dev/flutter/gestures/kPressTimeout-constant.html --- lib/widgets/button.dart | 8 ++++---- test/widgets/button_test.dart | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/lib/widgets/button.dart b/lib/widgets/button.dart index 1cfb308365..e3e8905f74 100644 --- a/lib/widgets/button.dart +++ b/lib/widgets/button.dart @@ -303,11 +303,11 @@ class _AnimatedScaleOnTapState extends State { @override Widget build(BuildContext context) { - return GestureDetector( + return Listener( behavior: HitTestBehavior.translucent, - onTapDown: (_) => _changeScale(widget.scaleEnd), - onTapUp: (_) => _changeScale(1), - onTapCancel: () => _changeScale(1), + onPointerDown: (_) => _changeScale(widget.scaleEnd), + onPointerUp: (_) => _changeScale(1), + onPointerCancel: (_) => _changeScale(1), child: AnimatedScale( scale: _scale, duration: widget.duration, diff --git a/test/widgets/button_test.dart b/test/widgets/button_test.dart index acbdb9cfac..581895a7fc 100644 --- a/test/widgets/button_test.dart +++ b/test/widgets/button_test.dart @@ -114,6 +114,39 @@ void main() { check(renderObject).size.equals(Size.square(40)); }); + group('AnimatedScaleOnTap', () { + void checkScale(WidgetTester tester, Finder finder, double expectedScale) { + final scale = tester.widget(finder).scale; + check(scale).equals(expectedScale); + } + + testWidgets('Animation happen instantly when tap down', (tester) async { + addTearDown(testBinding.reset); + + await tester.pumpWidget(TestZulipApp( + child: AnimatedScaleOnTap( + scaleEnd: 0.95, + duration: Duration(milliseconds: 100), + child: UnconstrainedBox( + child: ZulipIconButton( + icon: ZulipIcons.follow, + onPressed: () {}))))); + await tester.pump(); + + final animatedScaleFinder = find.byType(AnimatedScale); + + // Now that the widget is being held down, its scale should be at the target scaleEnd i.e 0.95. + final gesture = await tester.startGesture(tester.getCenter(find.byType(ZulipIconButton))); + await tester.pumpAndSettle(); + checkScale(tester, animatedScaleFinder, 0.95); + + // After releasing, the scale must return to 1.0. + await gesture.up(); + await tester.pumpAndSettle(); + checkScale(tester, animatedScaleFinder, 1.0); + }); + }); + // TODO test that the touch feedback fills the whole square }); }