| // 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 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; |
| |
| void main() { |
| test('SwitchThemeData copyWith, ==, hashCode basics', () { |
| expect(const SwitchThemeData(), const SwitchThemeData().copyWith()); |
| expect(const SwitchThemeData().hashCode, const SwitchThemeData().copyWith().hashCode); |
| }); |
| |
| test('SwitchThemeData lerp special cases', () { |
| const SwitchThemeData data = SwitchThemeData(); |
| expect(identical(SwitchThemeData.lerp(data, data, 0.5), data), true); |
| }); |
| |
| test('SwitchThemeData defaults', () { |
| const SwitchThemeData themeData = SwitchThemeData(); |
| expect(themeData.thumbColor, null); |
| expect(themeData.trackColor, null); |
| expect(themeData.trackOutlineColor, null); |
| expect(themeData.trackOutlineWidth, null); |
| expect(themeData.mouseCursor, null); |
| expect(themeData.materialTapTargetSize, null); |
| expect(themeData.overlayColor, null); |
| expect(themeData.splashRadius, null); |
| expect(themeData.thumbIcon, null); |
| |
| const SwitchTheme theme = SwitchTheme(data: SwitchThemeData(), child: SizedBox()); |
| expect(theme.data.thumbColor, null); |
| expect(theme.data.trackColor, null); |
| expect(theme.data.trackOutlineColor, null); |
| expect(theme.data.trackOutlineWidth, null); |
| expect(theme.data.mouseCursor, null); |
| expect(theme.data.materialTapTargetSize, null); |
| expect(theme.data.overlayColor, null); |
| expect(theme.data.splashRadius, null); |
| expect(theme.data.thumbIcon, null); |
| }); |
| |
| testWidgetsWithLeakTracking('Default SwitchThemeData debugFillProperties', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const SwitchThemeData().debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description, <String>[]); |
| }); |
| |
| testWidgetsWithLeakTracking('SwitchThemeData implements debugFillProperties', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const SwitchThemeData( |
| thumbColor: MaterialStatePropertyAll<Color>(Color(0xfffffff0)), |
| trackColor: MaterialStatePropertyAll<Color>(Color(0xfffffff1)), |
| trackOutlineColor: MaterialStatePropertyAll<Color>(Color(0xfffffff3)), |
| trackOutlineWidth: MaterialStatePropertyAll<double>(6.0), |
| mouseCursor: MaterialStatePropertyAll<MouseCursor>(SystemMouseCursors.click), |
| materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, |
| overlayColor: MaterialStatePropertyAll<Color>(Color(0xfffffff2)), |
| splashRadius: 1.0, |
| thumbIcon: MaterialStatePropertyAll<Icon>(Icon(IconData(123))), |
| ).debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description[0], 'thumbColor: MaterialStatePropertyAll(Color(0xfffffff0))'); |
| expect(description[1], 'trackColor: MaterialStatePropertyAll(Color(0xfffffff1))'); |
| expect(description[2], 'trackOutlineColor: MaterialStatePropertyAll(Color(0xfffffff3))'); |
| expect(description[3], 'trackOutlineWidth: MaterialStatePropertyAll(6.0)'); |
| expect(description[4], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap'); |
| expect(description[5], 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))'); |
| expect(description[6], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))'); |
| expect(description[7], 'splashRadius: 1.0'); |
| expect(description[8], 'thumbIcon: MaterialStatePropertyAll(Icon(IconData(U+0007B)))'); |
| }); |
| |
| testWidgetsWithLeakTracking('Material2 - Switch is themeable', (WidgetTester tester) async { |
| tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; |
| |
| const Color defaultThumbColor = Color(0xfffffff0); |
| const Color selectedThumbColor = Color(0xfffffff1); |
| const Color defaultTrackColor = Color(0xfffffff2); |
| const Color selectedTrackColor = Color(0xfffffff3); |
| const Color defaultTrackOutlineColor = Color(0xfffffff4); |
| const Color selectedTrackOutlineColor = Color(0xfffffff5); |
| const double defaultTrackOutlineWidth = 3.0; |
| const double selectedTrackOutlineWidth = 6.0; |
| const MouseCursor mouseCursor = SystemMouseCursors.text; |
| const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap; |
| const Color focusOverlayColor = Color(0xfffffff4); |
| const Color hoverOverlayColor = Color(0xfffffff5); |
| const double splashRadius = 1.0; |
| const Icon icon1 = Icon(Icons.check); |
| const Icon icon2 = Icon(Icons.close); |
| |
| final ThemeData themeData = ThemeData( |
| useMaterial3: false, |
| switchTheme: SwitchThemeData( |
| thumbColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedThumbColor; |
| } |
| return defaultThumbColor; |
| }), |
| trackColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedTrackColor; |
| } |
| return defaultTrackColor; |
| }), |
| trackOutlineColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedTrackOutlineColor; |
| } |
| return defaultTrackOutlineColor; |
| }), |
| trackOutlineWidth: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedTrackOutlineWidth; |
| } |
| return defaultTrackOutlineWidth; |
| }), |
| mouseCursor: const MaterialStatePropertyAll<MouseCursor>(mouseCursor), |
| materialTapTargetSize: materialTapTargetSize, |
| overlayColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.focused)) { |
| return focusOverlayColor; |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return hoverOverlayColor; |
| } |
| return null; |
| }), |
| splashRadius: splashRadius, |
| thumbIcon: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return icon1; |
| } |
| return icon2; |
| }), |
| ), |
| ); |
| Widget buildSwitch({bool selected = false, bool autofocus = false}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: Switch( |
| dragStartBehavior: DragStartBehavior.down, |
| value: selected, |
| onChanged: (bool value) {}, |
| autofocus: autofocus, |
| ), |
| ), |
| ); |
| } |
| |
| // Switch. |
| await tester.pumpWidget(buildSwitch()); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: defaultTrackColor) |
| ..rrect(color: defaultTrackOutlineColor, strokeWidth: defaultTrackOutlineWidth) |
| ..rrect() |
| ..rrect() |
| ..rrect() |
| ..rrect(color: defaultThumbColor) |
| ); |
| // Size from MaterialTapTargetSize.shrinkWrap. |
| expect(tester.getSize(find.byType(Switch)), const Size(59.0, 40.0)); |
| |
| // Selected switch. |
| await tester.pumpWidget(buildSwitch(selected: true)); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: selectedTrackColor) |
| ..rrect(color: selectedTrackOutlineColor, strokeWidth: selectedTrackOutlineWidth) |
| ..rrect() |
| ..rrect() |
| ..rrect() |
| ..rrect(color: selectedThumbColor) |
| ); |
| |
| // Switch with hover. |
| await tester.pumpWidget(buildSwitch()); |
| await _pointGestureToSwitch(tester); |
| await tester.pumpAndSettle(); |
| expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); |
| expect(_getSwitchMaterial(tester), paints..circle(color: hoverOverlayColor)); |
| |
| // Switch with focus. |
| await tester.pumpWidget(buildSwitch(autofocus: true)); |
| await tester.pumpAndSettle(); |
| expect(_getSwitchMaterial(tester), paints..circle(color: focusOverlayColor, radius: splashRadius)); |
| }); |
| |
| testWidgetsWithLeakTracking('Material3 - Switch is themeable', (WidgetTester tester) async { |
| tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; |
| |
| const Color defaultThumbColor = Color(0xfffffff0); |
| const Color selectedThumbColor = Color(0xfffffff1); |
| const Color defaultTrackColor = Color(0xfffffff2); |
| const Color selectedTrackColor = Color(0xfffffff3); |
| const Color defaultTrackOutlineColor = Color(0xfffffff4); |
| const Color selectedTrackOutlineColor = Color(0xfffffff5); |
| const double defaultTrackOutlineWidth = 3.0; |
| const double selectedTrackOutlineWidth = 6.0; |
| const MouseCursor mouseCursor = SystemMouseCursors.text; |
| const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap; |
| const Color focusOverlayColor = Color(0xfffffff4); |
| const Color hoverOverlayColor = Color(0xfffffff5); |
| const double splashRadius = 1.0; |
| const Icon icon1 = Icon(Icons.check); |
| const Icon icon2 = Icon(Icons.close); |
| |
| final ThemeData themeData = ThemeData( |
| useMaterial3: true, |
| switchTheme: SwitchThemeData( |
| thumbColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedThumbColor; |
| } |
| return defaultThumbColor; |
| }), |
| trackColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedTrackColor; |
| } |
| return defaultTrackColor; |
| }), |
| trackOutlineColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedTrackOutlineColor; |
| } |
| return defaultTrackOutlineColor; |
| }), |
| trackOutlineWidth: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedTrackOutlineWidth; |
| } |
| return defaultTrackOutlineWidth; |
| }), |
| mouseCursor: const MaterialStatePropertyAll<MouseCursor>(mouseCursor), |
| materialTapTargetSize: materialTapTargetSize, |
| overlayColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.focused)) { |
| return focusOverlayColor; |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return hoverOverlayColor; |
| } |
| return null; |
| }), |
| splashRadius: splashRadius, |
| thumbIcon: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return icon1; |
| } |
| return icon2; |
| }), |
| ), |
| ); |
| Widget buildSwitch({bool selected = false, bool autofocus = false}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: Switch( |
| dragStartBehavior: DragStartBehavior.down, |
| value: selected, |
| onChanged: (bool value) {}, |
| autofocus: autofocus, |
| ), |
| ), |
| ); |
| } |
| |
| // Switch. |
| await tester.pumpWidget(buildSwitch()); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: defaultTrackColor) |
| ..rrect(color: defaultTrackOutlineColor, strokeWidth: defaultTrackOutlineWidth) |
| ..rrect(color: defaultThumbColor) |
| ..paragraph() |
| ); |
| // Size from MaterialTapTargetSize.shrinkWrap. |
| expect(tester.getSize(find.byType(Switch)), const Size(60.0, 40.0)); |
| |
| // Selected switch. |
| await tester.pumpWidget(buildSwitch(selected: true)); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: selectedTrackColor) |
| ..rrect(color: selectedTrackOutlineColor, strokeWidth: selectedTrackOutlineWidth) |
| ..rrect(color: selectedThumbColor)..paragraph() |
| ); |
| |
| // Switch with hover. |
| await tester.pumpWidget(buildSwitch()); |
| await _pointGestureToSwitch(tester); |
| await tester.pumpAndSettle(); |
| expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); |
| expect(_getSwitchMaterial(tester), paints..circle(color: hoverOverlayColor)); |
| |
| // Switch with focus. |
| await tester.pumpWidget(buildSwitch(autofocus: true)); |
| await tester.pumpAndSettle(); |
| expect(_getSwitchMaterial(tester), paints..circle(color: focusOverlayColor, radius: splashRadius)); |
| }); |
| |
| testWidgetsWithLeakTracking('Material2 - Switch properties are taken over the theme values', (WidgetTester tester) async { |
| tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; |
| |
| const Color themeDefaultThumbColor = Color(0xfffffff0); |
| const Color themeSelectedThumbColor = Color(0xfffffff1); |
| const Color themeDefaultTrackColor = Color(0xfffffff2); |
| const Color themeSelectedTrackColor = Color(0xfffffff3); |
| const Color themeDefaultOutlineColor = Color(0xfffffff6); |
| const Color themeSelectedOutlineColor = Color(0xfffffff7); |
| const double themeDefaultOutlineWidth = 5.0; |
| const double themeSelectedOutlineWidth = 7.0; |
| const MouseCursor themeMouseCursor = SystemMouseCursors.click; |
| const MaterialTapTargetSize themeMaterialTapTargetSize = MaterialTapTargetSize.padded; |
| const Color themeFocusOverlayColor = Color(0xfffffff4); |
| const Color themeHoverOverlayColor = Color(0xfffffff5); |
| const double themeSplashRadius = 1.0; |
| |
| const Color defaultThumbColor = Color(0xffffff0f); |
| const Color selectedThumbColor = Color(0xffffff1f); |
| const Color defaultTrackColor = Color(0xffffff2f); |
| const Color selectedTrackColor = Color(0xffffff3f); |
| const Color defaultOutlineColor = Color(0xffffff6f); |
| const Color selectedOutlineColor = Color(0xffffff7f); |
| const double defaultOutlineWidth = 6.0; |
| const double selectedOutlineWidth = 8.0; |
| const MouseCursor mouseCursor = SystemMouseCursors.text; |
| const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap; |
| const Color focusColor = Color(0xffffff4f); |
| const Color hoverColor = Color(0xffffff5f); |
| const double splashRadius = 2.0; |
| |
| final ThemeData themeData = ThemeData( |
| useMaterial3: false, |
| switchTheme: SwitchThemeData( |
| thumbColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedThumbColor; |
| } |
| return themeDefaultThumbColor; |
| }), |
| trackColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedTrackColor; |
| } |
| return themeDefaultTrackColor; |
| }), |
| trackOutlineColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedOutlineColor; |
| } |
| return themeDefaultOutlineColor; |
| }), |
| trackOutlineWidth: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedOutlineWidth; |
| } |
| return themeDefaultOutlineWidth; |
| }), |
| mouseCursor: const MaterialStatePropertyAll<MouseCursor>(themeMouseCursor), |
| materialTapTargetSize: themeMaterialTapTargetSize, |
| overlayColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.focused)) { |
| return themeFocusOverlayColor; |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return themeHoverOverlayColor; |
| } |
| return null; |
| }), |
| splashRadius: themeSplashRadius, |
| thumbIcon: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return null; |
| } |
| return null; |
| }), |
| ), |
| ); |
| |
| Widget buildSwitch({bool selected = false, bool autofocus = false}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: Switch( |
| value: selected, |
| onChanged: (bool value) {}, |
| autofocus: autofocus, |
| thumbColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedThumbColor; |
| } |
| return defaultThumbColor; |
| }), |
| trackColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedTrackColor; |
| } |
| return defaultTrackColor; |
| }), |
| trackOutlineColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedOutlineColor; |
| } |
| return defaultOutlineColor; |
| }), |
| trackOutlineWidth: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedOutlineWidth; |
| } |
| return defaultOutlineWidth; |
| }), |
| mouseCursor: mouseCursor, |
| materialTapTargetSize: materialTapTargetSize, |
| focusColor: focusColor, |
| hoverColor: hoverColor, |
| splashRadius: splashRadius, |
| thumbIcon: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return const Icon(Icons.add); |
| } |
| return const Icon(Icons.access_alarm); |
| }), |
| ), |
| ), |
| ); |
| } |
| |
| // Switch. |
| await tester.pumpWidget(buildSwitch()); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: defaultTrackColor) |
| ..rrect(color: defaultOutlineColor, strokeWidth: defaultOutlineWidth) |
| ..rrect() |
| ..rrect() |
| ..rrect() |
| ..rrect(color: defaultThumbColor) |
| ); |
| // Size from MaterialTapTargetSize.shrinkWrap. |
| expect(tester.getSize(find.byType(Switch)), const Size(59.0, 40.0)); |
| |
| // Selected switch. |
| await tester.pumpWidget(buildSwitch(selected: true)); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: selectedTrackColor) |
| ..rrect(color: selectedOutlineColor, strokeWidth: selectedOutlineWidth) |
| ..rrect() |
| ..rrect() |
| ..rrect() |
| ..rrect(color: selectedThumbColor) |
| ); |
| |
| // Switch with hover. |
| await tester.pumpWidget(buildSwitch()); |
| await _pointGestureToSwitch(tester); |
| await tester.pumpAndSettle(); |
| expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); |
| expect(_getSwitchMaterial(tester), paints..circle(color: hoverColor)); |
| |
| // Switch with focus. |
| await tester.pumpWidget(buildSwitch(autofocus: true)); |
| await tester.pumpAndSettle(); |
| expect(_getSwitchMaterial(tester), paints..circle(color: focusColor, radius: splashRadius)); |
| }); |
| |
| testWidgetsWithLeakTracking('Material3 - Switch properties are taken over the theme values', (WidgetTester tester) async { |
| tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; |
| |
| const Color themeDefaultThumbColor = Color(0xfffffff0); |
| const Color themeSelectedThumbColor = Color(0xfffffff1); |
| const Color themeDefaultTrackColor = Color(0xfffffff2); |
| const Color themeSelectedTrackColor = Color(0xfffffff3); |
| const Color themeDefaultOutlineColor = Color(0xfffffff6); |
| const Color themeSelectedOutlineColor = Color(0xfffffff7); |
| const double themeDefaultOutlineWidth = 5.0; |
| const double themeSelectedOutlineWidth = 7.0; |
| const MouseCursor themeMouseCursor = SystemMouseCursors.click; |
| const MaterialTapTargetSize themeMaterialTapTargetSize = MaterialTapTargetSize.padded; |
| const Color themeFocusOverlayColor = Color(0xfffffff4); |
| const Color themeHoverOverlayColor = Color(0xfffffff5); |
| const double themeSplashRadius = 1.0; |
| |
| const Color defaultThumbColor = Color(0xffffff0f); |
| const Color selectedThumbColor = Color(0xffffff1f); |
| const Color defaultTrackColor = Color(0xffffff2f); |
| const Color selectedTrackColor = Color(0xffffff3f); |
| const Color defaultOutlineColor = Color(0xffffff6f); |
| const Color selectedOutlineColor = Color(0xffffff7f); |
| const double defaultOutlineWidth = 6.0; |
| const double selectedOutlineWidth = 8.0; |
| const MouseCursor mouseCursor = SystemMouseCursors.text; |
| const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap; |
| const Color focusColor = Color(0xffffff4f); |
| const Color hoverColor = Color(0xffffff5f); |
| const double splashRadius = 2.0; |
| |
| final ThemeData themeData = ThemeData( |
| useMaterial3: true, |
| switchTheme: SwitchThemeData( |
| thumbColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedThumbColor; |
| } |
| return themeDefaultThumbColor; |
| }), |
| trackColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedTrackColor; |
| } |
| return themeDefaultTrackColor; |
| }), |
| trackOutlineColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedOutlineColor; |
| } |
| return themeDefaultOutlineColor; |
| }), |
| trackOutlineWidth: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedOutlineWidth; |
| } |
| return themeDefaultOutlineWidth; |
| }), |
| mouseCursor: const MaterialStatePropertyAll<MouseCursor>(themeMouseCursor), |
| materialTapTargetSize: themeMaterialTapTargetSize, |
| overlayColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.focused)) { |
| return themeFocusOverlayColor; |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return themeHoverOverlayColor; |
| } |
| return null; |
| }), |
| splashRadius: themeSplashRadius, |
| thumbIcon: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return null; |
| } |
| return null; |
| }), |
| ), |
| ); |
| |
| Widget buildSwitch({bool selected = false, bool autofocus = false}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: Switch( |
| value: selected, |
| onChanged: (bool value) {}, |
| autofocus: autofocus, |
| thumbColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedThumbColor; |
| } |
| return defaultThumbColor; |
| }), |
| trackColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedTrackColor; |
| } |
| return defaultTrackColor; |
| }), |
| trackOutlineColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedOutlineColor; |
| } |
| return defaultOutlineColor; |
| }), |
| trackOutlineWidth: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedOutlineWidth; |
| } |
| return defaultOutlineWidth; |
| }), |
| mouseCursor: mouseCursor, |
| materialTapTargetSize: materialTapTargetSize, |
| focusColor: focusColor, |
| hoverColor: hoverColor, |
| splashRadius: splashRadius, |
| thumbIcon: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return const Icon(Icons.add); |
| } |
| return const Icon(Icons.access_alarm); |
| }), |
| ), |
| ), |
| ); |
| } |
| |
| // Switch. |
| await tester.pumpWidget(buildSwitch()); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: defaultTrackColor) |
| ..rrect(color: defaultOutlineColor, strokeWidth: defaultOutlineWidth) |
| ..rrect(color: defaultThumbColor)..paragraph(offset: const Offset(12, 12)) |
| ); |
| // Size from MaterialTapTargetSize.shrinkWrap. |
| expect(tester.getSize(find.byType(Switch)), const Size(60.0, 40.0)); |
| |
| // Selected switch. |
| await tester.pumpWidget(buildSwitch(selected: true)); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: selectedTrackColor)..rrect(color: selectedOutlineColor, strokeWidth: selectedOutlineWidth) |
| ..rrect(color: selectedThumbColor) |
| ); |
| |
| // Switch with hover. |
| await tester.pumpWidget(buildSwitch()); |
| await _pointGestureToSwitch(tester); |
| await tester.pumpAndSettle(); |
| expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); |
| expect(_getSwitchMaterial(tester), paints..circle(color: hoverColor)); |
| |
| // Switch with focus. |
| await tester.pumpWidget(buildSwitch(autofocus: true)); |
| await tester.pumpAndSettle(); |
| expect(_getSwitchMaterial(tester), paints..circle(color: focusColor, radius: splashRadius)); |
| }); |
| |
| testWidgetsWithLeakTracking('Material2 - Switch active and inactive properties are taken over the theme values', (WidgetTester tester) async { |
| tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; |
| |
| const Color themeDefaultThumbColor = Color(0xfffffff0); |
| const Color themeSelectedThumbColor = Color(0xfffffff1); |
| const Color themeDefaultTrackColor = Color(0xfffffff2); |
| const Color themeSelectedTrackColor = Color(0xfffffff3); |
| |
| const Color defaultThumbColor = Color(0xffffff0f); |
| const Color selectedThumbColor = Color(0xffffff1f); |
| const Color defaultTrackColor = Color(0xffffff2f); |
| const Color selectedTrackColor = Color(0xffffff3f); |
| |
| final ThemeData themeData = ThemeData( |
| useMaterial3: false, |
| switchTheme: SwitchThemeData( |
| thumbColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedThumbColor; |
| } |
| return themeDefaultThumbColor; |
| }), |
| trackColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedTrackColor; |
| } |
| return themeDefaultTrackColor; |
| }), |
| ), |
| ); |
| |
| Widget buildSwitch({bool selected = false, bool autofocus = false}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: Switch( |
| value: selected, |
| onChanged: (bool value) {}, |
| autofocus: autofocus, |
| activeColor: selectedThumbColor, |
| inactiveThumbColor: defaultThumbColor, |
| activeTrackColor: selectedTrackColor, |
| inactiveTrackColor: defaultTrackColor, |
| ), |
| ), |
| ); |
| } |
| |
| // Unselected switch. |
| await tester.pumpWidget(buildSwitch()); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: defaultTrackColor) |
| ..rrect() |
| ..rrect() |
| ..rrect() |
| ..rrect(color: defaultThumbColor) |
| ); |
| |
| // Selected switch. |
| await tester.pumpWidget(buildSwitch(selected: true)); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: selectedTrackColor) |
| ..rrect() |
| ..rrect() |
| ..rrect() |
| ..rrect(color: selectedThumbColor) |
| ); |
| }); |
| |
| testWidgetsWithLeakTracking('Material3 - Switch active and inactive properties are taken over the theme values', (WidgetTester tester) async { |
| tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; |
| |
| const Color themeDefaultThumbColor = Color(0xfffffff0); |
| const Color themeSelectedThumbColor = Color(0xfffffff1); |
| const Color themeDefaultTrackColor = Color(0xfffffff2); |
| const Color themeSelectedTrackColor = Color(0xfffffff3); |
| |
| const Color defaultThumbColor = Color(0xffffff0f); |
| const Color selectedThumbColor = Color(0xffffff1f); |
| const Color defaultTrackColor = Color(0xffffff2f); |
| const Color selectedTrackColor = Color(0xffffff3f); |
| |
| final ThemeData themeData = ThemeData( |
| useMaterial3: true, |
| switchTheme: SwitchThemeData( |
| thumbColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedThumbColor; |
| } |
| return themeDefaultThumbColor; |
| }), |
| trackColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return themeSelectedTrackColor; |
| } |
| return themeDefaultTrackColor; |
| }), |
| ), |
| ); |
| |
| Widget buildSwitch({bool selected = false, bool autofocus = false}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: Switch( |
| value: selected, |
| onChanged: (bool value) {}, |
| autofocus: autofocus, |
| activeColor: selectedThumbColor, |
| inactiveThumbColor: defaultThumbColor, |
| activeTrackColor: selectedTrackColor, |
| inactiveTrackColor: defaultTrackColor, |
| ), |
| ), |
| ); |
| } |
| |
| // Unselected switch. |
| await tester.pumpWidget(buildSwitch()); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: defaultTrackColor) |
| ..rrect(color: themeData.colorScheme.outline) |
| ..rrect(color: defaultThumbColor) |
| ); |
| |
| // Selected switch. |
| await tester.pumpWidget(buildSwitch(selected: true)); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: selectedTrackColor) |
| ..rrect() |
| ..rrect(color: selectedThumbColor) |
| ); |
| }); |
| |
| testWidgetsWithLeakTracking('Material2 - Switch 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; |
| final ThemeData themeData = ThemeData( |
| useMaterial3: false, |
| switchTheme: SwitchThemeData( |
| overlayColor: MaterialStateProperty.resolveWith(getOverlayColor), |
| splashRadius: splashRadius, |
| ), |
| ); |
| |
| Widget buildSwitch({required bool active}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: Switch( |
| value: active, |
| onChanged: (_) { }, |
| ), |
| ), |
| ); |
| } |
| |
| await tester.pumpWidget(buildSwitch(active: false)); |
| await tester.press(find.byType(Switch)); |
| await tester.pumpAndSettle(); |
| |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect() |
| ..circle( |
| color: inactivePressedOverlayColor, |
| radius: splashRadius, |
| ), |
| reason: 'Inactive pressed Switch should have overlay color: $inactivePressedOverlayColor', |
| ); |
| |
| await tester.pumpWidget(buildSwitch(active: true)); |
| await tester.press(find.byType(Switch)); |
| await tester.pumpAndSettle(); |
| |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect() |
| ..circle( |
| color: activePressedOverlayColor, |
| radius: splashRadius, |
| ), |
| reason: 'Active pressed Switch should have overlay color: $activePressedOverlayColor', |
| ); |
| }); |
| |
| testWidgetsWithLeakTracking('Material3 - Switch 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; |
| final ThemeData themeData = ThemeData( |
| useMaterial3: true, |
| switchTheme: SwitchThemeData( |
| overlayColor: MaterialStateProperty.resolveWith(getOverlayColor), |
| splashRadius: splashRadius, |
| ), |
| ); |
| |
| Widget buildSwitch({required bool active}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: Switch( |
| value: active, |
| onChanged: (_) { }, |
| ), |
| ), |
| ); |
| } |
| |
| await tester.pumpWidget(buildSwitch(active: false)); |
| await tester.press(find.byType(Switch)); |
| await tester.pumpAndSettle(); |
| |
| expect( |
| _getSwitchMaterial(tester), |
| (paints |
| ..rrect() |
| ..rrect()) |
| ..circle( |
| color: inactivePressedOverlayColor, |
| radius: splashRadius, |
| ), |
| reason: 'Inactive pressed Switch should have overlay color: $inactivePressedOverlayColor', |
| ); |
| |
| await tester.pumpWidget(buildSwitch(active: true)); |
| await tester.press(find.byType(Switch)); |
| await tester.pumpAndSettle(); |
| |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect() |
| ..circle( |
| color: activePressedOverlayColor, |
| radius: splashRadius, |
| ), |
| reason: 'Active pressed Switch should have overlay color: $activePressedOverlayColor', |
| ); |
| }); |
| |
| testWidgetsWithLeakTracking('Material2 - Local SwitchTheme can override global SwitchTheme', (WidgetTester tester) async { |
| const Color globalThemeThumbColor = Color(0xfffffff1); |
| const Color globalThemeTrackColor = Color(0xfffffff2); |
| const Color globalThemeOutlineColor = Color(0xfffffff3); |
| const double globalThemeOutlineWidth = 6.0; |
| const Color localThemeThumbColor = Color(0xffff0000); |
| const Color localThemeTrackColor = Color(0xffff0000); |
| const Color localThemeOutlineColor = Color(0xffff0000); |
| const double localThemeOutlineWidth = 4.0; |
| |
| final ThemeData themeData = ThemeData( |
| useMaterial3: false, |
| switchTheme: const SwitchThemeData( |
| thumbColor: MaterialStatePropertyAll<Color>(globalThemeThumbColor), |
| trackColor: MaterialStatePropertyAll<Color>(globalThemeTrackColor), |
| trackOutlineColor: MaterialStatePropertyAll<Color>(globalThemeOutlineColor), |
| trackOutlineWidth: MaterialStatePropertyAll<double>(globalThemeOutlineWidth), |
| ), |
| ); |
| Widget buildSwitch({bool selected = false, bool autofocus = false}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: SwitchTheme( |
| data: const SwitchThemeData( |
| thumbColor: MaterialStatePropertyAll<Color>(localThemeThumbColor), |
| trackColor: MaterialStatePropertyAll<Color>(localThemeTrackColor), |
| trackOutlineColor: MaterialStatePropertyAll<Color>(localThemeOutlineColor), |
| trackOutlineWidth: MaterialStatePropertyAll<double>(localThemeOutlineWidth) |
| ), |
| child: Switch( |
| value: selected, |
| onChanged: (bool value) {}, |
| autofocus: autofocus, |
| ), |
| ), |
| ), |
| ); |
| } |
| |
| await tester.pumpWidget(buildSwitch(selected: true)); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: localThemeTrackColor) |
| ..rrect(color: localThemeOutlineColor, strokeWidth: localThemeOutlineWidth) |
| ..rrect() |
| ..rrect() |
| ..rrect() |
| ..rrect(color: localThemeThumbColor) |
| ); |
| }); |
| |
| testWidgetsWithLeakTracking('Material3 - Local SwitchTheme can override global SwitchTheme', (WidgetTester tester) async { |
| const Color globalThemeThumbColor = Color(0xfffffff1); |
| const Color globalThemeTrackColor = Color(0xfffffff2); |
| const Color globalThemeOutlineColor = Color(0xfffffff3); |
| const double globalThemeOutlineWidth = 6.0; |
| const Color localThemeThumbColor = Color(0xffff0000); |
| const Color localThemeTrackColor = Color(0xffff0000); |
| const Color localThemeOutlineColor = Color(0xffff0000); |
| const double localThemeOutlineWidth = 4.0; |
| |
| final ThemeData themeData = ThemeData( |
| useMaterial3: true, |
| switchTheme: const SwitchThemeData( |
| thumbColor: MaterialStatePropertyAll<Color>(globalThemeThumbColor), |
| trackColor: MaterialStatePropertyAll<Color>(globalThemeTrackColor), |
| trackOutlineColor: MaterialStatePropertyAll<Color>(globalThemeOutlineColor), |
| trackOutlineWidth: MaterialStatePropertyAll<double>(globalThemeOutlineWidth), |
| ), |
| ); |
| Widget buildSwitch({bool selected = false, bool autofocus = false}) { |
| return MaterialApp( |
| theme: themeData, |
| home: Scaffold( |
| body: SwitchTheme( |
| data: const SwitchThemeData( |
| thumbColor: MaterialStatePropertyAll<Color>(localThemeThumbColor), |
| trackColor: MaterialStatePropertyAll<Color>(localThemeTrackColor), |
| trackOutlineColor: MaterialStatePropertyAll<Color>(localThemeOutlineColor), |
| trackOutlineWidth: MaterialStatePropertyAll<double>(localThemeOutlineWidth) |
| ), |
| child: Switch( |
| value: selected, |
| onChanged: (bool value) {}, |
| autofocus: autofocus, |
| ), |
| ), |
| ), |
| ); |
| } |
| |
| await tester.pumpWidget(buildSwitch(selected: true)); |
| await tester.pumpAndSettle(); |
| expect( |
| _getSwitchMaterial(tester), |
| paints |
| ..rrect(color: localThemeTrackColor) |
| ..rrect(color: localThemeOutlineColor, strokeWidth: localThemeOutlineWidth) |
| ..rrect(color: localThemeThumbColor) |
| ); |
| }); |
| } |
| |
| Future<void> _pointGestureToSwitch(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(Switch))); |
| } |
| |
| MaterialInkController? _getSwitchMaterial(WidgetTester tester) { |
| return Material.of(tester.element(find.byType(Switch))); |
| } |