From 591cc39c2dcec1c8ddb764b2fc822e663880a785 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Wed, 2 Oct 2024 01:15:53 +0200 Subject: [PATCH] Add WidgetStateMouseCursor example and tests for it. (#155552) Fixes https://github.com/flutter/flutter/issues/155551 ### Description - Adds example for `WidgetStateMouseCursor` - Adds tests for `examples/api/lib/widgets/widget_state/widget_state_mouse_cursor.0.dart` --- .../widget_state_mouse_cursor.0.dart | 85 +++++++++++++++++++ .../widget_state_mouse_cursor.0_test.dart | 71 ++++++++++++++++ .../flutter/lib/src/widgets/widget_state.dart | 2 +- 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 examples/api/lib/widgets/widget_state/widget_state_mouse_cursor.0.dart create mode 100644 examples/api/test/widgets/widget_state/widget_state_mouse_cursor.0_test.dart diff --git a/examples/api/lib/widgets/widget_state/widget_state_mouse_cursor.0.dart b/examples/api/lib/widgets/widget_state/widget_state_mouse_cursor.0.dart new file mode 100644 index 0000000000..4786367608 --- /dev/null +++ b/examples/api/lib/widgets/widget_state/widget_state_mouse_cursor.0.dart @@ -0,0 +1,85 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Flutter code sample for [WidgetStateMouseCursor]. + +void main() { + runApp(const WidgetStateMouseCursorExampleApp()); +} + +class WidgetStateMouseCursorExampleApp extends StatelessWidget { + const WidgetStateMouseCursorExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('WidgetStateMouseCursor Sample')), + body: const WidgetStateMouseCursorExample(), + ), + ); + } +} + +class ListTileCursor extends WidgetStateMouseCursor { + const ListTileCursor(); + + @override + MouseCursor resolve(Set states) { + if (states.contains(WidgetState.disabled)) { + return SystemMouseCursors.forbidden; + } + + return SystemMouseCursors.click; + } + + @override + String get debugDescription => 'ListTileCursor()'; +} + +class WidgetStateMouseCursorExample extends StatefulWidget { + const WidgetStateMouseCursorExample({super.key}); + + @override + State createState() => _WidgetStateMouseCursorExampleState(); +} + +class _WidgetStateMouseCursorExampleState extends State { + bool _enabled = false; + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ListTile( + title: const Text('ListTile'), + enabled: _enabled, + onTap: () {}, + mouseCursor: const ListTileCursor(), + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Enabled: ', + style: Theme.of(context).textTheme.titleSmall, + ), + Switch( + value: _enabled, + onChanged: (_) { + setState(() { + _enabled = !_enabled; + }); + }, + ), + ], + ), + ], + ); + } +} diff --git a/examples/api/test/widgets/widget_state/widget_state_mouse_cursor.0_test.dart b/examples/api/test/widgets/widget_state/widget_state_mouse_cursor.0_test.dart new file mode 100644 index 0000000000..11034b8d9a --- /dev/null +++ b/examples/api/test/widgets/widget_state/widget_state_mouse_cursor.0_test.dart @@ -0,0 +1,71 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_api_samples/widgets/widget_state/widget_state_mouse_cursor.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('ListTile displays correct mouse cursor when disabled', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WidgetStateMouseCursorExampleApp(), + ); + + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer( + location: tester.getCenter(find.byType(ListTile)), + ); + addTearDown(gesture.removePointer); + + expect( + RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), + SystemMouseCursors.forbidden, + ); + }); + + testWidgets('Switch enables ListTile', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WidgetStateMouseCursorExampleApp(), + ); + + ListTile listTile = tester.widget(find.byType(ListTile)); + expect(listTile.enabled, isFalse); + + // Enable ListTile using Switch. + await tester.tap(find.byType(Switch)); + await tester.pumpAndSettle(); + + listTile = tester.widget(find.byType(ListTile)); + expect(listTile.enabled, isTrue); + }); + + testWidgets('ListTile displays correct mouse cursor when enabled', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WidgetStateMouseCursorExampleApp(), + ); + + // Enable ListTile using Switch. + await tester.tap(find.byType(Switch)); + await tester.pumpAndSettle(); + + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer( + location: tester.getCenter(find.byType(ListTile)), + ); + addTearDown(gesture.removePointer); + + expect( + RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), + SystemMouseCursors.click, + ); + }); +} diff --git a/packages/flutter/lib/src/widgets/widget_state.dart b/packages/flutter/lib/src/widgets/widget_state.dart index 0cd809def4..da08d4a9a0 100644 --- a/packages/flutter/lib/src/widgets/widget_state.dart +++ b/packages/flutter/lib/src/widgets/widget_state.dart @@ -390,7 +390,7 @@ class _WidgetStateColorMapper extends _WidgetStateColorTransparent { /// This example defines a mouse cursor that resolves to /// [SystemMouseCursors.forbidden] when its widget is disabled. /// -/// ** See code in examples/api/lib/material/material_state/material_state_mouse_cursor.0.dart ** +/// ** See code in examples/api/lib/widgets/widget_state/widget_state_mouse_cursor.0.dart ** /// {@end-tool} /// /// This class should only be used for parameters which are documented to take