mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Feat: Add yearShape property to DatePickerThemeData (#163909)
Feat: Add yearShape property to DatePickerThemeData fixes: #163340 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. --------- Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com>
This commit is contained in:
parent
2f72db6c7f
commit
c6c3876ba9
@ -50,6 +50,7 @@ class _${blockName}DefaultsM3 extends DatePickerThemeData {
|
||||
// TODO(tahatesser): Update this to use token when gen_defaults
|
||||
// supports `CircleBorder` for fully rounded corners.
|
||||
dayShape: const WidgetStatePropertyAll<OutlinedBorder>(CircleBorder()),
|
||||
yearShape: const WidgetStatePropertyAll<OutlinedBorder>(StadiumBorder()),
|
||||
rangePickerElevation: ${elevation("md.comp.date-picker.modal.range-selection.container")},
|
||||
rangePickerShape: ${shape("md.comp.date-picker.modal.range-selection.container")},
|
||||
);
|
||||
|
@ -1409,17 +1409,19 @@ class _YearPickerState extends State<YearPicker> {
|
||||
effectiveValue((DatePickerThemeData? theme) => theme?.yearOverlayColor?.resolve(states)),
|
||||
);
|
||||
|
||||
BoxBorder? border;
|
||||
final OutlinedBorder yearShape =
|
||||
resolve<OutlinedBorder?>((DatePickerThemeData? theme) => theme?.yearShape, states)!;
|
||||
|
||||
BorderSide? borderSide;
|
||||
if (isCurrentYear) {
|
||||
final BorderSide? todayBorder = datePickerTheme.todayBorder ?? defaults.todayBorder;
|
||||
if (todayBorder != null) {
|
||||
border = Border.fromBorderSide(todayBorder.copyWith(color: textColor));
|
||||
borderSide = datePickerTheme.todayBorder ?? defaults.todayBorder;
|
||||
if (borderSide != null) {
|
||||
borderSide = borderSide.copyWith(color: textColor);
|
||||
}
|
||||
}
|
||||
final BoxDecoration decoration = BoxDecoration(
|
||||
border: border,
|
||||
final ShapeDecoration decoration = ShapeDecoration(
|
||||
color: background,
|
||||
borderRadius: BorderRadius.circular(decorationHeight / 2),
|
||||
shape: yearShape.copyWith(side: borderSide),
|
||||
);
|
||||
|
||||
final TextStyle? itemStyle = (datePickerTheme.yearStyle ?? defaults.yearStyle)?.apply(
|
||||
|
@ -67,6 +67,7 @@ class DatePickerThemeData with Diagnosticable {
|
||||
this.yearForegroundColor,
|
||||
this.yearBackgroundColor,
|
||||
this.yearOverlayColor,
|
||||
this.yearShape,
|
||||
this.rangePickerBackgroundColor,
|
||||
this.rangePickerElevation,
|
||||
this.rangePickerShadowColor,
|
||||
@ -251,6 +252,19 @@ class DatePickerThemeData with Diagnosticable {
|
||||
/// or pressed.
|
||||
final WidgetStateProperty<Color?>? yearOverlayColor;
|
||||
|
||||
/// Overrides the default shape used to paint the shape decoration of the
|
||||
/// year labels in the list of the year picker.
|
||||
///
|
||||
/// If the selected year is the current year, the provided shape with the
|
||||
/// value of [todayBackgroundColor] is used to paint the shape decoration of
|
||||
/// the year label and the value of [todayBorder] and [todayForegroundColor] is
|
||||
/// used to paint the border.
|
||||
///
|
||||
/// If the selected year is not the current year, the provided shape with the
|
||||
/// value of [yearBackgroundColor] is used to paint the shape decoration of
|
||||
/// the year label.
|
||||
final WidgetStateProperty<OutlinedBorder?>? yearShape;
|
||||
|
||||
/// Overrides the default [Scaffold.backgroundColor] for
|
||||
/// [DateRangePickerDialog].
|
||||
final Color? rangePickerBackgroundColor;
|
||||
@ -384,6 +398,7 @@ class DatePickerThemeData with Diagnosticable {
|
||||
WidgetStateProperty<Color?>? yearForegroundColor,
|
||||
WidgetStateProperty<Color?>? yearBackgroundColor,
|
||||
WidgetStateProperty<Color?>? yearOverlayColor,
|
||||
WidgetStateProperty<OutlinedBorder?>? yearShape,
|
||||
Color? rangePickerBackgroundColor,
|
||||
double? rangePickerElevation,
|
||||
Color? rangePickerShadowColor,
|
||||
@ -424,6 +439,7 @@ class DatePickerThemeData with Diagnosticable {
|
||||
yearForegroundColor: yearForegroundColor ?? this.yearForegroundColor,
|
||||
yearBackgroundColor: yearBackgroundColor ?? this.yearBackgroundColor,
|
||||
yearOverlayColor: yearOverlayColor ?? this.yearOverlayColor,
|
||||
yearShape: yearShape ?? this.yearShape,
|
||||
rangePickerBackgroundColor: rangePickerBackgroundColor ?? this.rangePickerBackgroundColor,
|
||||
rangePickerElevation: rangePickerElevation ?? this.rangePickerElevation,
|
||||
rangePickerShadowColor: rangePickerShadowColor ?? this.rangePickerShadowColor,
|
||||
@ -520,6 +536,12 @@ class DatePickerThemeData with Diagnosticable {
|
||||
t,
|
||||
Color.lerp,
|
||||
),
|
||||
yearShape: WidgetStateProperty.lerp<OutlinedBorder?>(
|
||||
a?.yearShape,
|
||||
b?.yearShape,
|
||||
t,
|
||||
OutlinedBorder.lerp,
|
||||
),
|
||||
rangePickerBackgroundColor: Color.lerp(
|
||||
a?.rangePickerBackgroundColor,
|
||||
b?.rangePickerBackgroundColor,
|
||||
@ -606,6 +628,7 @@ class DatePickerThemeData with Diagnosticable {
|
||||
yearForegroundColor,
|
||||
yearBackgroundColor,
|
||||
yearOverlayColor,
|
||||
yearShape,
|
||||
rangePickerBackgroundColor,
|
||||
rangePickerElevation,
|
||||
rangePickerShadowColor,
|
||||
@ -652,6 +675,7 @@ class DatePickerThemeData with Diagnosticable {
|
||||
other.yearForegroundColor == yearForegroundColor &&
|
||||
other.yearBackgroundColor == yearBackgroundColor &&
|
||||
other.yearOverlayColor == yearOverlayColor &&
|
||||
other.yearShape == yearShape &&
|
||||
other.rangePickerBackgroundColor == rangePickerBackgroundColor &&
|
||||
other.rangePickerElevation == rangePickerElevation &&
|
||||
other.rangePickerShadowColor == rangePickerShadowColor &&
|
||||
@ -765,6 +789,13 @@ class DatePickerThemeData with Diagnosticable {
|
||||
defaultValue: null,
|
||||
),
|
||||
);
|
||||
properties.add(
|
||||
DiagnosticsProperty<WidgetStateProperty<OutlinedBorder?>>(
|
||||
'yearShape',
|
||||
yearShape,
|
||||
defaultValue: null,
|
||||
),
|
||||
);
|
||||
properties.add(
|
||||
ColorProperty('rangePickerBackgroundColor', rangePickerBackgroundColor, defaultValue: null),
|
||||
);
|
||||
@ -943,6 +974,7 @@ class _DatePickerDefaultsM2 extends DatePickerThemeData {
|
||||
elevation: 24.0,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))),
|
||||
dayShape: const WidgetStatePropertyAll<OutlinedBorder>(CircleBorder()),
|
||||
yearShape: const WidgetStatePropertyAll<OutlinedBorder>(StadiumBorder()),
|
||||
rangePickerElevation: 0.0,
|
||||
rangePickerShape: const RoundedRectangleBorder(),
|
||||
);
|
||||
@ -1117,6 +1149,7 @@ class _DatePickerDefaultsM3 extends DatePickerThemeData {
|
||||
// TODO(tahatesser): Update this to use token when gen_defaults
|
||||
// supports `CircleBorder` for fully rounded corners.
|
||||
dayShape: const WidgetStatePropertyAll<OutlinedBorder>(CircleBorder()),
|
||||
yearShape: const WidgetStatePropertyAll<OutlinedBorder>(StadiumBorder()),
|
||||
rangePickerElevation: 0.0,
|
||||
rangePickerShape: const RoundedRectangleBorder(),
|
||||
);
|
||||
|
@ -32,6 +32,7 @@ void main() {
|
||||
yearForegroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffffa)),
|
||||
yearBackgroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffffb)),
|
||||
yearOverlayColor: MaterialStatePropertyAll<Color>(Color(0xfffffffc)),
|
||||
yearShape: MaterialStatePropertyAll<OutlinedBorder>(RoundedRectangleBorder()),
|
||||
rangePickerBackgroundColor: Color(0xfffffffd),
|
||||
rangePickerElevation: 7,
|
||||
rangePickerShadowColor: Color(0xfffffffe),
|
||||
@ -69,11 +70,11 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
BoxDecoration? findTextDecoration(WidgetTester tester, String date) {
|
||||
ShapeDecoration? findTextDecoration(WidgetTester tester, String date) {
|
||||
final Container container = tester.widget<Container>(
|
||||
find.ancestor(of: find.text(date), matching: find.byType(Container)).first,
|
||||
);
|
||||
return container.decoration as BoxDecoration?;
|
||||
return container.decoration as ShapeDecoration?;
|
||||
}
|
||||
|
||||
ShapeDecoration? findDayDecoration(WidgetTester tester, String day) {
|
||||
@ -449,6 +450,7 @@ void main() {
|
||||
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
|
||||
);
|
||||
expect(m2.locale, null);
|
||||
expect(m2.yearShape?.resolve(<MaterialState>{}), const StadiumBorder());
|
||||
});
|
||||
|
||||
testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async {
|
||||
@ -500,6 +502,7 @@ void main() {
|
||||
'yearForegroundColor: WidgetStatePropertyAll(${const Color(0xfffffffa)})',
|
||||
'yearBackgroundColor: WidgetStatePropertyAll(${const Color(0xfffffffb)})',
|
||||
'yearOverlayColor: WidgetStatePropertyAll(${const Color(0xfffffffc)})',
|
||||
'yearShape: WidgetStatePropertyAll(RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero))',
|
||||
'rangePickerBackgroundColor: ${const Color(0xfffffffd)}',
|
||||
'rangePickerElevation: 7.0',
|
||||
'rangePickerShadowColor: ${const Color(0xfffffffe)}',
|
||||
@ -607,30 +610,28 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Text year2022 = tester.widget<Text>(find.text('2022'));
|
||||
final BoxDecoration year2022Decoration = findTextDecoration(tester, '2022')!;
|
||||
final ShapeDecoration year2022Decoration = findTextDecoration(tester, '2022')!;
|
||||
expect(year2022.style?.fontSize, datePickerTheme.yearStyle?.fontSize);
|
||||
expect(year2022.style?.color, datePickerTheme.yearForegroundColor?.resolve(<MaterialState>{}));
|
||||
expect(
|
||||
year2022Decoration.color,
|
||||
datePickerTheme.yearBackgroundColor?.resolve(<MaterialState>{}),
|
||||
);
|
||||
expect(year2022Decoration.shape, datePickerTheme.yearShape?.resolve(<MaterialState>{}));
|
||||
|
||||
final Text year2023 = tester.widget<Text>(find.text('2023')); // DatePickerDialog.currentDate
|
||||
final BoxDecoration year2023Decoration = findTextDecoration(tester, '2023')!;
|
||||
final ShapeDecoration year2023Decoration = findTextDecoration(tester, '2023')!;
|
||||
expect(year2023.style?.fontSize, datePickerTheme.yearStyle?.fontSize);
|
||||
expect(year2023.style?.color, datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}));
|
||||
expect(
|
||||
year2023Decoration.color,
|
||||
datePickerTheme.todayBackgroundColor?.resolve(<MaterialState>{}),
|
||||
);
|
||||
expect(year2023Decoration.border?.top.width, datePickerTheme.todayBorder?.width);
|
||||
expect(year2023Decoration.border?.bottom.width, datePickerTheme.todayBorder?.width);
|
||||
final RoundedRectangleBorder roundedRectangleBorder =
|
||||
year2023Decoration.shape as RoundedRectangleBorder;
|
||||
expect(roundedRectangleBorder.side.width, datePickerTheme.todayBorder?.width);
|
||||
expect(
|
||||
year2023Decoration.border?.top.color,
|
||||
datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}),
|
||||
);
|
||||
expect(
|
||||
year2023Decoration.border?.bottom.color,
|
||||
roundedRectangleBorder.side.color,
|
||||
datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}),
|
||||
);
|
||||
|
||||
@ -1206,4 +1207,109 @@ void main() {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('YearPicker maintains default year shape at textScaleFactor 1, 1.5, 2', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
double textScaleFactor = 1.0;
|
||||
Widget buildFrame() {
|
||||
return MaterialApp(
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return MediaQuery.withClampedTextScaling(
|
||||
minScaleFactor: textScaleFactor,
|
||||
maxScaleFactor: textScaleFactor,
|
||||
child: Scaffold(
|
||||
body: YearPicker(
|
||||
currentDate: DateTime(2025),
|
||||
firstDate: DateTime(2021),
|
||||
lastDate: DateTime(2030),
|
||||
selectedDate: DateTime(2025),
|
||||
onChanged: (DateTime value) {},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildFrame());
|
||||
|
||||
// Find container whose child is text 2025.
|
||||
final Finder yearContainer =
|
||||
find.ancestor(of: find.text('2025'), matching: find.byType(Container)).first;
|
||||
|
||||
expect(
|
||||
tester.renderObject(yearContainer),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromLTRBR(0.5, 0.5, 71.5, 35.5, const Radius.circular(17.5)),
|
||||
color: const Color(0xFF6750A4),
|
||||
),
|
||||
);
|
||||
|
||||
textScaleFactor = 1.5;
|
||||
await tester.pumpWidget(buildFrame());
|
||||
|
||||
expect(
|
||||
tester.renderObject(yearContainer),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromLTRBR(0.5, 0.5, 107.5, 51.5, const Radius.circular(25.5)),
|
||||
color: const Color(0xFF6750A4),
|
||||
),
|
||||
);
|
||||
|
||||
textScaleFactor = 2;
|
||||
await tester.pumpWidget(buildFrame());
|
||||
|
||||
expect(
|
||||
tester.renderObject(yearContainer),
|
||||
paints..rrect(
|
||||
rrect: RRect.fromLTRBR(0.5, 0.5, 143.5, 51.5, const Radius.circular(25.5)),
|
||||
color: const Color(0xFF6750A4),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('YearPicker applies shape from DatePickerThemeData.yearShape correctly', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
const OutlinedBorder yearShpae = CircleBorder();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
datePickerTheme: datePickerTheme.copyWith(
|
||||
yearShape: MaterialStateProperty.all<OutlinedBorder>(yearShpae),
|
||||
),
|
||||
),
|
||||
home: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Material(
|
||||
child: Center(
|
||||
child: YearPicker(
|
||||
currentDate: DateTime(2025),
|
||||
firstDate: DateTime(2021),
|
||||
lastDate: DateTime(2030),
|
||||
selectedDate: DateTime(2025),
|
||||
onChanged: (DateTime value) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final ShapeDecoration year2022Decoration = findTextDecoration(tester, '2022')!;
|
||||
final OutlinedBorder year2022roundedRectangleBorder = year2022Decoration.shape as CircleBorder;
|
||||
expect(year2022roundedRectangleBorder.side.width, 0.0);
|
||||
expect(year2022roundedRectangleBorder.side.color, yearShpae.side.color);
|
||||
|
||||
final ShapeDecoration year2025Decoration = findTextDecoration(tester, '2025')!;
|
||||
final OutlinedBorder year2022RoundedRectangleBorder = year2025Decoration.shape as CircleBorder;
|
||||
expect(year2022RoundedRectangleBorder.side.width, datePickerTheme.todayBorder?.width);
|
||||
expect(
|
||||
year2022RoundedRectangleBorder.side.color,
|
||||
datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user