mirror of
https://github.com/flutter/flutter
synced 2024-08-28 04:21:14 +00:00
Migrated Checkbox
to Material 3 Colors (#110537)
This commit is contained in:
parent
c213fd9b9c
commit
a490a6a11d
|
@ -20,6 +20,7 @@ import 'dart:io';
|
|||
import 'package:gen_defaults/app_bar_template.dart';
|
||||
import 'package:gen_defaults/button_template.dart';
|
||||
import 'package:gen_defaults/card_template.dart';
|
||||
import 'package:gen_defaults/checkbox_template.dart';
|
||||
import 'package:gen_defaults/chip_action_template.dart';
|
||||
import 'package:gen_defaults/chip_filter_template.dart';
|
||||
import 'package:gen_defaults/chip_input_template.dart';
|
||||
|
@ -108,6 +109,7 @@ Future<void> main(List<String> args) async {
|
|||
ButtonTemplate('md.comp.outlined-button', 'OutlinedButton', '$materialLib/outlined_button.dart', tokens).updateFile();
|
||||
ButtonTemplate('md.comp.text-button', 'TextButton', '$materialLib/text_button.dart', tokens).updateFile();
|
||||
CardTemplate('Card', '$materialLib/card.dart', tokens).updateFile();
|
||||
CheckboxTemplate('Checkbox', '$materialLib/checkbox.dart', tokens).updateFile();
|
||||
ChipActionTemplate('ActionChip', '$materialLib/chip_action.dart', tokens).updateFile();
|
||||
ChipFilterTemplate('FilterChip', '$materialLib/chip_filter.dart', tokens).updateFile();
|
||||
ChipFilterTemplate('FilterChip', '$materialLib/chip_choice.dart', tokens).updateFile();
|
||||
|
|
119
dev/tools/gen_defaults/lib/checkbox_template.dart
Normal file
119
dev/tools/gen_defaults/lib/checkbox_template.dart
Normal file
|
@ -0,0 +1,119 @@
|
|||
// 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 'template.dart';
|
||||
|
||||
class CheckboxTemplate extends TokenTemplate {
|
||||
const CheckboxTemplate(super.blockName, super.fileName, super.tokens, {
|
||||
super.colorSchemePrefix = '_colors.',
|
||||
});
|
||||
|
||||
@override
|
||||
String generate() => '''
|
||||
class _${blockName}DefaultsM3 extends CheckboxThemeData {
|
||||
_${blockName}DefaultsM3(BuildContext context)
|
||||
: _theme = Theme.of(context),
|
||||
_colors = Theme.of(context).colorScheme;
|
||||
|
||||
final ThemeData _theme;
|
||||
final ColorScheme _colors;
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color> get fillColor {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.disabled.container')};
|
||||
}
|
||||
return ${componentColor('md.comp.checkbox.unselected.disabled.outline')}.withOpacity(${opacity('md.comp.checkbox.unselected.disabled.container.opacity')});
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.pressed.container')};
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.hover.container')};
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.focus.container')};
|
||||
}
|
||||
return ${componentColor('md.comp.checkbox.selected.container')};
|
||||
}
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return ${componentColor('md.comp.checkbox.unselected.pressed.outline')};
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return ${componentColor('md.comp.checkbox.unselected.hover.outline')};
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return ${componentColor('md.comp.checkbox.unselected.focus.outline')};
|
||||
}
|
||||
return ${componentColor('md.comp.checkbox.unselected.outline')};
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color> get checkColor {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.disabled.icon')};
|
||||
}
|
||||
return Colors.transparent; // No icons available when the checkbox is unselected.
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.pressed.icon')};
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.hover.icon')};
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.focus.icon')};
|
||||
}
|
||||
return ${componentColor('md.comp.checkbox.selected.icon')};
|
||||
}
|
||||
return Colors.transparent; // No icons available when the checkbox is unselected.
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color> get overlayColor {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.pressed.state-layer')};
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.hover.state-layer')};
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return ${componentColor('md.comp.checkbox.selected.focus.state-layer')};
|
||||
}
|
||||
return Colors.transparent;
|
||||
}
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return ${componentColor('md.comp.checkbox.unselected.pressed.state-layer')};
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return ${componentColor('md.comp.checkbox.unselected.hover.state-layer')};
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return ${componentColor('md.comp.checkbox.unselected.focus.state-layer')};
|
||||
}
|
||||
return Colors.transparent;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
double get splashRadius => ${tokens['md.comp.checkbox.state-layer.size']} / 2;
|
||||
|
||||
@override
|
||||
MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize;
|
||||
|
||||
@override
|
||||
VisualDensity get visualDensity => _theme.visualDensity;
|
||||
}
|
||||
''';
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'checkbox_theme.dart';
|
||||
import 'color_scheme.dart';
|
||||
import 'colors.dart';
|
||||
import 'constants.dart';
|
||||
import 'debug.dart';
|
||||
import 'material_state.dart';
|
||||
|
@ -383,19 +385,6 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
|
|||
});
|
||||
}
|
||||
|
||||
MaterialStateProperty<Color> get _defaultFillColor {
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
return themeData.disabledColor;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return themeData.colorScheme.secondary;
|
||||
}
|
||||
return themeData.unselectedWidgetColor;
|
||||
});
|
||||
}
|
||||
|
||||
BorderSide? _resolveSide(BorderSide? side) {
|
||||
if (side is MaterialStateBorderSide) {
|
||||
return MaterialStateProperty.resolveAs<BorderSide?>(side, states);
|
||||
|
@ -409,14 +398,16 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final CheckboxThemeData checkboxTheme = CheckboxTheme.of(context);
|
||||
final CheckboxThemeData defaults = Theme.of(context).useMaterial3
|
||||
? _CheckboxDefaultsM3(context)
|
||||
: _CheckboxDefaultsM2(context);
|
||||
final MaterialTapTargetSize effectiveMaterialTapTargetSize = widget.materialTapTargetSize
|
||||
?? checkboxTheme.materialTapTargetSize
|
||||
?? themeData.materialTapTargetSize;
|
||||
?? defaults.materialTapTargetSize!;
|
||||
final VisualDensity effectiveVisualDensity = widget.visualDensity
|
||||
?? checkboxTheme.visualDensity
|
||||
?? themeData.visualDensity;
|
||||
?? defaults.visualDensity!;
|
||||
Size size;
|
||||
switch (effectiveMaterialTapTargetSize) {
|
||||
case MaterialTapTargetSize.padded:
|
||||
|
@ -438,40 +429,48 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
|
|||
// so that they can be lerped between.
|
||||
final Set<MaterialState> activeStates = states..add(MaterialState.selected);
|
||||
final Set<MaterialState> inactiveStates = states..remove(MaterialState.selected);
|
||||
final Color effectiveActiveColor = widget.fillColor?.resolve(activeStates)
|
||||
final Color? activeColor = widget.fillColor?.resolve(activeStates)
|
||||
?? _widgetFillColor.resolve(activeStates)
|
||||
?? checkboxTheme.fillColor?.resolve(activeStates)
|
||||
?? _defaultFillColor.resolve(activeStates);
|
||||
final Color effectiveInactiveColor = widget.fillColor?.resolve(inactiveStates)
|
||||
?? checkboxTheme.fillColor?.resolve(activeStates);
|
||||
final Color effectiveActiveColor = activeColor
|
||||
?? defaults.fillColor!.resolve(activeStates)!;
|
||||
final Color? inactiveColor = widget.fillColor?.resolve(inactiveStates)
|
||||
?? _widgetFillColor.resolve(inactiveStates)
|
||||
?? checkboxTheme.fillColor?.resolve(inactiveStates)
|
||||
?? _defaultFillColor.resolve(inactiveStates);
|
||||
?? checkboxTheme.fillColor?.resolve(inactiveStates);
|
||||
final Color effectiveInactiveColor = inactiveColor
|
||||
?? defaults.fillColor!.resolve(inactiveStates)!;
|
||||
|
||||
final Set<MaterialState> focusedStates = states..add(MaterialState.focused);
|
||||
final Color effectiveFocusOverlayColor = widget.overlayColor?.resolve(focusedStates)
|
||||
?? widget.focusColor
|
||||
?? checkboxTheme.overlayColor?.resolve(focusedStates)
|
||||
?? themeData.focusColor;
|
||||
?? defaults.overlayColor!.resolve(focusedStates)!;
|
||||
|
||||
final Set<MaterialState> hoveredStates = states..add(MaterialState.hovered);
|
||||
final Color effectiveHoverOverlayColor = widget.overlayColor?.resolve(hoveredStates)
|
||||
?? widget.hoverColor
|
||||
?? checkboxTheme.overlayColor?.resolve(hoveredStates)
|
||||
?? themeData.hoverColor;
|
||||
?? widget.hoverColor
|
||||
?? checkboxTheme.overlayColor?.resolve(hoveredStates)
|
||||
?? defaults.overlayColor!.resolve(hoveredStates)!;
|
||||
|
||||
final Set<MaterialState> activePressedStates = activeStates..add(MaterialState.pressed);
|
||||
final Color effectiveActivePressedOverlayColor = widget.overlayColor?.resolve(activePressedStates)
|
||||
?? checkboxTheme.overlayColor?.resolve(activePressedStates)
|
||||
?? effectiveActiveColor.withAlpha(kRadialReactionAlpha);
|
||||
?? checkboxTheme.overlayColor?.resolve(activePressedStates)
|
||||
?? activeColor?.withAlpha(kRadialReactionAlpha)
|
||||
?? defaults.overlayColor!.resolve(activePressedStates)!;
|
||||
|
||||
final Set<MaterialState> inactivePressedStates = inactiveStates..add(MaterialState.pressed);
|
||||
final Color effectiveInactivePressedOverlayColor = widget.overlayColor?.resolve(inactivePressedStates)
|
||||
?? checkboxTheme.overlayColor?.resolve(inactivePressedStates)
|
||||
?? effectiveActiveColor.withAlpha(kRadialReactionAlpha);
|
||||
?? checkboxTheme.overlayColor?.resolve(inactivePressedStates)
|
||||
?? inactiveColor?.withAlpha(kRadialReactionAlpha)
|
||||
?? defaults.overlayColor!.resolve(inactivePressedStates)!;
|
||||
|
||||
final Color effectiveCheckColor = widget.checkColor
|
||||
?? checkboxTheme.checkColor?.resolve(states)
|
||||
?? const Color(0xFFFFFFFF);
|
||||
?? defaults.checkColor!.resolve(states)!;
|
||||
|
||||
final double effectiveSplashRadius = widget.splashRadius
|
||||
?? checkboxTheme.splashRadius
|
||||
?? defaults.splashRadius!;
|
||||
|
||||
return Semantics(
|
||||
checked: widget.value ?? false,
|
||||
|
@ -489,7 +488,7 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin, Togg
|
|||
..reactionColor = effectiveActivePressedOverlayColor
|
||||
..hoverColor = effectiveHoverOverlayColor
|
||||
..focusColor = effectiveFocusOverlayColor
|
||||
..splashRadius = widget.splashRadius ?? checkboxTheme.splashRadius ?? kRadialReactionRadius
|
||||
..splashRadius = effectiveSplashRadius
|
||||
..downPosition = downPosition
|
||||
..isFocused = states.contains(MaterialState.focused)
|
||||
..isHovered = states.contains(MaterialState.hovered)
|
||||
|
@ -683,3 +682,172 @@ class _CheckboxPainter extends ToggleablePainter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hand coded defaults based on Material Design 2.
|
||||
class _CheckboxDefaultsM2 extends CheckboxThemeData {
|
||||
_CheckboxDefaultsM2(BuildContext context)
|
||||
: _theme = Theme.of(context),
|
||||
_colors = Theme.of(context).colorScheme;
|
||||
|
||||
final ThemeData _theme;
|
||||
final ColorScheme _colors;
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color> get fillColor {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
return _theme.disabledColor;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return _colors.secondary;
|
||||
}
|
||||
return _theme.unselectedWidgetColor;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color> get checkColor {
|
||||
return MaterialStateProperty.all<Color>(const Color(0xFFFFFFFF));
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color?> get overlayColor {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return fillColor.resolve(states).withAlpha(kRadialReactionAlpha);
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return _theme.hoverColor;
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return _theme.focusColor;
|
||||
}
|
||||
return Colors.transparent;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
double get splashRadius => kRadialReactionRadius;
|
||||
|
||||
@override
|
||||
MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize;
|
||||
|
||||
@override
|
||||
VisualDensity get visualDensity => _theme.visualDensity;
|
||||
}
|
||||
|
||||
// BEGIN GENERATED TOKEN PROPERTIES - Checkbox
|
||||
|
||||
// Do not edit by hand. The code between the "BEGIN GENERATED" and
|
||||
// "END GENERATED" comments are generated from data in the Material
|
||||
// Design token database by the script:
|
||||
// dev/tools/gen_defaults/bin/gen_defaults.dart.
|
||||
|
||||
// Token database version: v0_101
|
||||
|
||||
class _CheckboxDefaultsM3 extends CheckboxThemeData {
|
||||
_CheckboxDefaultsM3(BuildContext context)
|
||||
: _theme = Theme.of(context),
|
||||
_colors = Theme.of(context).colorScheme;
|
||||
|
||||
final ThemeData _theme;
|
||||
final ColorScheme _colors;
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color> get fillColor {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return _colors.onSurface.withOpacity(0.38);
|
||||
}
|
||||
return _colors.onSurface.withOpacity(0.38);
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return _colors.primary;
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return _colors.primary;
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return _colors.primary;
|
||||
}
|
||||
return _colors.primary;
|
||||
}
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return _colors.onSurface;
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return _colors.onSurface;
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return _colors.onSurface;
|
||||
}
|
||||
return _colors.onSurface;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color> get checkColor {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return _colors.surface;
|
||||
}
|
||||
return Colors.transparent; // No icons available when the checkbox is unselected.
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return _colors.onPrimary;
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return _colors.onPrimary;
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return _colors.onPrimary;
|
||||
}
|
||||
return _colors.onPrimary;
|
||||
}
|
||||
return Colors.transparent; // No icons available when the checkbox is unselected.
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color> get overlayColor {
|
||||
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return _colors.onSurface.withOpacity(0.12);
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return _colors.primary.withOpacity(0.08);
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return _colors.primary.withOpacity(0.12);
|
||||
}
|
||||
return Colors.transparent;
|
||||
}
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return _colors.primary.withOpacity(0.12);
|
||||
}
|
||||
if (states.contains(MaterialState.hovered)) {
|
||||
return _colors.onSurface.withOpacity(0.08);
|
||||
}
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return _colors.onSurface.withOpacity(0.12);
|
||||
}
|
||||
return Colors.transparent;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
double get splashRadius => 40.0 / 2;
|
||||
|
||||
@override
|
||||
MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize;
|
||||
|
||||
@override
|
||||
VisualDensity get visualDensity => _theme.visualDensity;
|
||||
}
|
||||
|
||||
// END GENERATED TOKEN PROPERTIES - Checkbox
|
||||
|
|
|
@ -14,6 +14,7 @@ import '../rendering/mock_canvas.dart';
|
|||
import '../widgets/semantics_tester.dart';
|
||||
|
||||
void main() {
|
||||
final ThemeData theme = ThemeData();
|
||||
setUp(() {
|
||||
debugResetSemanticsIdCounter();
|
||||
});
|
||||
|
@ -21,7 +22,7 @@ void main() {
|
|||
testWidgets('Checkbox size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
Theme(
|
||||
data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.padded),
|
||||
data: theme.copyWith(materialTapTargetSize: MaterialTapTargetSize.padded),
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Material(
|
||||
|
@ -40,7 +41,7 @@ void main() {
|
|||
|
||||
await tester.pumpWidget(
|
||||
Theme(
|
||||
data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap),
|
||||
data: theme.copyWith(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap),
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Material(
|
||||
|
@ -61,10 +62,13 @@ void main() {
|
|||
testWidgets('CheckBox semantics', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
|
||||
await tester.pumpWidget(Material(
|
||||
child: Checkbox(
|
||||
value: false,
|
||||
onChanged: (bool? b) { },
|
||||
await tester.pumpWidget(Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: Checkbox(
|
||||
value: false,
|
||||
onChanged: (bool? b) { },
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
|
@ -76,10 +80,13 @@ void main() {
|
|||
isFocusable: true,
|
||||
));
|
||||
|
||||
await tester.pumpWidget(Material(
|
||||
child: Checkbox(
|
||||
value: true,
|
||||
onChanged: (bool? b) { },
|
||||
await tester.pumpWidget(Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: Checkbox(
|
||||
value: true,
|
||||
onChanged: (bool? b) { },
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
|
@ -92,10 +99,13 @@ void main() {
|
|||
isFocusable: true,
|
||||
));
|
||||
|
||||
await tester.pumpWidget(const Material(
|
||||
child: Checkbox(
|
||||
value: false,
|
||||
onChanged: null,
|
||||
await tester.pumpWidget(Theme(
|
||||
data: theme,
|
||||
child: const Material(
|
||||
child: Checkbox(
|
||||
value: false,
|
||||
onChanged: null,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
|
@ -113,10 +123,13 @@ void main() {
|
|||
hasEnabledState: true,
|
||||
));
|
||||
|
||||
await tester.pumpWidget(const Material(
|
||||
child: Checkbox(
|
||||
value: true,
|
||||
onChanged: null,
|
||||
await tester.pumpWidget(Theme(
|
||||
data: theme,
|
||||
child: const Material(
|
||||
child: Checkbox(
|
||||
value: true,
|
||||
onChanged: null,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
|
@ -131,13 +144,16 @@ void main() {
|
|||
testWidgets('Can wrap CheckBox with Semantics', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
|
||||
await tester.pumpWidget(Material(
|
||||
child: Semantics(
|
||||
label: 'foo',
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Checkbox(
|
||||
value: false,
|
||||
onChanged: (bool? b) { },
|
||||
await tester.pumpWidget(Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: Semantics(
|
||||
label: 'foo',
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Checkbox(
|
||||
value: false,
|
||||
onChanged: (bool? b) { },
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
@ -158,19 +174,22 @@ void main() {
|
|||
bool? checkBoxValue;
|
||||
|
||||
await tester.pumpWidget(
|
||||
Material(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Checkbox(
|
||||
tristate: true,
|
||||
value: checkBoxValue,
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
checkBoxValue = value;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Checkbox(
|
||||
tristate: true,
|
||||
value: checkBoxValue,
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
checkBoxValue = value;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -201,11 +220,14 @@ void main() {
|
|||
testWidgets('has semantics for tristate', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
await tester.pumpWidget(
|
||||
Material(
|
||||
child: Checkbox(
|
||||
tristate: true,
|
||||
value: null,
|
||||
onChanged: (bool? newValue) { },
|
||||
Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: Checkbox(
|
||||
tristate: true,
|
||||
value: null,
|
||||
onChanged: (bool? newValue) { },
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -221,11 +243,14 @@ void main() {
|
|||
), hasLength(1));
|
||||
|
||||
await tester.pumpWidget(
|
||||
Material(
|
||||
child: Checkbox(
|
||||
tristate: true,
|
||||
value: true,
|
||||
onChanged: (bool? newValue) { },
|
||||
Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: Checkbox(
|
||||
tristate: true,
|
||||
value: true,
|
||||
onChanged: (bool? newValue) { },
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -242,11 +267,14 @@ void main() {
|
|||
), hasLength(1));
|
||||
|
||||
await tester.pumpWidget(
|
||||
Material(
|
||||
child: Checkbox(
|
||||
tristate: true,
|
||||
value: false,
|
||||
onChanged: (bool? newValue) { },
|
||||
Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: Checkbox(
|
||||
tristate: true,
|
||||
value: false,
|
||||
onChanged: (bool? newValue) { },
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -273,18 +301,21 @@ void main() {
|
|||
final SemanticsTester semanticsTester = SemanticsTester(tester);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Material(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Checkbox(
|
||||
value: checkboxValue,
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
checkboxValue = value;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Checkbox(
|
||||
value: checkboxValue,
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
checkboxValue = value;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -306,15 +337,18 @@ void main() {
|
|||
|
||||
testWidgets('CheckBox tristate rendering, programmatic transitions', (WidgetTester tester) async {
|
||||
Widget buildFrame(bool? checkboxValue) {
|
||||
return Material(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Checkbox(
|
||||
tristate: true,
|
||||
value: checkboxValue,
|
||||
onChanged: (bool? value) { },
|
||||
);
|
||||
},
|
||||
return Theme(
|
||||
data: theme,
|
||||
child: Material(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Checkbox(
|
||||
tristate: true,
|
||||
value: checkboxValue,
|
||||
onChanged: (bool? value) { },
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -391,10 +425,14 @@ void main() {
|
|||
|
||||
activeColor = const Color(0xFF00FF00);
|
||||
|
||||
ThemeData themeData = ThemeData();
|
||||
final bool material3 = themeData.useMaterial3;
|
||||
final ColorScheme colorScheme = material3
|
||||
? const ColorScheme.light().copyWith(primary: activeColor)
|
||||
: const ColorScheme.light().copyWith(secondary: activeColor);
|
||||
themeData = themeData.copyWith(colorScheme: colorScheme);
|
||||
await tester.pumpWidget(buildFrame(
|
||||
themeData: ThemeData(
|
||||
colorScheme: const ColorScheme.light()
|
||||
.copyWith(secondary: activeColor))),
|
||||
themeData: themeData),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getCheckboxRenderer(), paints..path(color: activeColor)); // paints's color is 0xFF00FF00 (theme)
|
||||
|
@ -412,6 +450,7 @@ void main() {
|
|||
bool? value = true;
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
|
@ -434,13 +473,19 @@ void main() {
|
|||
await tester.pumpWidget(buildApp());
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
final bool material3 = theme.useMaterial3;
|
||||
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
paints
|
||||
..circle(color: Colors.orange[500])
|
||||
..path(color: const Color(0xff2196f3))
|
||||
..path(color: Colors.white),
|
||||
material3
|
||||
? (paints
|
||||
..circle(color: Colors.orange[500])
|
||||
..path(color: const Color(0xff2196f3))
|
||||
..path(color: theme.colorScheme.onPrimary))
|
||||
: (paints
|
||||
..circle(color: Colors.orange[500])
|
||||
..path(color: const Color(0xff2196f3))
|
||||
..path(color: Colors.white))
|
||||
);
|
||||
|
||||
// Check the false value.
|
||||
|
@ -453,7 +498,7 @@ void main() {
|
|||
paints
|
||||
..circle(color: Colors.orange[500])
|
||||
..drrect(
|
||||
color: const Color(0x8a000000),
|
||||
color: material3 ? theme.colorScheme.onSurface : const Color(0x8a000000),
|
||||
outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(1.0)),
|
||||
inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, const Radius.circular(-1.0)),
|
||||
),
|
||||
|
@ -468,7 +513,7 @@ void main() {
|
|||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
paints
|
||||
..drrect(
|
||||
color: const Color(0x61000000),
|
||||
color: material3 ? theme.colorScheme.onSurface.withOpacity(0.38) : const Color(0x61000000),
|
||||
outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(1.0)),
|
||||
inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, const Radius.circular(-1.0)),
|
||||
),
|
||||
|
@ -480,6 +525,7 @@ void main() {
|
|||
const double splashRadius = 30;
|
||||
Widget buildApp() {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
|
@ -506,8 +552,10 @@ void main() {
|
|||
testWidgets('Checkbox can be hovered and has correct hover color', (WidgetTester tester) async {
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
bool? value = true;
|
||||
final bool material3 = theme.useMaterial3;
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
|
@ -531,7 +579,7 @@ void main() {
|
|||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
paints
|
||||
..path(color: const Color(0xff2196f3))
|
||||
..path(color: const Color(0xffffffff),style: PaintingStyle.stroke, strokeWidth: 2.0),
|
||||
..path(color: material3 ? theme.colorScheme.onPrimary : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0),
|
||||
);
|
||||
|
||||
// Start hovering
|
||||
|
@ -544,7 +592,7 @@ void main() {
|
|||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
paints
|
||||
..path(color: const Color(0xff2196f3))
|
||||
..path(color: const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0),
|
||||
..path(color: material3 ? theme.colorScheme.onPrimary : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0),
|
||||
);
|
||||
|
||||
// Check what happens when disabled.
|
||||
|
@ -553,8 +601,8 @@ void main() {
|
|||
expect(
|
||||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
paints
|
||||
..path(color: const Color(0x61000000))
|
||||
..path(color: const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0),
|
||||
..path(color: material3 ? theme.colorScheme.onSurface.withOpacity(0.38) : const Color(0x61000000))
|
||||
..path(color: material3 ? theme.colorScheme.surface : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0),
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -563,6 +611,7 @@ void main() {
|
|||
bool? value = true;
|
||||
Widget buildApp({bool enabled = true}) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
|
@ -603,6 +652,7 @@ void main() {
|
|||
Future<void> buildTest(VisualDensity visualDensity) async {
|
||||
return tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: Checkbox(
|
||||
|
@ -693,6 +743,7 @@ void main() {
|
|||
// Test Checkbox() constructor
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: Scaffold(
|
||||
body: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
|
@ -721,6 +772,7 @@ void main() {
|
|||
// Test default cursor
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: Scaffold(
|
||||
body: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
|
@ -742,8 +794,9 @@ void main() {
|
|||
|
||||
// Test default cursor when disabled
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: const Scaffold(
|
||||
body: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Material(
|
||||
|
@ -764,8 +817,9 @@ void main() {
|
|||
|
||||
// Test cursor when tristate
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: const Scaffold(
|
||||
body: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Material(
|
||||
|
@ -807,7 +861,7 @@ void main() {
|
|||
Widget buildFrame({required bool enabled}) {
|
||||
return Material(
|
||||
child: Theme(
|
||||
data: ThemeData(),
|
||||
data: theme,
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Checkbox(
|
||||
|
@ -856,7 +910,7 @@ void main() {
|
|||
Widget buildFrame() {
|
||||
return Material(
|
||||
child: Theme(
|
||||
data: ThemeData(),
|
||||
data: theme,
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Checkbox(
|
||||
|
@ -901,6 +955,7 @@ void main() {
|
|||
|
||||
Widget buildApp() {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
|
@ -932,6 +987,82 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
testWidgets('Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox');
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
|
||||
final ColorScheme colors = theme.colorScheme;
|
||||
final bool material3 = theme.useMaterial3;
|
||||
Widget buildCheckbox({bool active = false, bool focused = false}) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Scaffold(
|
||||
body: Checkbox(
|
||||
focusNode: focusNode,
|
||||
autofocus: focused,
|
||||
value: active,
|
||||
onChanged: (_) { },
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildCheckbox());
|
||||
await tester.startGesture(tester.getCenter(find.byType(Checkbox)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
material3
|
||||
? (paints..circle(color: colors.primary.withOpacity(0.12)))
|
||||
: (paints
|
||||
..circle(color: theme.unselectedWidgetColor.withAlpha(kRadialReactionAlpha),)
|
||||
),
|
||||
reason: 'Default inactive pressed Checkbox should have overlay color from default fillColor',
|
||||
);
|
||||
|
||||
await tester.pumpWidget(buildCheckbox(active: true));
|
||||
await tester.startGesture(tester.getCenter(find.byType(Checkbox)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
material3
|
||||
? (paints..circle(color: colors.onSurface.withOpacity(0.12)))
|
||||
: (paints
|
||||
..circle(color: colors.secondary.withAlpha(kRadialReactionAlpha),)
|
||||
),
|
||||
reason: 'Default active pressed Checkbox should have overlay color from default fillColor',
|
||||
);
|
||||
|
||||
await tester.pumpWidget(buildCheckbox(focused: true));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
material3
|
||||
? (paints..circle(color: colors.onSurface.withOpacity(0.12)))
|
||||
: (paints..circle(color: theme.focusColor)),
|
||||
reason: 'Focused Checkbox should use default focused overlay color',
|
||||
);
|
||||
|
||||
await tester.pumpWidget(Container()); // reset test
|
||||
await tester.pumpWidget(buildCheckbox());
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||
await gesture.addPointer();
|
||||
await gesture.moveTo(tester.getCenter(find.byType(Checkbox)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Material.of(tester.element(find.byType(Checkbox))),
|
||||
material3
|
||||
? (paints..circle(color: colors.onSurface.withOpacity(0.08)))
|
||||
: (paints..circle(color: theme.hoverColor)),
|
||||
reason: 'Hovered Checkbox should use default hovered overlay color',
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Checkbox overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox');
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
|
@ -963,6 +1094,7 @@ void main() {
|
|||
|
||||
Widget buildCheckbox({bool active = false, bool focused = false, bool useOverlay = true}) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Scaffold(
|
||||
body: Checkbox(
|
||||
focusNode: focusNode,
|
||||
|
@ -1085,6 +1217,7 @@ void main() {
|
|||
|
||||
Widget buildTristateCheckbox() {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Scaffold(
|
||||
body: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
|
@ -1175,6 +1308,7 @@ void main() {
|
|||
testWidgets('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async {
|
||||
Widget buildCheckbox(bool show) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: show ? Checkbox(value: true, onChanged: (_) { }) : Container(),
|
||||
|
@ -1205,6 +1339,7 @@ void main() {
|
|||
|
||||
Widget buildApp({ bool? value, bool enabled = true }) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: Checkbox(
|
||||
|
@ -1268,6 +1403,7 @@ void main() {
|
|||
|
||||
Widget buildApp({ bool? value, bool enabled = true }) {
|
||||
return MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: Checkbox(
|
||||
|
|
Loading…
Reference in a new issue