Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions lib/widgets/button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,11 @@ class _AnimatedScaleOnTapState extends State<AnimatedScaleOnTap> {

@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),
Comment on lines +306 to +310
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From reading the docs for GestureDetector.onTapDown and friends, it looks like one of the helpful features of that higher-level API is that it only considers pointer events from a "primary button". I don't know how common it is e.g. to use a stylus with multiple buttons, but this seems like functionality that would be helpful to keep.

The event passed to the Listener.onPointerDown callback (etc.) has a buttons field. So in each of the handlers, let's check whether the event's buttons field equals kPrimaryButton, and only respond if it does.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the name and dartdoc of this AnimatedScaleOnTap should be updated to match the new behavior: it's no longer about a tap gesture, which is only recognized after 100ms. For example:

/// Apply [Transform.scale] to the child widget on primary pointer-down,
/// and reset its scale on -up or -cancel, with animated transitions.
class AnimatedScaleOnPointerDown extends StatefulWidget {

child: AnimatedScale(
scale: _scale,
duration: widget.duration,
Expand Down
33 changes: 33 additions & 0 deletions test/widgets/button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<AnimatedScale>(finder).scale;
check(scale).equals(expectedScale);
}

testWidgets('Animation happen instantly when tap down', (tester) async {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I run this test without your change in lib/widgets/button.dart, it still passes. That means it's not doing its job.

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
});
}