blob: bcd7f0cb5d4d6f7640efab58b9d5ea3a4a96e250 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
void main() {
test('CheckboxThemeData copyWith, ==, hashCode basics', () {
expect(const CheckboxThemeData(), const CheckboxThemeData().copyWith());
expect(const CheckboxThemeData().hashCode, const CheckboxThemeData().copyWith().hashCode);
});
test('CheckboxThemeData defaults', () {
const CheckboxThemeData themeData = CheckboxThemeData();
expect(themeData.mouseCursor, null);
expect(themeData.fillColor, null);
expect(themeData.checkColor, null);
expect(themeData.overlayColor, null);
expect(themeData.splashRadius, null);
expect(themeData.materialTapTargetSize, null);
expect(themeData.visualDensity, null);
const CheckboxTheme theme = CheckboxTheme(data: CheckboxThemeData(), child: SizedBox());
expect(theme.data.mouseCursor, null);
expect(theme.data.fillColor, null);
expect(theme.data.checkColor, null);
expect(theme.data.overlayColor, null);
expect(theme.data.splashRadius, null);
expect(theme.data.materialTapTargetSize, null);
expect(theme.data.visualDensity, null);
});
testWidgets('Default CheckboxThemeData debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const CheckboxThemeData().debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[]);
});
testWidgets('CheckboxThemeData implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
CheckboxThemeData(
mouseCursor: MaterialStateProperty.all(SystemMouseCursors.click),
fillColor: MaterialStateProperty.all(const Color(0xfffffff0)),
checkColor: MaterialStateProperty.all(const Color(0xfffffff1)),
overlayColor: MaterialStateProperty.all(const Color(0xfffffff2)),
splashRadius: 1.0,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.standard,
).debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description[0], 'mouseCursor: MaterialStateProperty.all(SystemMouseCursor(click))');
expect(description[1], 'fillColor: MaterialStateProperty.all(Color(0xfffffff0))');
expect(description[2], 'checkColor: MaterialStateProperty.all(Color(0xfffffff1))');
expect(description[3], 'overlayColor: MaterialStateProperty.all(Color(0xfffffff2))');
expect(description[4], 'splashRadius: 1.0');
expect(description[5], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap');
expect(description[6], 'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)');
});
testWidgets('Checkbox is themeable', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
const MouseCursor mouseCursor = SystemMouseCursors.text;
const Color defaultFillColor = Color(0xfffffff0);
const Color selectedFillColor = Color(0xfffffff1);
const Color defaultCheckColor = Color(0xfffffff2);
const Color focusedCheckColor = Color(0xfffffff3);
const Color focusOverlayColor = Color(0xfffffff4);
const Color hoverOverlayColor = Color(0xfffffff5);
const double splashRadius = 1.0;
const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap;
const VisualDensity visualDensity = VisualDensity(vertical: 1.0, horizontal: 1.0);
Widget buildCheckbox({bool selected = false, bool autofocus = false}) {
return MaterialApp(
theme: ThemeData(
checkboxTheme: CheckboxThemeData(
mouseCursor: MaterialStateProperty.all(mouseCursor),
fillColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return selectedFillColor;
}
return defaultFillColor;
}),
checkColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.focused)) {
return focusedCheckColor;
}
return defaultCheckColor;
}),
overlayColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.focused)) {
return focusOverlayColor;
}
if (states.contains(MaterialState.hovered)) {
return hoverOverlayColor;
}
return null;
}),
splashRadius: splashRadius,
materialTapTargetSize: materialTapTargetSize,
visualDensity: visualDensity,
),
),
home: Scaffold(
body: Checkbox(
onChanged: (bool? value) {},
value: selected,
autofocus: autofocus,
),
),
);
}
// Checkbox.
await tester.pumpWidget(buildCheckbox());
await tester.pumpAndSettle();
expect(_getCheckboxMaterial(tester), paints..drrect(color: defaultFillColor));
// Size from MaterialTapTargetSize.shrinkWrap with added VisualDensity.
expect(tester.getSize(find.byType(Checkbox)), const Size(40.0, 40.0) + visualDensity.baseSizeAdjustment);
// Selected checkbox.
await tester.pumpWidget(buildCheckbox(selected: true));
await tester.pumpAndSettle();
expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor));
expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)..path(color: defaultCheckColor));
// Checkbox with hover.
await tester.pumpWidget(buildCheckbox());
await _pointGestureToCheckbox(tester);
await tester.pumpAndSettle();
expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
expect(_getCheckboxMaterial(tester), paints..circle(color: hoverOverlayColor));
// Checkbox with focus.
await tester.pumpWidget(buildCheckbox(autofocus: true, selected: true));
await tester.pumpAndSettle();
expect(_getCheckboxMaterial(tester), paints..circle(color: focusOverlayColor, radius: splashRadius));
expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)..path(color: focusedCheckColor));
});
testWidgets('Checkbox properties are taken over the theme values', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
const MouseCursor themeMouseCursor = SystemMouseCursors.click;
const Color themeDefaultFillColor = Color(0xfffffff0);
const Color themeSelectedFillColor = Color(0xfffffff1);
const Color themeCheckColor = Color(0xfffffff2);
const Color themeFocusOverlayColor = Color(0xfffffff3);
const Color themeHoverOverlayColor = Color(0xfffffff4);
const double themeSplashRadius = 1.0;
const MaterialTapTargetSize themeMaterialTapTargetSize = MaterialTapTargetSize.padded;
const VisualDensity themeVisualDensity = VisualDensity.standard;
const MouseCursor mouseCursor = SystemMouseCursors.text;
const Color defaultFillColor = Color(0xfffffff5);
const Color selectedFillColor = Color(0xfffffff6);
const Color checkColor = Color(0xfffffff7);
const Color focusColor = Color(0xfffffff8);
const Color hoverColor = Color(0xfffffff9);
const double splashRadius = 2.0;
const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap;
const VisualDensity visualDensity = VisualDensity.standard;
Widget buildCheckbox({bool selected = false, bool autofocus = false}) {
return MaterialApp(
theme: ThemeData(
checkboxTheme: CheckboxThemeData(
mouseCursor: MaterialStateProperty.all(themeMouseCursor),
fillColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return themeSelectedFillColor;
}
return themeDefaultFillColor;
}),
checkColor: MaterialStateProperty.all(themeCheckColor),
overlayColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.focused)) {
return themeFocusOverlayColor;
}
if (states.contains(MaterialState.hovered)) {
return themeHoverOverlayColor;
}
return null;
}),
splashRadius: themeSplashRadius,
materialTapTargetSize: themeMaterialTapTargetSize,
visualDensity: themeVisualDensity,
),
),
home: Scaffold(
body: Checkbox(
onChanged: (bool? value) { },
value: selected,
autofocus: autofocus,
mouseCursor: mouseCursor,
fillColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return selectedFillColor;
}
return defaultFillColor;
}),
checkColor: checkColor,
focusColor: focusColor,
hoverColor: hoverColor,
splashRadius: splashRadius,
materialTapTargetSize: materialTapTargetSize,
visualDensity: visualDensity,
),
),
);
}
// Checkbox.
await tester.pumpWidget(buildCheckbox());
await tester.pumpAndSettle();
expect(_getCheckboxMaterial(tester), paints..drrect(color: defaultFillColor));
// Size from MaterialTapTargetSize.shrinkWrap with added VisualDensity.
expect(tester.getSize(find.byType(Checkbox)), const Size(40.0, 40.0) + visualDensity.baseSizeAdjustment);
// Selected checkbox.
await tester.pumpWidget(buildCheckbox(selected: true));
await tester.pumpAndSettle();
expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor));
expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)..path(color: checkColor));
// Checkbox with hover.
await tester.pumpWidget(buildCheckbox());
await _pointGestureToCheckbox(tester);
await tester.pumpAndSettle();
expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
expect(_getCheckboxMaterial(tester), paints..circle(color: hoverColor));
// Checkbox with focus.
await tester.pumpWidget(buildCheckbox(autofocus: true));
await tester.pumpAndSettle();
expect(_getCheckboxMaterial(tester), paints..circle(color: focusColor, radius: splashRadius));
});
testWidgets('Checkbox activeColor property is taken over the theme', (WidgetTester tester) async {
const Color themeSelectedFillColor = Color(0xfffffff1);
const Color themeDefaultFillColor = Color(0xfffffff0);
const Color selectedFillColor = Color(0xfffffff6);
Widget buildCheckbox({bool selected = false}) {
return MaterialApp(
theme: ThemeData(
checkboxTheme: CheckboxThemeData(
fillColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return themeSelectedFillColor;
}
return themeDefaultFillColor;
}),
),
),
home: Scaffold(
body: Checkbox(
onChanged: (bool? value) { },
value: selected,
activeColor: selectedFillColor,
),
),
);
}
// Unselected checkbox.
await tester.pumpWidget(buildCheckbox());
await tester.pumpAndSettle();
expect(_getCheckboxMaterial(tester), paints..drrect(color: themeDefaultFillColor));
// Selected checkbox.
await tester.pumpWidget(buildCheckbox(selected: true));
await tester.pumpAndSettle();
expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor));
});
testWidgets('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async {
const Color activePressedOverlayColor = Color(0xFF000001);
const Color inactivePressedOverlayColor = Color(0xFF000002);
Color? getOverlayColor(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
if (states.contains(MaterialState.selected)) {
return activePressedOverlayColor;
}
return inactivePressedOverlayColor;
}
return null;
}
const double splashRadius = 24.0;
Widget buildCheckbox({required bool active}) {
return MaterialApp(
theme: ThemeData(
checkboxTheme: CheckboxThemeData(
overlayColor: MaterialStateProperty.resolveWith(getOverlayColor),
splashRadius: splashRadius,
),
),
home: Scaffold(
body: Checkbox(
value: active,
onChanged: (_) { },
),
),
);
}
await tester.pumpWidget(buildCheckbox(active: false));
await tester.startGesture(tester.getCenter(find.byType(Checkbox)));
await tester.pumpAndSettle();
expect(
_getCheckboxMaterial(tester),
paints
..circle(
color: inactivePressedOverlayColor,
radius: splashRadius,
),
reason: 'Inactive pressed Checkbox should have overlay color: $inactivePressedOverlayColor',
);
await tester.pumpWidget(buildCheckbox(active: true));
await tester.startGesture(tester.getCenter(find.byType(Checkbox)));
await tester.pumpAndSettle();
expect(
_getCheckboxMaterial(tester),
paints
..circle(
color: activePressedOverlayColor,
radius: splashRadius,
),
reason: 'Active pressed Checkbox should have overlay color: $activePressedOverlayColor',
);
});
}
Future<void> _pointGestureToCheckbox(WidgetTester tester) async {
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer();
addTearDown(gesture.removePointer);
await gesture.moveTo(tester.getCenter(find.byType(Checkbox)));
}
MaterialInkController? _getCheckboxMaterial(WidgetTester tester) {
return Material.of(tester.element(find.byType(Checkbox)));
}