Add mouseCursor
parameter to Chip
s (#159422)
Part of https://github.com/flutter/flutter/issues/58192 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Victor Sanni <victorsanniay@gmail.com>
This commit is contained in:
parent
a9ed692396
commit
628ab7f493
@ -120,6 +120,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
||||
this.iconTheme,
|
||||
this.avatarBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.flat;
|
||||
@ -156,6 +157,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
||||
this.iconTheme,
|
||||
this.avatarBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.elevated;
|
||||
@ -208,6 +210,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
@override
|
||||
final ChipAnimationStyle? chipAnimationStyle;
|
||||
@override
|
||||
final MouseCursor? mouseCursor;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onPressed != null;
|
||||
@ -247,6 +251,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
||||
iconTheme: iconTheme,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
chipAnimationStyle: chipAnimationStyle,
|
||||
mouseCursor: mouseCursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -278,6 +278,19 @@ abstract interface class ChipAttributes {
|
||||
/// ** See code in examples/api/lib/material/chip/chip_attributes.chip_animation_style.0.dart **
|
||||
/// {@end-tool}
|
||||
ChipAnimationStyle? get chipAnimationStyle;
|
||||
|
||||
/// The cursor for a mouse pointer when it enters or is hovering over the
|
||||
/// widget.
|
||||
///
|
||||
/// If [mouseCursor] is a [WidgetStateMouseCursor],
|
||||
/// [WidgetStateProperty.resolve] is used for the following [WidgetState]s:
|
||||
///
|
||||
/// * [WidgetState.hovered].
|
||||
/// * [WidgetState.focused].
|
||||
/// * [WidgetState.disabled].
|
||||
///
|
||||
/// If this property is null, [WidgetStateMouseCursor.clickable] will be used.
|
||||
MouseCursor? get mouseCursor;
|
||||
}
|
||||
|
||||
/// An interface for Material Design chips that can be deleted.
|
||||
@ -704,6 +717,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(elevation == null || elevation >= 0.0);
|
||||
|
||||
@override
|
||||
@ -756,6 +770,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
@override
|
||||
final ChipAnimationStyle? chipAnimationStyle;
|
||||
@override
|
||||
final MouseCursor? mouseCursor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -787,6 +803,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
chipAnimationStyle: chipAnimationStyle,
|
||||
mouseCursor: mouseCursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -877,6 +894,7 @@ class RawChip extends StatefulWidget
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
deleteIcon = deleteIcon ?? _kDefaultDeleteIcon;
|
||||
@ -962,6 +980,8 @@ class RawChip extends StatefulWidget
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
@override
|
||||
final ChipAnimationStyle? chipAnimationStyle;
|
||||
@override
|
||||
final MouseCursor? mouseCursor;
|
||||
|
||||
/// If set, this indicates that the chip should be disabled if all of the
|
||||
/// tap callbacks ([onSelected], [onPressed]) are null.
|
||||
@ -1407,6 +1427,7 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
|
||||
onTapDown: canTap ? _handleTapDown : null,
|
||||
onTapCancel: canTap ? _handleTapCancel : null,
|
||||
onHover: canTap ? updateMaterialState(MaterialState.hovered) : null,
|
||||
mouseCursor: widget.mouseCursor,
|
||||
hoverColor: (widget.color ?? chipTheme.color) == null ? null : Colors.transparent,
|
||||
customBorder: resolvedShape,
|
||||
child: AnimatedBuilder(
|
||||
|
@ -101,6 +101,7 @@ class ChoiceChip extends StatelessWidget
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
this.avatarBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.flat;
|
||||
@ -143,6 +144,7 @@ class ChoiceChip extends StatelessWidget
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
this.avatarBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.elevated;
|
||||
@ -207,6 +209,8 @@ class ChoiceChip extends StatelessWidget
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
@override
|
||||
final ChipAnimationStyle? chipAnimationStyle;
|
||||
@override
|
||||
final MouseCursor? mouseCursor;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onSelected != null;
|
||||
@ -253,6 +257,7 @@ class ChoiceChip extends StatelessWidget
|
||||
iconTheme: iconTheme,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
chipAnimationStyle: chipAnimationStyle,
|
||||
mouseCursor: mouseCursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ class FilterChip extends StatelessWidget
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.flat;
|
||||
@ -160,6 +161,7 @@ class FilterChip extends StatelessWidget
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.elevated;
|
||||
@ -234,6 +236,8 @@ class FilterChip extends StatelessWidget
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
@override
|
||||
final ChipAnimationStyle? chipAnimationStyle;
|
||||
@override
|
||||
final MouseCursor? mouseCursor;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onSelected != null;
|
||||
@ -286,6 +290,7 @@ class FilterChip extends StatelessWidget
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
chipAnimationStyle: chipAnimationStyle,
|
||||
mouseCursor: mouseCursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ class InputChip extends StatelessWidget
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
this.chipAnimationStyle,
|
||||
this.mouseCursor,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0);
|
||||
|
||||
@ -209,6 +210,8 @@ class InputChip extends StatelessWidget
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
@override
|
||||
final ChipAnimationStyle? chipAnimationStyle;
|
||||
@override
|
||||
final MouseCursor? mouseCursor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -257,6 +260,7 @@ class InputChip extends StatelessWidget
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
chipAnimationStyle: chipAnimationStyle,
|
||||
mouseCursor: mouseCursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -516,7 +516,7 @@ void main() {
|
||||
home: Center(
|
||||
child: CupertinoCheckbox(
|
||||
value: value,
|
||||
onChanged: enabled ? (bool? value) => true : null,
|
||||
onChanged: enabled ? (bool? value) {} : null,
|
||||
mouseCursor: const _CheckboxMouseCursor(),
|
||||
focusNode: focusNode
|
||||
),
|
||||
|
@ -2,7 +2,11 @@
|
||||
// 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/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// Adds the basic requirements for a Chip.
|
||||
@ -529,4 +533,77 @@ void main() {
|
||||
|
||||
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||
});
|
||||
|
||||
testWidgets('ActionChip mouse cursor behavior', (WidgetTester tester) async {
|
||||
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
|
||||
|
||||
await tester.pumpWidget(wrapForChip(
|
||||
child: const Center(
|
||||
child: ActionChip(
|
||||
mouseCursor: customCursor,
|
||||
label: Text('Chip'),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
await gesture.addPointer(location: const Offset(10, 10));
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
SystemMouseCursors.basic,
|
||||
);
|
||||
|
||||
final Offset chip = tester.getCenter(find.text('Chip'));
|
||||
await gesture.moveTo(chip);
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
customCursor,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
|
||||
addTearDown(focusNode.dispose);
|
||||
|
||||
Widget buildChip({ required bool enabled }) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: ActionChip(
|
||||
mouseCursor: const WidgetStateMouseCursor.fromMap(
|
||||
<WidgetStatesConstraint, MouseCursor>{
|
||||
WidgetState.disabled: SystemMouseCursors.forbidden,
|
||||
WidgetState.focused: SystemMouseCursors.grab,
|
||||
WidgetState.any: SystemMouseCursors.basic,
|
||||
},
|
||||
),
|
||||
focusNode: focusNode,
|
||||
label: const Text('Chip'),
|
||||
onPressed: enabled ? () {} : null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildChip(enabled: true));
|
||||
|
||||
// Unfocused case.
|
||||
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
addTearDown(gesture1.removePointer);
|
||||
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
|
||||
await tester.pump();
|
||||
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
|
||||
|
||||
// Focused case.
|
||||
focusNode.requestFocus();
|
||||
await tester.pump();
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
|
||||
|
||||
// Disabled case.
|
||||
await tester.pumpWidget(buildChip(enabled: false));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
|
||||
});
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import '../widgets/feedback_tester.dart';
|
||||
import '../widgets/semantics_tester.dart';
|
||||
@ -6082,6 +6083,61 @@ void main() {
|
||||
isNot(paints..rrect(color: hoverColor)..rect(color: themeDataHoverColor)),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Chip mouse cursor behavior', (WidgetTester tester) async {
|
||||
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
|
||||
|
||||
await tester.pumpWidget(wrapForChip(
|
||||
child: const Center(
|
||||
child: Chip(
|
||||
mouseCursor: customCursor,
|
||||
label: Text('Chip'),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
await gesture.addPointer(location: const Offset(10, 10));
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
SystemMouseCursors.basic,
|
||||
);
|
||||
|
||||
final Offset chip = tester.getCenter(find.text('Chip'));
|
||||
await gesture.moveTo(chip);
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
customCursor,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Mouse cursor resolves in disabled states', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrapForChip(
|
||||
child: const Center(
|
||||
child: Chip(
|
||||
mouseCursor: WidgetStateMouseCursor.fromMap(
|
||||
<WidgetStatesConstraint, MouseCursor>{
|
||||
WidgetState.disabled: SystemMouseCursors.forbidden,
|
||||
},
|
||||
),
|
||||
label: Text('Chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
// Unfocused case.
|
||||
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
addTearDown(gesture1.removePointer);
|
||||
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
|
||||
await tester.pump();
|
||||
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
|
||||
});
|
||||
}
|
||||
|
||||
class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {
|
||||
|
@ -2,7 +2,11 @@
|
||||
// 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/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
RenderBox getMaterialBox(WidgetTester tester, Finder type) {
|
||||
@ -813,4 +817,79 @@ void main() {
|
||||
|
||||
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||
});
|
||||
|
||||
testWidgets('ChoiceChip mouse cursor behavior', (WidgetTester tester) async {
|
||||
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
|
||||
|
||||
await tester.pumpWidget(wrapForChip(
|
||||
child: const Center(
|
||||
child: ChoiceChip(
|
||||
selected: false,
|
||||
mouseCursor: customCursor,
|
||||
label: Text('Chip'),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
await gesture.addPointer(location: const Offset(10, 10));
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
SystemMouseCursors.basic,
|
||||
);
|
||||
|
||||
final Offset chip = tester.getCenter(find.text('Chip'));
|
||||
await gesture.moveTo(chip);
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
customCursor,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
|
||||
addTearDown(focusNode.dispose);
|
||||
|
||||
Widget buildChip({ required bool enabled }) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: ChoiceChip(
|
||||
mouseCursor: const WidgetStateMouseCursor.fromMap(
|
||||
<WidgetStatesConstraint, MouseCursor>{
|
||||
WidgetState.disabled: SystemMouseCursors.forbidden,
|
||||
WidgetState.focused: SystemMouseCursors.grab,
|
||||
WidgetState.selected: SystemMouseCursors.click,
|
||||
WidgetState.any: SystemMouseCursors.basic,
|
||||
},
|
||||
),
|
||||
focusNode: focusNode,
|
||||
label: const Text('Chip'),
|
||||
onSelected: enabled ? (bool value) {} : null,
|
||||
selected: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Unfocused case.
|
||||
await tester.pumpWidget(buildChip(enabled: true));
|
||||
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
addTearDown(gesture1.removePointer);
|
||||
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
|
||||
await tester.pump();
|
||||
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
|
||||
|
||||
// Focused case.
|
||||
focusNode.requestFocus();
|
||||
await tester.pump();
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
|
||||
|
||||
// Disabled case.
|
||||
await tester.pumpWidget(buildChip(enabled: false));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
|
||||
});
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ library;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../widgets/feedback_tester.dart';
|
||||
@ -1324,4 +1326,78 @@ void main() {
|
||||
|
||||
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||
});
|
||||
|
||||
testWidgets('FilterChip mouse cursor behavior', (WidgetTester tester) async {
|
||||
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
|
||||
|
||||
await tester.pumpWidget(wrapForChip(
|
||||
child: Center(
|
||||
child: FilterChip(
|
||||
mouseCursor: customCursor,
|
||||
label: const Text('Chip'),
|
||||
onSelected: (bool value) {},
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
await gesture.addPointer(location: const Offset(10, 10));
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
SystemMouseCursors.basic,
|
||||
);
|
||||
|
||||
final Offset chip = tester.getCenter(find.text('Chip'));
|
||||
await gesture.moveTo(chip);
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
customCursor,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
|
||||
addTearDown(focusNode.dispose);
|
||||
|
||||
Widget buildChip({ required bool enabled }) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: FilterChip(
|
||||
mouseCursor: const WidgetStateMouseCursor.fromMap(
|
||||
<WidgetStatesConstraint, MouseCursor>{
|
||||
WidgetState.disabled: SystemMouseCursors.forbidden,
|
||||
WidgetState.focused: SystemMouseCursors.grab,
|
||||
WidgetState.selected: SystemMouseCursors.click,
|
||||
WidgetState.any: SystemMouseCursors.basic,
|
||||
},
|
||||
),
|
||||
focusNode: focusNode,
|
||||
label: const Text('Chip'),
|
||||
onSelected: enabled ? (bool value) {} : null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Unfocused case.
|
||||
await tester.pumpWidget(buildChip(enabled: true));
|
||||
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
addTearDown(gesture1.removePointer);
|
||||
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
|
||||
await tester.pump();
|
||||
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
|
||||
|
||||
// Focused case.
|
||||
focusNode.requestFocus();
|
||||
await tester.pump();
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
|
||||
|
||||
// Disabled case.
|
||||
await tester.pumpWidget(buildChip(enabled: false));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
|
||||
});
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ library;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// Adds the basic requirements for a Chip.
|
||||
@ -617,4 +619,77 @@ void main() {
|
||||
|
||||
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||
});
|
||||
|
||||
testWidgets('InputChip mouse cursor behavior', (WidgetTester tester) async {
|
||||
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
|
||||
|
||||
await tester.pumpWidget(wrapForChip(
|
||||
child: const Center(
|
||||
child: InputChip(
|
||||
mouseCursor: customCursor,
|
||||
label: Text('Chip'),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
await gesture.addPointer(location: const Offset(10, 10));
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
SystemMouseCursors.basic,
|
||||
);
|
||||
|
||||
final Offset chip = tester.getCenter(find.text('Chip'));
|
||||
await gesture.moveTo(chip);
|
||||
await tester.pump();
|
||||
expect(
|
||||
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||
customCursor,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
|
||||
addTearDown(focusNode.dispose);
|
||||
|
||||
Widget buildChip({ required bool enabled }) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: InputChip(
|
||||
mouseCursor: const WidgetStateMouseCursor.fromMap(
|
||||
<WidgetStatesConstraint, MouseCursor>{
|
||||
WidgetState.disabled: SystemMouseCursors.forbidden,
|
||||
WidgetState.focused: SystemMouseCursors.grab,
|
||||
WidgetState.selected: SystemMouseCursors.click,
|
||||
WidgetState.any: SystemMouseCursors.basic,
|
||||
},
|
||||
),
|
||||
focusNode: focusNode,
|
||||
label: const Text('Chip'),
|
||||
onSelected: enabled ? (bool value) {} : null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Unfocused case.
|
||||
await tester.pumpWidget(buildChip(enabled: true));
|
||||
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||
addTearDown(gesture1.removePointer);
|
||||
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
|
||||
await tester.pump();
|
||||
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
|
||||
|
||||
// Focused case.
|
||||
focusNode.requestFocus();
|
||||
await tester.pump();
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
|
||||
|
||||
// Disabled case.
|
||||
await tester.pumpWidget(buildChip(enabled: false));
|
||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user