From 4b902c79ce0cc8765dbcc2f93aa368f5760e7c04 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Sat, 5 Mar 2022 01:31:16 +0200 Subject: [PATCH] CupertinoButton: Add clickable cursor on web (#96863) --- .../flutter/lib/src/cupertino/button.dart | 77 ++++++++++--------- .../flutter/test/cupertino/button_test.dart | 29 +++++++ 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/button.dart b/packages/flutter/lib/src/cupertino/button.dart index 57e3139fa9f..468bc186cf4 100644 --- a/packages/flutter/lib/src/cupertino/button.dart +++ b/packages/flutter/lib/src/cupertino/button.dart @@ -245,43 +245,46 @@ class _CupertinoButtonState extends State with SingleTickerProv final TextStyle textStyle = themeData.textTheme.textStyle.copyWith(color: foregroundColor); - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTapDown: enabled ? _handleTapDown : null, - onTapUp: enabled ? _handleTapUp : null, - onTapCancel: enabled ? _handleTapCancel : null, - onTap: widget.onPressed, - child: Semantics( - button: true, - child: ConstrainedBox( - constraints: widget.minSize == null - ? const BoxConstraints() - : BoxConstraints( - minWidth: widget.minSize!, - minHeight: widget.minSize!, - ), - child: FadeTransition( - opacity: _opacityAnimation, - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: widget.borderRadius, - color: backgroundColor != null && !enabled - ? CupertinoDynamicColor.resolve(widget.disabledColor, context) - : backgroundColor, - ), - child: Padding( - padding: widget.padding ?? (backgroundColor != null - ? _kBackgroundButtonPadding - : _kButtonPadding), - child: Align( - alignment: widget.alignment, - widthFactor: 1.0, - heightFactor: 1.0, - child: DefaultTextStyle( - style: textStyle, - child: IconTheme( - data: IconThemeData(color: foregroundColor), - child: widget.child, + return MouseRegion( + cursor: enabled && kIsWeb ? SystemMouseCursors.click : MouseCursor.defer, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: enabled ? _handleTapDown : null, + onTapUp: enabled ? _handleTapUp : null, + onTapCancel: enabled ? _handleTapCancel : null, + onTap: widget.onPressed, + child: Semantics( + button: true, + child: ConstrainedBox( + constraints: widget.minSize == null + ? const BoxConstraints() + : BoxConstraints( + minWidth: widget.minSize!, + minHeight: widget.minSize!, + ), + child: FadeTransition( + opacity: _opacityAnimation, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: widget.borderRadius, + color: backgroundColor != null && !enabled + ? CupertinoDynamicColor.resolve(widget.disabledColor, context) + : backgroundColor, + ), + child: Padding( + padding: widget.padding ?? (backgroundColor != null + ? _kBackgroundButtonPadding + : _kButtonPadding), + child: Align( + alignment: widget.alignment, + widthFactor: 1.0, + heightFactor: 1.0, + child: DefaultTextStyle( + style: textStyle, + child: IconTheme( + data: IconThemeData(color: foregroundColor), + child: widget.child, + ), ), ), ), diff --git a/packages/flutter/test/cupertino/button_test.dart b/packages/flutter/test/cupertino/button_test.dart index 3d6d6173cf4..d8737661e93 100644 --- a/packages/flutter/test/cupertino/button_test.dart +++ b/packages/flutter/test/cupertino/button_test.dart @@ -3,6 +3,8 @@ // found in the LICENSE file. import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -451,6 +453,33 @@ void main() { ).decoration as BoxDecoration; expect(decoration.color, isSameColorAs(CupertinoColors.systemBlue.darkColor)); }); + + testWidgets('Hovering over Cupertino button updates cursor to clickable on Web', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoButton.filled( + onPressed: () { }, + child: const Text('Tap me'), + ), + ), + ), + ); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); + await gesture.addPointer(location: const Offset(10, 10)); + await tester.pumpAndSettle(); + expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); + + final Offset button = tester.getCenter(find.byType(CupertinoButton)); + await gesture.moveTo(button); + addTearDown(gesture.removePointer); + await tester.pumpAndSettle(); + expect( + RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), + kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic, + ); + }); } Widget boilerplate({ required Widget child }) {