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.iconTheme,
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.flat;
|
_chipVariant = _ChipVariant.flat;
|
||||||
@ -156,6 +157,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||||||
this.iconTheme,
|
this.iconTheme,
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.elevated;
|
_chipVariant = _ChipVariant.elevated;
|
||||||
@ -208,6 +210,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||||||
final BoxConstraints? avatarBoxConstraints;
|
final BoxConstraints? avatarBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final ChipAnimationStyle? chipAnimationStyle;
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
@override
|
||||||
|
final MouseCursor? mouseCursor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isEnabled => onPressed != null;
|
bool get isEnabled => onPressed != null;
|
||||||
@ -247,6 +251,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||||||
iconTheme: iconTheme,
|
iconTheme: iconTheme,
|
||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
chipAnimationStyle: chipAnimationStyle,
|
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 **
|
/// ** See code in examples/api/lib/material/chip/chip_attributes.chip_animation_style.0.dart **
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
ChipAnimationStyle? get chipAnimationStyle;
|
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.
|
/// An interface for Material Design chips that can be deleted.
|
||||||
@ -704,6 +717,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(elevation == null || elevation >= 0.0);
|
}) : assert(elevation == null || elevation >= 0.0);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -756,6 +770,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||||||
final BoxConstraints? deleteIconBoxConstraints;
|
final BoxConstraints? deleteIconBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final ChipAnimationStyle? chipAnimationStyle;
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
@override
|
||||||
|
final MouseCursor? mouseCursor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -787,6 +803,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||||
chipAnimationStyle: chipAnimationStyle,
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
mouseCursor: mouseCursor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -877,6 +894,7 @@ class RawChip extends StatefulWidget
|
|||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
deleteIcon = deleteIcon ?? _kDefaultDeleteIcon;
|
deleteIcon = deleteIcon ?? _kDefaultDeleteIcon;
|
||||||
@ -962,6 +980,8 @@ class RawChip extends StatefulWidget
|
|||||||
final BoxConstraints? deleteIconBoxConstraints;
|
final BoxConstraints? deleteIconBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final ChipAnimationStyle? chipAnimationStyle;
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
@override
|
||||||
|
final MouseCursor? mouseCursor;
|
||||||
|
|
||||||
/// If set, this indicates that the chip should be disabled if all of the
|
/// If set, this indicates that the chip should be disabled if all of the
|
||||||
/// tap callbacks ([onSelected], [onPressed]) are null.
|
/// tap callbacks ([onSelected], [onPressed]) are null.
|
||||||
@ -1407,6 +1427,7 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
|
|||||||
onTapDown: canTap ? _handleTapDown : null,
|
onTapDown: canTap ? _handleTapDown : null,
|
||||||
onTapCancel: canTap ? _handleTapCancel : null,
|
onTapCancel: canTap ? _handleTapCancel : null,
|
||||||
onHover: canTap ? updateMaterialState(MaterialState.hovered) : null,
|
onHover: canTap ? updateMaterialState(MaterialState.hovered) : null,
|
||||||
|
mouseCursor: widget.mouseCursor,
|
||||||
hoverColor: (widget.color ?? chipTheme.color) == null ? null : Colors.transparent,
|
hoverColor: (widget.color ?? chipTheme.color) == null ? null : Colors.transparent,
|
||||||
customBorder: resolvedShape,
|
customBorder: resolvedShape,
|
||||||
child: AnimatedBuilder(
|
child: AnimatedBuilder(
|
||||||
|
@ -101,6 +101,7 @@ class ChoiceChip extends StatelessWidget
|
|||||||
this.avatarBorder = const CircleBorder(),
|
this.avatarBorder = const CircleBorder(),
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.flat;
|
_chipVariant = _ChipVariant.flat;
|
||||||
@ -143,6 +144,7 @@ class ChoiceChip extends StatelessWidget
|
|||||||
this.avatarBorder = const CircleBorder(),
|
this.avatarBorder = const CircleBorder(),
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.elevated;
|
_chipVariant = _ChipVariant.elevated;
|
||||||
@ -207,6 +209,8 @@ class ChoiceChip extends StatelessWidget
|
|||||||
final BoxConstraints? avatarBoxConstraints;
|
final BoxConstraints? avatarBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final ChipAnimationStyle? chipAnimationStyle;
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
@override
|
||||||
|
final MouseCursor? mouseCursor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isEnabled => onSelected != null;
|
bool get isEnabled => onSelected != null;
|
||||||
@ -253,6 +257,7 @@ class ChoiceChip extends StatelessWidget
|
|||||||
iconTheme: iconTheme,
|
iconTheme: iconTheme,
|
||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
chipAnimationStyle: chipAnimationStyle,
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
mouseCursor: mouseCursor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,7 @@ class FilterChip extends StatelessWidget
|
|||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.flat;
|
_chipVariant = _ChipVariant.flat;
|
||||||
@ -160,6 +161,7 @@ class FilterChip extends StatelessWidget
|
|||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.elevated;
|
_chipVariant = _ChipVariant.elevated;
|
||||||
@ -234,6 +236,8 @@ class FilterChip extends StatelessWidget
|
|||||||
final BoxConstraints? deleteIconBoxConstraints;
|
final BoxConstraints? deleteIconBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final ChipAnimationStyle? chipAnimationStyle;
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
@override
|
||||||
|
final MouseCursor? mouseCursor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isEnabled => onSelected != null;
|
bool get isEnabled => onSelected != null;
|
||||||
@ -286,6 +290,7 @@ class FilterChip extends StatelessWidget
|
|||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||||
chipAnimationStyle: chipAnimationStyle,
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
mouseCursor: mouseCursor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,7 @@ class InputChip extends StatelessWidget
|
|||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
this.chipAnimationStyle,
|
this.chipAnimationStyle,
|
||||||
|
this.mouseCursor,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0);
|
assert(elevation == null || elevation >= 0.0);
|
||||||
|
|
||||||
@ -209,6 +210,8 @@ class InputChip extends StatelessWidget
|
|||||||
final BoxConstraints? deleteIconBoxConstraints;
|
final BoxConstraints? deleteIconBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final ChipAnimationStyle? chipAnimationStyle;
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
@override
|
||||||
|
final MouseCursor? mouseCursor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -257,6 +260,7 @@ class InputChip extends StatelessWidget
|
|||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||||
chipAnimationStyle: chipAnimationStyle,
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
mouseCursor: mouseCursor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,7 +516,7 @@ void main() {
|
|||||||
home: Center(
|
home: Center(
|
||||||
child: CupertinoCheckbox(
|
child: CupertinoCheckbox(
|
||||||
value: value,
|
value: value,
|
||||||
onChanged: enabled ? (bool? value) => true : null,
|
onChanged: enabled ? (bool? value) {} : null,
|
||||||
mouseCursor: const _CheckboxMouseCursor(),
|
mouseCursor: const _CheckboxMouseCursor(),
|
||||||
focusNode: focusNode
|
focusNode: focusNode
|
||||||
),
|
),
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
/// Adds the basic requirements for a Chip.
|
/// Adds the basic requirements for a Chip.
|
||||||
@ -529,4 +533,77 @@ void main() {
|
|||||||
|
|
||||||
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
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/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import '../widgets/feedback_tester.dart';
|
import '../widgets/feedback_tester.dart';
|
||||||
import '../widgets/semantics_tester.dart';
|
import '../widgets/semantics_tester.dart';
|
||||||
@ -6082,6 +6083,61 @@ void main() {
|
|||||||
isNot(paints..rrect(color: hoverColor)..rect(color: themeDataHoverColor)),
|
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 {
|
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
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
RenderBox getMaterialBox(WidgetTester tester, Finder type) {
|
RenderBox getMaterialBox(WidgetTester tester, Finder type) {
|
||||||
@ -813,4 +817,79 @@ void main() {
|
|||||||
|
|
||||||
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
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/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import '../widgets/feedback_tester.dart';
|
import '../widgets/feedback_tester.dart';
|
||||||
@ -1324,4 +1326,78 @@ void main() {
|
|||||||
|
|
||||||
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
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/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
/// Adds the basic requirements for a Chip.
|
/// Adds the basic requirements for a Chip.
|
||||||
@ -617,4 +619,77 @@ void main() {
|
|||||||
|
|
||||||
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
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