mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
WIP Commits separated as follows: - Update lints in analysis_options files - Run `dart fix --apply` - Clean up leftover analysis issues - Run `dart format .` in the right places. Local analysis and testing passes. Checking CI now. Part of https://github.com/flutter/flutter/issues/178827 - Adoption of flutter_lints in examples/api coming in a separate change (cc @loic-sharma) ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- 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
1187 lines
46 KiB
Dart
1187 lines
46 KiB
Dart
// 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/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
test('TimePickerThemeData copyWith, ==, hashCode basics', () {
|
|
expect(const TimePickerThemeData(), const TimePickerThemeData().copyWith());
|
|
expect(const TimePickerThemeData().hashCode, const TimePickerThemeData().copyWith().hashCode);
|
|
});
|
|
|
|
test('TimePickerThemeData lerp special cases', () {
|
|
const data = TimePickerThemeData();
|
|
expect(identical(TimePickerThemeData.lerp(data, data, 0.5), data), true);
|
|
});
|
|
|
|
test('TimePickerThemeData has null fields by default', () {
|
|
const timePickerTheme = TimePickerThemeData();
|
|
expect(timePickerTheme.backgroundColor, null);
|
|
expect(timePickerTheme.cancelButtonStyle, null);
|
|
expect(timePickerTheme.confirmButtonStyle, null);
|
|
expect(timePickerTheme.dayPeriodBorderSide, null);
|
|
expect(timePickerTheme.dayPeriodColor, null);
|
|
expect(timePickerTheme.dayPeriodShape, null);
|
|
expect(timePickerTheme.dayPeriodTextColor, null);
|
|
expect(timePickerTheme.dayPeriodTextStyle, null);
|
|
expect(timePickerTheme.dialBackgroundColor, null);
|
|
expect(timePickerTheme.dialHandColor, null);
|
|
expect(timePickerTheme.dialTextColor, null);
|
|
expect(timePickerTheme.dialTextStyle, null);
|
|
expect(timePickerTheme.elevation, null);
|
|
expect(timePickerTheme.entryModeIconColor, null);
|
|
expect(timePickerTheme.helpTextStyle, null);
|
|
expect(timePickerTheme.hourMinuteColor, null);
|
|
expect(timePickerTheme.hourMinuteShape, null);
|
|
expect(timePickerTheme.hourMinuteTextColor, null);
|
|
expect(timePickerTheme.hourMinuteTextStyle, null);
|
|
expect(timePickerTheme.inputDecorationTheme, null);
|
|
expect(timePickerTheme.entryModeIconColor, null);
|
|
expect(timePickerTheme.padding, null);
|
|
expect(timePickerTheme.shape, null);
|
|
expect(timePickerTheme.timeSelectorSeparatorColor, null);
|
|
expect(timePickerTheme.timeSelectorSeparatorTextStyle, null);
|
|
});
|
|
|
|
testWidgets('Default TimePickerThemeData debugFillProperties', (WidgetTester tester) async {
|
|
final builder = DiagnosticPropertiesBuilder();
|
|
const TimePickerThemeData().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('TimePickerThemeData implements debugFillProperties', (WidgetTester tester) async {
|
|
final builder = DiagnosticPropertiesBuilder();
|
|
const TimePickerThemeData(
|
|
backgroundColor: Color(0xfffffff0),
|
|
cancelButtonStyle: ButtonStyle(
|
|
foregroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff1)),
|
|
),
|
|
confirmButtonStyle: ButtonStyle(
|
|
foregroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff2)),
|
|
),
|
|
dayPeriodBorderSide: BorderSide(color: Color(0xfffffff3)),
|
|
dayPeriodColor: Color(0x00000000),
|
|
dayPeriodShape: RoundedRectangleBorder(side: BorderSide(color: Color(0xfffffff5))),
|
|
dayPeriodTextColor: Color(0xfffffff6),
|
|
dayPeriodTextStyle: TextStyle(color: Color(0xfffffff7)),
|
|
dialBackgroundColor: Color(0xfffffff8),
|
|
dialHandColor: Color(0xfffffff9),
|
|
dialTextColor: Color(0xfffffffa),
|
|
dialTextStyle: TextStyle(color: Color(0xfffffffb)),
|
|
elevation: 1.0,
|
|
entryModeIconColor: Color(0xfffffffc),
|
|
helpTextStyle: TextStyle(color: Color(0xfffffffd)),
|
|
hourMinuteColor: Color(0xfffffffe),
|
|
hourMinuteShape: RoundedRectangleBorder(side: BorderSide(color: Color(0xffffffff))),
|
|
hourMinuteTextColor: Color(0xfffffff0),
|
|
hourMinuteTextStyle: TextStyle(color: Color(0xfffffff1)),
|
|
inputDecorationTheme: InputDecorationTheme(labelStyle: TextStyle(color: Color(0xfffffff2))),
|
|
padding: EdgeInsets.all(1.0),
|
|
shape: RoundedRectangleBorder(side: BorderSide(color: Color(0xfffffff3))),
|
|
timeSelectorSeparatorColor: WidgetStatePropertyAll<Color>(Color(0xfffffff4)),
|
|
timeSelectorSeparatorTextStyle: WidgetStatePropertyAll<TextStyle>(
|
|
TextStyle(color: Color(0xfffffff5)),
|
|
),
|
|
).debugFillProperties(builder);
|
|
|
|
final List<String> description = builder.properties
|
|
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
|
.map((DiagnosticsNode node) => node.toString())
|
|
.toList();
|
|
|
|
expect(
|
|
description,
|
|
equalsIgnoringHashCodes(<String>[
|
|
'backgroundColor: ${const Color(0xfffffff0)}',
|
|
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(${const Color(0xfffffff1)}))',
|
|
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(${const Color(0xfffffff2)}))',
|
|
'dayPeriodBorderSide: BorderSide(color: ${const Color(0xfffffff3)})',
|
|
'dayPeriodColor: ${const Color(0x00000000)}',
|
|
'dayPeriodShape: RoundedRectangleBorder(BorderSide(color: ${const Color(0xfffffff5)}), BorderRadius.zero)',
|
|
'dayPeriodTextColor: ${const Color(0xfffffff6)}',
|
|
'dayPeriodTextStyle: TextStyle(inherit: true, color: ${const Color(0xfffffff7)})',
|
|
'dialBackgroundColor: ${const Color(0xfffffff8)}',
|
|
'dialHandColor: ${const Color(0xfffffff9)}',
|
|
'dialTextColor: ${const Color(0xfffffffa)}',
|
|
'dialTextStyle: TextStyle(inherit: true, color: ${const Color(0xfffffffb)})',
|
|
'elevation: 1.0',
|
|
'entryModeIconColor: ${const Color(0xfffffffc)}',
|
|
'helpTextStyle: TextStyle(inherit: true, color: ${const Color(0xfffffffd)})',
|
|
'hourMinuteColor: ${const Color(0xfffffffe)}',
|
|
'hourMinuteShape: RoundedRectangleBorder(BorderSide(color: ${const Color(0xffffffff)}), BorderRadius.zero)',
|
|
'hourMinuteTextColor: ${const Color(0xfffffff0)}',
|
|
'hourMinuteTextStyle: TextStyle(inherit: true, color: ${const Color(0xfffffff1)})',
|
|
'inputDecorationTheme: InputDecorationThemeData#ff861(labelStyle: TextStyle(inherit: true, color: ${const Color(0xfffffff2)}))',
|
|
'padding: EdgeInsets.all(1.0)',
|
|
'shape: RoundedRectangleBorder(BorderSide(color: ${const Color(0xfffffff3)}), BorderRadius.zero)',
|
|
'timeSelectorSeparatorColor: WidgetStatePropertyAll(${const Color(0xfffffff4)})',
|
|
'timeSelectorSeparatorTextStyle: WidgetStatePropertyAll(TextStyle(inherit: true, color: ${const Color(0xfffffff5)}))',
|
|
]),
|
|
);
|
|
});
|
|
|
|
test(
|
|
'TimePickerThemeData.inputDecorationTheme accepts only InputDecorationTheme or InputDecorationThemeData instances',
|
|
() {
|
|
const decorationTheme = InputDecorationTheme();
|
|
var timePickerTheme = const TimePickerThemeData(inputDecorationTheme: decorationTheme);
|
|
expect(timePickerTheme.inputDecorationTheme, decorationTheme.data);
|
|
|
|
timePickerTheme = TimePickerThemeData(inputDecorationTheme: decorationTheme.data);
|
|
expect(timePickerTheme.inputDecorationTheme, decorationTheme.data);
|
|
|
|
// Wrong type throws.
|
|
expect(() {
|
|
TimePickerThemeData(inputDecorationTheme: Object());
|
|
}, throwsA(isA<AssertionError>()));
|
|
},
|
|
);
|
|
|
|
testWidgets('Material2 - Passing no TimePickerThemeData uses defaults', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final defaultTheme = ThemeData(useMaterial3: false);
|
|
await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme));
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final Material dialogMaterial = _dialogMaterial(tester);
|
|
expect(dialogMaterial.color, defaultTheme.colorScheme.surface);
|
|
expect(
|
|
dialogMaterial.shape,
|
|
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))),
|
|
);
|
|
|
|
final RenderBox dial = tester.firstRenderObject<RenderBox>(find.byType(CustomPaint));
|
|
expect(
|
|
dial,
|
|
paints
|
|
..circle(
|
|
color: defaultTheme.colorScheme.onSurface.withOpacity(0.08),
|
|
) // Dial background color.
|
|
..circle(color: Color(defaultTheme.colorScheme.primary.value)),
|
|
);
|
|
|
|
final RenderParagraph hourText = _textRenderParagraph(tester, '7');
|
|
expect(
|
|
hourText.text.style,
|
|
Typography.material2014().englishLike.displayMedium!
|
|
.merge(Typography.material2014().black.displayMedium)
|
|
.copyWith(color: defaultTheme.colorScheme.primary),
|
|
);
|
|
|
|
final RenderParagraph minuteText = _textRenderParagraph(tester, '15');
|
|
expect(
|
|
minuteText.text.style,
|
|
Typography.material2014().englishLike.displayMedium!
|
|
.merge(Typography.material2014().black.displayMedium)
|
|
.copyWith(color: defaultTheme.colorScheme.onSurface),
|
|
);
|
|
|
|
final RenderParagraph amText = _textRenderParagraph(tester, 'AM');
|
|
expect(
|
|
amText.text.style,
|
|
Typography.material2014().englishLike.titleMedium!
|
|
.merge(Typography.material2014().black.titleMedium)
|
|
.copyWith(color: defaultTheme.colorScheme.primary),
|
|
);
|
|
|
|
final RenderParagraph pmText = _textRenderParagraph(tester, 'PM');
|
|
expect(
|
|
pmText.text.style,
|
|
Typography.material2014().englishLike.titleMedium!
|
|
.merge(Typography.material2014().black.titleMedium)
|
|
.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.6)),
|
|
);
|
|
|
|
final RenderParagraph helperText = _textRenderParagraph(tester, 'SELECT TIME');
|
|
expect(
|
|
helperText.text.style,
|
|
Typography.material2014().englishLike.labelSmall!.merge(
|
|
Typography.material2014().black.labelSmall,
|
|
),
|
|
);
|
|
|
|
final CustomPaint dialPaint = tester.widget(findDialPaint);
|
|
final dynamic dialPainter = dialPaint.painter;
|
|
// ignore: avoid_dynamic_calls
|
|
final primaryLabels = dialPainter.primaryLabels as List<dynamic>;
|
|
expect(
|
|
// ignore: avoid_dynamic_calls
|
|
primaryLabels.first.painter.text.style,
|
|
Typography.material2014().englishLike.bodyLarge!
|
|
.merge(Typography.material2014().black.bodyLarge)
|
|
.copyWith(color: defaultTheme.colorScheme.onSurface),
|
|
);
|
|
// ignore: avoid_dynamic_calls
|
|
final selectedLabels = dialPainter.selectedLabels as List<dynamic>;
|
|
expect(
|
|
// ignore: avoid_dynamic_calls
|
|
selectedLabels.first.painter.text.style,
|
|
Typography.material2014().englishLike.bodyLarge!
|
|
.merge(Typography.material2014().white.bodyLarge)
|
|
.copyWith(color: defaultTheme.colorScheme.onPrimary),
|
|
);
|
|
|
|
final Material hourMaterial = _textMaterial(tester, '7');
|
|
expect(hourMaterial.color, defaultTheme.colorScheme.primary.withOpacity(0.12));
|
|
expect(
|
|
hourMaterial.shape,
|
|
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))),
|
|
);
|
|
|
|
final Material minuteMaterial = _textMaterial(tester, '15');
|
|
expect(minuteMaterial.color, defaultTheme.colorScheme.onSurface.withOpacity(0.12));
|
|
expect(
|
|
minuteMaterial.shape,
|
|
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))),
|
|
);
|
|
|
|
final Material amMaterial = _textMaterial(tester, 'AM');
|
|
expect(amMaterial.color, defaultTheme.colorScheme.primary.withOpacity(0.12));
|
|
|
|
final Material pmMaterial = _textMaterial(tester, 'PM');
|
|
expect(pmMaterial.color, Colors.transparent);
|
|
|
|
final Color expectedBorderColor = Color.alphaBlend(
|
|
defaultTheme.colorScheme.onSurface.withOpacity(0.38),
|
|
defaultTheme.colorScheme.surface,
|
|
);
|
|
|
|
final expectedAmShape = RoundedRectangleBorder(
|
|
side: BorderSide(color: expectedBorderColor),
|
|
borderRadius: const BorderRadius.only(
|
|
topLeft: Radius.circular(4.0),
|
|
bottomLeft: Radius.circular(4.0),
|
|
),
|
|
);
|
|
expect(amMaterial.shape, expectedAmShape);
|
|
|
|
final expectedPmShape = RoundedRectangleBorder(
|
|
side: BorderSide(color: expectedBorderColor),
|
|
borderRadius: const BorderRadius.only(
|
|
topRight: Radius.circular(4.0),
|
|
bottomRight: Radius.circular(4.0),
|
|
),
|
|
);
|
|
expect(pmMaterial.shape, expectedPmShape);
|
|
|
|
expect(
|
|
find.descendant(
|
|
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl'),
|
|
matching: find.byType(Container),
|
|
),
|
|
findsNothing,
|
|
);
|
|
|
|
final IconButton entryModeIconButton = _entryModeIconButton(tester);
|
|
expect(entryModeIconButton.color, defaultTheme.colorScheme.onSurface.withOpacity(0.6));
|
|
|
|
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL');
|
|
expect(
|
|
cancelButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
|
);
|
|
|
|
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
|
|
expect(
|
|
confirmButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
|
);
|
|
});
|
|
|
|
testWidgets('Material3 - Passing no TimePickerThemeData uses defaults', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final defaultTheme = ThemeData();
|
|
await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme));
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final Material dialogMaterial = _dialogMaterial(tester);
|
|
expect(dialogMaterial.color, defaultTheme.colorScheme.surfaceContainerHigh);
|
|
expect(
|
|
dialogMaterial.shape,
|
|
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))),
|
|
);
|
|
|
|
final RenderBox dial = tester.firstRenderObject<RenderBox>(find.byType(CustomPaint));
|
|
expect(
|
|
dial,
|
|
paints
|
|
..circle(color: defaultTheme.colorScheme.surfaceContainerHighest) // Dial background color.
|
|
..circle(color: Color(defaultTheme.colorScheme.primary.value)), // Dial hand color.
|
|
);
|
|
|
|
final RenderParagraph hourText = _textRenderParagraph(tester, '7');
|
|
expect(
|
|
hourText.text.style,
|
|
Typography.material2021().englishLike.displayLarge!
|
|
.merge(Typography.material2021().black.displayLarge)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onPrimaryContainer,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final RenderParagraph minuteText = _textRenderParagraph(tester, '15');
|
|
expect(
|
|
minuteText.text.style,
|
|
Typography.material2021().englishLike.displayLarge!
|
|
.merge(Typography.material2021().black.displayLarge)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onSurface,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final RenderParagraph amText = _textRenderParagraph(tester, 'AM');
|
|
expect(
|
|
amText.text.style,
|
|
Typography.material2021().englishLike.titleMedium!
|
|
.merge(Typography.material2021().black.titleMedium)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onTertiaryContainer,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final RenderParagraph pmText = _textRenderParagraph(tester, 'PM');
|
|
expect(
|
|
pmText.text.style,
|
|
Typography.material2021().englishLike.titleMedium!
|
|
.merge(Typography.material2021().black.titleMedium)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onSurfaceVariant,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final RenderParagraph helperText = _textRenderParagraph(tester, 'Select time');
|
|
expect(
|
|
helperText.text.style,
|
|
Typography.material2021().englishLike.bodyMedium!
|
|
.merge(Typography.material2021().black.bodyMedium)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onSurface,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final CustomPaint dialPaint = tester.widget(findDialPaint);
|
|
final dynamic dialPainter = dialPaint.painter;
|
|
// ignore: avoid_dynamic_calls
|
|
final primaryLabels = dialPainter.primaryLabels as List<dynamic>;
|
|
expect(
|
|
// ignore: avoid_dynamic_calls
|
|
primaryLabels.first.painter.text.style,
|
|
Typography.material2021().englishLike.bodyLarge!
|
|
.merge(Typography.material2021().black.bodyLarge)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onSurface,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
// ignore: avoid_dynamic_calls
|
|
final selectedLabels = dialPainter.selectedLabels as List<dynamic>;
|
|
expect(
|
|
// ignore: avoid_dynamic_calls
|
|
selectedLabels.first.painter.text.style,
|
|
Typography.material2021().englishLike.bodyLarge!
|
|
.merge(Typography.material2021().black.bodyLarge)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onPrimary,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final Material hourMaterial = _textMaterial(tester, '7');
|
|
expect(hourMaterial.color, defaultTheme.colorScheme.primaryContainer);
|
|
expect(
|
|
hourMaterial.shape,
|
|
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),
|
|
);
|
|
|
|
final Material minuteMaterial = _textMaterial(tester, '15');
|
|
expect(minuteMaterial.color, defaultTheme.colorScheme.surfaceContainerHighest);
|
|
expect(
|
|
minuteMaterial.shape,
|
|
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),
|
|
);
|
|
|
|
final Material amMaterial = _textMaterial(tester, 'AM');
|
|
expect(amMaterial.color, defaultTheme.colorScheme.tertiaryContainer);
|
|
|
|
final Material pmMaterial = _textMaterial(tester, 'PM');
|
|
expect(pmMaterial.color, Colors.transparent);
|
|
|
|
final expectedAmShape = RoundedRectangleBorder(
|
|
side: BorderSide(color: defaultTheme.colorScheme.outline),
|
|
borderRadius: const BorderRadius.only(
|
|
topLeft: Radius.circular(8.0),
|
|
bottomLeft: Radius.circular(8.0),
|
|
),
|
|
);
|
|
expect(amMaterial.shape, expectedAmShape);
|
|
|
|
final expectedPmShape = RoundedRectangleBorder(
|
|
side: BorderSide(color: defaultTheme.colorScheme.outline),
|
|
borderRadius: const BorderRadius.only(
|
|
topRight: Radius.circular(8.0),
|
|
bottomRight: Radius.circular(8.0),
|
|
),
|
|
);
|
|
expect(pmMaterial.shape, expectedPmShape);
|
|
|
|
expect(
|
|
find.descendant(
|
|
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl'),
|
|
matching: find.byType(Container),
|
|
),
|
|
findsNothing,
|
|
);
|
|
|
|
final IconButton entryModeIconButton = _entryModeIconButton(tester);
|
|
expect(entryModeIconButton.color, null);
|
|
|
|
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel');
|
|
expect(
|
|
cancelButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
|
);
|
|
|
|
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
|
|
expect(
|
|
confirmButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
|
);
|
|
});
|
|
|
|
testWidgets('Material2 - Passing no TimePickerThemeData uses defaults - input mode', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final defaultTheme = ThemeData(useMaterial3: false);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: defaultTheme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final InputDecoration hourDecoration = _textField(tester, '7').decoration!;
|
|
expect(hourDecoration.filled, true);
|
|
expect(
|
|
hourDecoration.fillColor,
|
|
WidgetStateColor.resolveWith(
|
|
(Set<WidgetState> states) => defaultTheme.colorScheme.onSurface.withOpacity(0.12),
|
|
),
|
|
);
|
|
expect(
|
|
hourDecoration.enabledBorder,
|
|
const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)),
|
|
);
|
|
expect(
|
|
hourDecoration.errorBorder,
|
|
OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2)),
|
|
);
|
|
expect(
|
|
hourDecoration.focusedBorder,
|
|
OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2)),
|
|
);
|
|
expect(
|
|
hourDecoration.focusedErrorBorder,
|
|
OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2)),
|
|
);
|
|
expect(
|
|
hourDecoration.hintStyle,
|
|
Typography.material2014().englishLike.displayMedium!.merge(
|
|
defaultTheme.textTheme.displayMedium!.copyWith(
|
|
color: defaultTheme.colorScheme.onSurface.withOpacity(0.36),
|
|
),
|
|
),
|
|
);
|
|
|
|
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL');
|
|
expect(
|
|
cancelButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
|
);
|
|
|
|
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
|
|
expect(
|
|
confirmButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
|
);
|
|
});
|
|
|
|
testWidgets('Material3 - Passing no TimePickerThemeData uses defaults - input mode', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final defaultTheme = ThemeData();
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: defaultTheme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final TextStyle hourTextStyle = _textField(tester, '7').style!;
|
|
expect(
|
|
hourTextStyle,
|
|
Typography.material2021().englishLike.displayMedium!
|
|
.merge(Typography.material2021().black.displayMedium)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onSurface,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final TextStyle minuteTextStyle = _textField(tester, '15').style!;
|
|
expect(
|
|
minuteTextStyle,
|
|
Typography.material2021().englishLike.displayMedium!
|
|
.merge(Typography.material2021().black.displayMedium)
|
|
.copyWith(
|
|
color: defaultTheme.colorScheme.onSurface,
|
|
decorationColor: defaultTheme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final InputDecoration hourDecoration = _textField(tester, '7').decoration!;
|
|
expect(hourDecoration.filled, true);
|
|
expect(hourDecoration.fillColor, defaultTheme.colorScheme.surfaceContainerHighest);
|
|
expect(
|
|
hourDecoration.enabledBorder,
|
|
const OutlineInputBorder(
|
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
|
borderSide: BorderSide(color: Colors.transparent),
|
|
),
|
|
);
|
|
expect(
|
|
hourDecoration.errorBorder,
|
|
OutlineInputBorder(
|
|
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
|
borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0),
|
|
),
|
|
);
|
|
expect(
|
|
hourDecoration.focusedBorder,
|
|
OutlineInputBorder(
|
|
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
|
borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2.0),
|
|
),
|
|
);
|
|
expect(
|
|
hourDecoration.focusedErrorBorder,
|
|
OutlineInputBorder(
|
|
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
|
borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0),
|
|
),
|
|
);
|
|
expect(
|
|
hourDecoration.hintStyle,
|
|
TextStyle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)),
|
|
);
|
|
|
|
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel');
|
|
expect(
|
|
cancelButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
|
);
|
|
|
|
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
|
|
expect(
|
|
confirmButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
|
);
|
|
});
|
|
|
|
testWidgets('Material2 - Time picker uses values from TimePickerThemeData', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme();
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme, useMaterial3: false);
|
|
await tester.pumpWidget(_TimePickerLauncher(themeData: theme));
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final Material dialogMaterial = _dialogMaterial(tester);
|
|
expect(dialogMaterial.color, timePickerTheme.backgroundColor);
|
|
expect(dialogMaterial.shape, timePickerTheme.shape);
|
|
|
|
final RenderBox dial = tester.firstRenderObject<RenderBox>(find.byType(CustomPaint));
|
|
expect(
|
|
dial,
|
|
paints
|
|
..circle(color: Color(timePickerTheme.dialBackgroundColor!.value)) // Dial background color.
|
|
..circle(color: Color(timePickerTheme.dialHandColor!.value)), // Dial hand color.
|
|
);
|
|
|
|
final RenderParagraph hourText = _textRenderParagraph(tester, '7');
|
|
expect(
|
|
hourText.text.style,
|
|
Typography.material2014().englishLike.bodyMedium!
|
|
.merge(Typography.material2014().black.bodyMedium)
|
|
.merge(timePickerTheme.hourMinuteTextStyle)
|
|
.copyWith(color: _selectedColor),
|
|
);
|
|
|
|
final RenderParagraph minuteText = _textRenderParagraph(tester, '15');
|
|
expect(
|
|
minuteText.text.style,
|
|
Typography.material2014().englishLike.bodyMedium!
|
|
.merge(Typography.material2014().black.bodyMedium)
|
|
.merge(timePickerTheme.hourMinuteTextStyle)
|
|
.copyWith(color: _unselectedColor),
|
|
);
|
|
|
|
final RenderParagraph amText = _textRenderParagraph(tester, 'AM');
|
|
expect(
|
|
amText.text.style,
|
|
Typography.material2014().englishLike.titleMedium!
|
|
.merge(Typography.material2014().black.titleMedium)
|
|
.merge(timePickerTheme.dayPeriodTextStyle)
|
|
.copyWith(color: _selectedColor),
|
|
);
|
|
|
|
final RenderParagraph pmText = _textRenderParagraph(tester, 'PM');
|
|
expect(
|
|
pmText.text.style,
|
|
Typography.material2014().englishLike.titleMedium!
|
|
.merge(Typography.material2014().black.titleMedium)
|
|
.merge(timePickerTheme.dayPeriodTextStyle)
|
|
.copyWith(color: _unselectedColor),
|
|
);
|
|
|
|
final RenderParagraph helperText = _textRenderParagraph(tester, 'SELECT TIME');
|
|
expect(
|
|
helperText.text.style,
|
|
Typography.material2014().englishLike.bodyMedium!
|
|
.merge(Typography.material2014().black.bodyMedium)
|
|
.merge(timePickerTheme.helpTextStyle),
|
|
);
|
|
|
|
final CustomPaint dialPaint = tester.widget(findDialPaint);
|
|
final dynamic dialPainter = dialPaint.painter;
|
|
// ignore: avoid_dynamic_calls
|
|
final primaryLabels = dialPainter.primaryLabels as List<dynamic>;
|
|
expect(
|
|
// ignore: avoid_dynamic_calls
|
|
primaryLabels.first.painter.text.style,
|
|
Typography.material2014().englishLike.bodyLarge!
|
|
.merge(Typography.material2014().black.bodyLarge)
|
|
.copyWith(color: _unselectedColor),
|
|
);
|
|
// ignore: avoid_dynamic_calls
|
|
final selectedLabels = dialPainter.selectedLabels as List<dynamic>;
|
|
expect(
|
|
// ignore: avoid_dynamic_calls
|
|
selectedLabels.first.painter.text.style,
|
|
Typography.material2014().englishLike.bodyLarge!
|
|
.merge(Typography.material2014().white.bodyLarge)
|
|
.copyWith(color: _selectedColor),
|
|
);
|
|
|
|
final Material hourMaterial = _textMaterial(tester, '7');
|
|
expect(hourMaterial.color, _selectedColor);
|
|
expect(hourMaterial.shape, timePickerTheme.hourMinuteShape);
|
|
|
|
final Material minuteMaterial = _textMaterial(tester, '15');
|
|
expect(minuteMaterial.color, _unselectedColor);
|
|
expect(minuteMaterial.shape, timePickerTheme.hourMinuteShape);
|
|
|
|
final Material amMaterial = _textMaterial(tester, 'AM');
|
|
expect(amMaterial.color, _selectedColor);
|
|
|
|
final Material pmMaterial = _textMaterial(tester, 'PM');
|
|
expect(pmMaterial.color, _unselectedColor);
|
|
|
|
final dayPeriodShape = timePickerTheme.dayPeriodShape! as RoundedRectangleBorder;
|
|
final borderRadius = dayPeriodShape.borderRadius as BorderRadius;
|
|
|
|
final RoundedRectangleBorder expectedAmShape = dayPeriodShape.copyWith(
|
|
side: timePickerTheme.dayPeriodBorderSide,
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: borderRadius.topLeft,
|
|
bottomLeft: borderRadius.topRight,
|
|
),
|
|
);
|
|
expect(amMaterial.shape, expectedAmShape);
|
|
|
|
final RoundedRectangleBorder expectedPmShape = dayPeriodShape.copyWith(
|
|
side: timePickerTheme.dayPeriodBorderSide,
|
|
borderRadius: BorderRadius.only(
|
|
topRight: borderRadius.topLeft,
|
|
bottomRight: borderRadius.topRight,
|
|
),
|
|
);
|
|
expect(pmMaterial.shape, expectedPmShape);
|
|
|
|
expect(
|
|
find.descendant(
|
|
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl'),
|
|
matching: find.byType(Container),
|
|
),
|
|
findsNothing,
|
|
);
|
|
|
|
final IconButton entryModeIconButton = _entryModeIconButton(tester);
|
|
expect(entryModeIconButton.color, timePickerTheme.entryModeIconColor);
|
|
|
|
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL');
|
|
expect(
|
|
cancelButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(timePickerTheme.cancelButtonStyle.toString()),
|
|
);
|
|
|
|
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
|
|
expect(
|
|
confirmButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(timePickerTheme.confirmButtonStyle.toString()),
|
|
);
|
|
});
|
|
|
|
testWidgets('Material3 - Time picker uses values from TimePickerThemeData', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme();
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme);
|
|
await tester.pumpWidget(_TimePickerLauncher(themeData: theme));
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final Material dialogMaterial = _dialogMaterial(tester);
|
|
expect(dialogMaterial.color, timePickerTheme.backgroundColor);
|
|
expect(dialogMaterial.shape, timePickerTheme.shape);
|
|
|
|
final RenderBox dial = tester.firstRenderObject<RenderBox>(find.byType(CustomPaint));
|
|
expect(
|
|
dial,
|
|
paints
|
|
..circle(color: Color(timePickerTheme.dialBackgroundColor!.value)) // Dial background color.
|
|
..circle(color: Color(timePickerTheme.dialHandColor!.value)), // Dial hand color.
|
|
);
|
|
|
|
final RenderParagraph hourText = _textRenderParagraph(tester, '7');
|
|
expect(
|
|
hourText.text.style,
|
|
Typography.material2021().englishLike.bodyMedium!
|
|
.merge(Typography.material2021().black.bodyMedium)
|
|
.merge(timePickerTheme.hourMinuteTextStyle)
|
|
.copyWith(color: _selectedColor, decorationColor: const Color(0xff1d1b20)),
|
|
);
|
|
|
|
final RenderParagraph minuteText = _textRenderParagraph(tester, '15');
|
|
expect(
|
|
minuteText.text.style,
|
|
Typography.material2021().englishLike.bodyMedium!
|
|
.merge(Typography.material2021().black.bodyMedium)
|
|
.merge(timePickerTheme.hourMinuteTextStyle)
|
|
.copyWith(color: _unselectedColor, decorationColor: const Color(0xff1d1b20)),
|
|
);
|
|
|
|
final RenderParagraph amText = _textRenderParagraph(tester, 'AM');
|
|
expect(
|
|
amText.text.style,
|
|
Typography.material2021().englishLike.bodyMedium!
|
|
.merge(Typography.material2021().black.bodyMedium)
|
|
.merge(timePickerTheme.hourMinuteTextStyle)
|
|
.copyWith(color: _selectedColor, decorationColor: const Color(0xff1d1b20)),
|
|
);
|
|
|
|
final RenderParagraph pmText = _textRenderParagraph(tester, 'PM');
|
|
expect(
|
|
pmText.text.style,
|
|
Typography.material2021().englishLike.bodyMedium!
|
|
.merge(Typography.material2021().black.bodyMedium)
|
|
.merge(timePickerTheme.hourMinuteTextStyle)
|
|
.copyWith(color: _unselectedColor, decorationColor: const Color(0xff1d1b20)),
|
|
);
|
|
|
|
final RenderParagraph helperText = _textRenderParagraph(tester, 'Select time');
|
|
expect(
|
|
helperText.text.style,
|
|
Typography.material2021().englishLike.bodyMedium!
|
|
.merge(Typography.material2021().black.bodyMedium)
|
|
.merge(timePickerTheme.helpTextStyle)
|
|
.copyWith(
|
|
color: theme.colorScheme.onSurface,
|
|
decorationColor: theme.colorScheme.onSurface,
|
|
),
|
|
);
|
|
|
|
final CustomPaint dialPaint = tester.widget(findDialPaint);
|
|
final dynamic dialPainter = dialPaint.painter;
|
|
// ignore: avoid_dynamic_calls
|
|
final primaryLabels = dialPainter.primaryLabels as List<dynamic>;
|
|
expect(
|
|
// ignore: avoid_dynamic_calls
|
|
primaryLabels.first.painter.text.style,
|
|
Typography.material2021().englishLike.bodyLarge!
|
|
.merge(Typography.material2021().black.bodyLarge)
|
|
.copyWith(color: _unselectedColor, decorationColor: theme.colorScheme.onSurface),
|
|
);
|
|
// ignore: avoid_dynamic_calls
|
|
final selectedLabels = dialPainter.selectedLabels as List<dynamic>;
|
|
expect(
|
|
// ignore: avoid_dynamic_calls
|
|
selectedLabels.first.painter.text.style,
|
|
Typography.material2021().englishLike.bodyLarge!
|
|
.merge(Typography.material2021().black.bodyLarge)
|
|
.copyWith(color: _selectedColor, decorationColor: theme.colorScheme.onSurface),
|
|
);
|
|
|
|
final Material hourMaterial = _textMaterial(tester, '7');
|
|
expect(hourMaterial.color, _selectedColor);
|
|
expect(hourMaterial.shape, timePickerTheme.hourMinuteShape);
|
|
|
|
final Material minuteMaterial = _textMaterial(tester, '15');
|
|
expect(minuteMaterial.color, _unselectedColor);
|
|
expect(minuteMaterial.shape, timePickerTheme.hourMinuteShape);
|
|
|
|
final Material amMaterial = _textMaterial(tester, 'AM');
|
|
expect(amMaterial.color, _selectedColor);
|
|
|
|
final Material pmMaterial = _textMaterial(tester, 'PM');
|
|
expect(pmMaterial.color, _unselectedColor);
|
|
|
|
final dayPeriodShape = timePickerTheme.dayPeriodShape! as RoundedRectangleBorder;
|
|
final borderRadius = dayPeriodShape.borderRadius as BorderRadius;
|
|
|
|
final RoundedRectangleBorder expectedAmShape = dayPeriodShape.copyWith(
|
|
side: timePickerTheme.dayPeriodBorderSide,
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: borderRadius.topLeft,
|
|
bottomLeft: borderRadius.topRight,
|
|
),
|
|
);
|
|
expect(amMaterial.shape, expectedAmShape);
|
|
|
|
final RoundedRectangleBorder expectedPmShape = dayPeriodShape.copyWith(
|
|
side: timePickerTheme.dayPeriodBorderSide,
|
|
borderRadius: BorderRadius.only(
|
|
topRight: borderRadius.topLeft,
|
|
bottomRight: borderRadius.topRight,
|
|
),
|
|
);
|
|
expect(pmMaterial.shape, expectedPmShape);
|
|
|
|
expect(
|
|
find.descendant(
|
|
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl'),
|
|
matching: find.byType(Container),
|
|
),
|
|
findsNothing,
|
|
);
|
|
|
|
final IconButton entryModeIconButton = _entryModeIconButton(tester);
|
|
expect(entryModeIconButton.color, null);
|
|
|
|
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel');
|
|
expect(
|
|
cancelButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(timePickerTheme.cancelButtonStyle.toString()),
|
|
);
|
|
|
|
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
|
|
expect(
|
|
confirmButtonStyle.toString(),
|
|
equalsIgnoringHashCodes(timePickerTheme.confirmButtonStyle.toString()),
|
|
);
|
|
});
|
|
|
|
testWidgets(
|
|
'Time picker uses values from TimePickerThemeData when TimePickerThemeData.inputDecorationTheme is provided - input mode',
|
|
(WidgetTester tester) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme(includeInputDecoration: true);
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final InputDecoration hourDecoration = _textField(tester, '7').decoration!;
|
|
expect(hourDecoration.filled, timePickerTheme.inputDecorationTheme!.filled);
|
|
expect(hourDecoration.fillColor, timePickerTheme.inputDecorationTheme!.fillColor);
|
|
expect(hourDecoration.enabledBorder, timePickerTheme.inputDecorationTheme!.enabledBorder);
|
|
expect(hourDecoration.errorBorder, timePickerTheme.inputDecorationTheme!.errorBorder);
|
|
expect(hourDecoration.focusedBorder, timePickerTheme.inputDecorationTheme!.focusedBorder);
|
|
expect(
|
|
hourDecoration.focusedErrorBorder,
|
|
timePickerTheme.inputDecorationTheme!.focusedErrorBorder,
|
|
);
|
|
expect(hourDecoration.hintStyle, timePickerTheme.inputDecorationTheme!.hintStyle);
|
|
},
|
|
);
|
|
|
|
testWidgets(
|
|
'Time picker uses values from TimePickerThemeData when TimePickerThemeData.inputDecorationTheme is not provided - input mode',
|
|
(WidgetTester tester) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme();
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final InputDecoration hourDecoration = _textField(tester, '7').decoration!;
|
|
expect(hourDecoration.fillColor?.value, timePickerTheme.hourMinuteColor?.value);
|
|
},
|
|
);
|
|
|
|
testWidgets('Time picker dayPeriodColor does the right thing with non-WidgetStateColor', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme().copyWith(
|
|
dayPeriodColor: Colors.red,
|
|
);
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final Material amMaterial = _textMaterial(tester, 'AM');
|
|
expect(amMaterial.color, Colors.red);
|
|
|
|
final Material pmMaterial = _textMaterial(tester, 'PM');
|
|
expect(pmMaterial.color, Colors.transparent);
|
|
});
|
|
|
|
testWidgets('Time picker dayPeriodColor does the right thing with WidgetStateColor', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final testColor = WidgetStateColor.resolveWith((Set<WidgetState> states) {
|
|
if (states.contains(WidgetState.selected)) {
|
|
return Colors.green;
|
|
}
|
|
return Colors.blue;
|
|
});
|
|
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme().copyWith(
|
|
dayPeriodColor: testColor,
|
|
);
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final Material amMaterial = _textMaterial(tester, 'AM');
|
|
expect(amMaterial.color, Colors.green);
|
|
|
|
final Material pmMaterial = _textMaterial(tester, 'PM');
|
|
expect(pmMaterial.color, Colors.blue);
|
|
});
|
|
|
|
testWidgets('Time selector separator color uses the timeSelectorSeparatorColor value', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme().copyWith(
|
|
timeSelectorSeparatorColor: const MaterialStatePropertyAll<Color>(Color(0xff00ff00)),
|
|
);
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final RenderParagraph paragraph = tester.renderObject(find.text(':'));
|
|
expect(paragraph.text.style!.color, const Color(0xff00ff00));
|
|
});
|
|
|
|
testWidgets('Time selector separator text style uses the timeSelectorSeparatorTextStyle value', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme().copyWith(
|
|
timeSelectorSeparatorTextStyle: const MaterialStatePropertyAll<TextStyle>(
|
|
TextStyle(fontSize: 35.0, fontStyle: FontStyle.italic),
|
|
),
|
|
);
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
final RenderParagraph paragraph = tester.renderObject(find.text(':'));
|
|
expect(paragraph.text.style!.fontSize, 35.0);
|
|
expect(paragraph.text.style!.fontStyle, FontStyle.italic);
|
|
});
|
|
|
|
// This is a regression test for https://github.com/flutter/flutter/issues/153549.
|
|
testWidgets('Time picker hour minute does not resize on error', (WidgetTester tester) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme(includeInputDecoration: true);
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
expect(tester.getSize(findBorderPainter().first), const Size(96.0, 72.0));
|
|
|
|
// Enter invalid hour.
|
|
await tester.enterText(find.byType(TextField).first, 'AB');
|
|
await tester.tap(find.text('OK'));
|
|
|
|
expect(tester.getSize(findBorderPainter().first), const Size(96.0, 72.0));
|
|
});
|
|
|
|
// This is a regression test for https://github.com/flutter/flutter/issues/153549.
|
|
testWidgets('Material2 - Time picker hour minute does not resize on error', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final TimePickerThemeData timePickerTheme = _timePickerTheme(includeInputDecoration: true);
|
|
final theme = ThemeData(timePickerTheme: timePickerTheme, useMaterial3: false);
|
|
await tester.pumpWidget(
|
|
_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input),
|
|
);
|
|
await tester.tap(find.text('X'));
|
|
await tester.pumpAndSettle(const Duration(seconds: 1));
|
|
|
|
expect(tester.getSize(findBorderPainter().first), const Size(96.0, 70.0));
|
|
|
|
// Enter invalid hour.
|
|
await tester.enterText(find.byType(TextField).first, 'AB');
|
|
await tester.tap(find.text('OK'));
|
|
|
|
expect(tester.getSize(findBorderPainter().first), const Size(96.0, 70.0));
|
|
});
|
|
}
|
|
|
|
final Color _selectedColor = Colors.green[100]!;
|
|
final Color _unselectedColor = Colors.green[200]!;
|
|
|
|
TimePickerThemeData _timePickerTheme({bool includeInputDecoration = false}) {
|
|
Color getColor(Set<WidgetState> states) {
|
|
return states.contains(WidgetState.selected) ? _selectedColor : _unselectedColor;
|
|
}
|
|
|
|
final materialStateColor = WidgetStateColor.resolveWith(getColor);
|
|
return TimePickerThemeData(
|
|
backgroundColor: Colors.orange,
|
|
cancelButtonStyle: TextButton.styleFrom(foregroundColor: Colors.red),
|
|
confirmButtonStyle: TextButton.styleFrom(foregroundColor: Colors.green),
|
|
hourMinuteTextColor: materialStateColor,
|
|
hourMinuteColor: materialStateColor,
|
|
dayPeriodTextColor: materialStateColor,
|
|
dayPeriodColor: materialStateColor,
|
|
dialHandColor: Colors.brown,
|
|
dialBackgroundColor: Colors.pinkAccent,
|
|
dialTextColor: materialStateColor,
|
|
entryModeIconColor: Colors.red,
|
|
hourMinuteTextStyle: const TextStyle(fontSize: 8.0),
|
|
dayPeriodTextStyle: const TextStyle(fontSize: 8.0),
|
|
helpTextStyle: const TextStyle(fontSize: 8.0),
|
|
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))),
|
|
hourMinuteShape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.all(Radius.circular(16.0)),
|
|
),
|
|
dayPeriodShape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.all(Radius.circular(16.0)),
|
|
),
|
|
dayPeriodBorderSide: const BorderSide(color: Colors.blueAccent),
|
|
inputDecorationTheme: includeInputDecoration
|
|
? const InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: Colors.purple,
|
|
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.blue)),
|
|
errorBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.green)),
|
|
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.yellow)),
|
|
focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.red)),
|
|
hintStyle: TextStyle(fontSize: 8),
|
|
)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
class _TimePickerLauncher extends StatelessWidget {
|
|
const _TimePickerLauncher({this.themeData, this.entryMode = TimePickerEntryMode.dial});
|
|
|
|
final ThemeData? themeData;
|
|
final TimePickerEntryMode entryMode;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
theme: themeData,
|
|
home: Material(
|
|
child: Center(
|
|
child: Builder(
|
|
builder: (BuildContext context) {
|
|
return ElevatedButton(
|
|
child: const Text('X'),
|
|
onPressed: () async {
|
|
await showTimePicker(
|
|
context: context,
|
|
initialEntryMode: entryMode,
|
|
initialTime: const TimeOfDay(hour: 7, minute: 15),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
Material _dialogMaterial(WidgetTester tester) {
|
|
return tester.widget<Material>(
|
|
find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first,
|
|
);
|
|
}
|
|
|
|
Material _textMaterial(WidgetTester tester, String text) {
|
|
return tester.widget<Material>(
|
|
find.ancestor(of: find.text(text), matching: find.byType(Material)).first,
|
|
);
|
|
}
|
|
|
|
TextField _textField(WidgetTester tester, String text) {
|
|
return tester.widget<TextField>(
|
|
find.ancestor(of: find.text(text), matching: find.byType(TextField)).first,
|
|
);
|
|
}
|
|
|
|
IconButton _entryModeIconButton(WidgetTester tester) {
|
|
return tester.widget<IconButton>(
|
|
find.descendant(of: find.byType(Dialog), matching: find.byType(IconButton)).first,
|
|
);
|
|
}
|
|
|
|
RenderParagraph _textRenderParagraph(WidgetTester tester, String text) {
|
|
return tester.element<StatelessElement>(find.text(text).first).renderObject! as RenderParagraph;
|
|
}
|
|
|
|
final Finder findDialPaint = find.descendant(
|
|
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_Dial'),
|
|
matching: find.byWidgetPredicate((Widget w) => w is CustomPaint),
|
|
);
|
|
|
|
ButtonStyle _actionButtonStyle(WidgetTester tester, String text) {
|
|
return tester.widget<TextButton>(find.widgetWithText(TextButton, text)).style!;
|
|
}
|
|
|
|
Finder findBorderPainter() {
|
|
return find.descendant(
|
|
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_BorderContainer'),
|
|
matching: find.byWidgetPredicate((Widget w) => w is CustomPaint),
|
|
);
|
|
}
|