Skip to content

Commit 9c86e99

Browse files
Merge branch 'master' into master
2 parents d2ad2c7 + e051a8f commit 9c86e99

File tree

12 files changed

+1294
-37
lines changed

12 files changed

+1294
-37
lines changed

DEPS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@ deps = {
813813
'packages': [
814814
{
815815
'package': 'fuchsia/sdk/core/linux-amd64',
816-
'version': '91RIHvX0YC3wzD7qjbMedDs-zeXWJQMLcjwj6PKjR00C'
816+
'version': '7bWzHwIPBTyU6R9nOj84llziVBSXbmUIK5fTqQhWiDIC'
817817
}
818818
],
819819
'condition': 'download_fuchsia_deps and not download_fuchsia_sdk',

engine/src/flutter/ci/licenses_golden/excluded_files

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4037,6 +4037,7 @@
40374037
../../../fuchsia/sdk/linux/pkg/memory_barriers/meta.json
40384038
../../../fuchsia/sdk/linux/pkg/mmio-ptr/meta.json
40394039
../../../fuchsia/sdk/linux/pkg/mmio/meta.json
4040+
../../../fuchsia/sdk/linux/pkg/mock_mmio_cpp/meta.json
40404041
../../../fuchsia/sdk/linux/pkg/scenic_cpp/meta.json
40414042
../../../fuchsia/sdk/linux/pkg/scenic_cpp_testing/include/lib/ui/scenic/cpp/testing
40424043
../../../fuchsia/sdk/linux/pkg/scenic_cpp_testing/meta.json

engine/src/flutter/ci/licenses_golden/licenses_fuchsia

Lines changed: 202 additions & 1 deletion
Large diffs are not rendered by default.

packages/flutter/lib/src/material/time_picker.dart

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,7 +2324,8 @@ class _TimePickerDialogState extends State<TimePickerDialog> with RestorationMix
23242324
static const Size _kTimePickerPortraitSize = Size(310, 468);
23252325
static const Size _kTimePickerLandscapeSize = Size(524, 342);
23262326
static const Size _kTimePickerLandscapeSizeM2 = Size(508, 300);
2327-
static const Size _kTimePickerInputSize = Size(312, 216);
2327+
static const Size _kTimePickerInputSize = Size(312, 252);
2328+
static const double _kTimePickerInputMinimumHeight = 216;
23282329

23292330
// Absolute minimum dialog sizes, which is the point at which it begins
23302331
// scrolling to fit everything in.
@@ -2606,33 +2607,45 @@ class _TimePickerDialogState extends State<TimePickerDialog> with RestorationMix
26062607
restorationId: 'time_picker_scroll_view_vertical',
26072608
child: AnimatedContainer(
26082609
width: allowedSize.width,
2609-
height: allowedSize.height,
26102610
duration: _kDialogSizeAnimationDuration,
26112611
curve: Curves.easeIn,
2612+
constraints: BoxConstraints(
2613+
minHeight: _kTimePickerInputMinimumHeight,
2614+
maxHeight: allowedSize.height,
2615+
),
26122616
child: Column(
2617+
mainAxisSize: MainAxisSize.min,
2618+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
26132619
crossAxisAlignment: CrossAxisAlignment.start,
26142620
children: <Widget>[
2615-
Expanded(
2616-
child: Form(
2617-
key: _formKey,
2618-
autovalidateMode: _autovalidateMode.value,
2619-
child: _TimePicker(
2620-
time: widget.initialTime,
2621-
onTimeChanged: _handleTimeChanged,
2622-
helpText: widget.helpText,
2623-
cancelText: widget.cancelText,
2624-
confirmText: widget.confirmText,
2625-
errorInvalidText: widget.errorInvalidText,
2626-
hourLabelText: widget.hourLabelText,
2627-
minuteLabelText: widget.minuteLabelText,
2628-
restorationId: 'time_picker',
2629-
entryMode: _entryMode.value,
2630-
orientation: widget.orientation,
2631-
onEntryModeChanged: _handleEntryModeChanged,
2632-
switchToInputEntryModeIcon: widget.switchToInputEntryModeIcon,
2633-
switchToTimerEntryModeIcon: widget.switchToTimerEntryModeIcon,
2634-
),
2635-
),
2621+
Builder(
2622+
builder: (BuildContext context) {
2623+
final Widget child = Form(
2624+
key: _formKey,
2625+
autovalidateMode: _autovalidateMode.value,
2626+
child: _TimePicker(
2627+
time: widget.initialTime,
2628+
onTimeChanged: _handleTimeChanged,
2629+
helpText: widget.helpText,
2630+
cancelText: widget.cancelText,
2631+
confirmText: widget.confirmText,
2632+
errorInvalidText: widget.errorInvalidText,
2633+
hourLabelText: widget.hourLabelText,
2634+
minuteLabelText: widget.minuteLabelText,
2635+
restorationId: 'time_picker',
2636+
entryMode: _entryMode.value,
2637+
orientation: widget.orientation,
2638+
onEntryModeChanged: _handleEntryModeChanged,
2639+
switchToInputEntryModeIcon: widget.switchToInputEntryModeIcon,
2640+
switchToTimerEntryModeIcon: widget.switchToTimerEntryModeIcon,
2641+
),
2642+
);
2643+
if (_entryMode.value != TimePickerEntryMode.input &&
2644+
_entryMode.value != TimePickerEntryMode.inputOnly) {
2645+
return Flexible(child: child);
2646+
}
2647+
return child;
2648+
},
26362649
),
26372650
actions,
26382651
],

packages/flutter/lib/src/painting/colors.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,7 @@ class HSLColor {
266266
final double lightness = (max + min) / 2.0;
267267
// Saturation can exceed 1.0 with rounding errors, so clamp it.
268268
final double saturation =
269-
lightness == 1.0
270-
? 0.0
271-
: clampDouble(delta / (1.0 - (2.0 * lightness - 1.0).abs()), 0.0, 1.0);
269+
min == max ? 0.0 : clampDouble(delta / (1.0 - (2.0 * lightness - 1.0).abs()), 0.0, 1.0);
272270
return HSLColor.fromAHSL(alpha, hue, saturation, lightness);
273271
}
274272

packages/flutter/test/material/time_picker_test.dart

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void main() {
7272

7373
testWidgets('Material2 - Dialog size - input mode', (WidgetTester tester) async {
7474
const TimePickerEntryMode entryMode = TimePickerEntryMode.input;
75-
const Size timePickerInputSize = Size(312, 216);
75+
const Size timePickerInputSize = Size(312, 252);
7676
const Size dayPeriodPortraitSize = Size(52, 80);
7777
const EdgeInsets padding = EdgeInsets.fromLTRB(8, 18, 8, 8);
7878
final double height = timePickerInputSize.height + padding.vertical;
@@ -81,7 +81,9 @@ void main() {
8181
await mediaQueryBoilerplate(tester, entryMode: entryMode, materialType: MaterialType.material2);
8282

8383
width = timePickerInputSize.width + padding.horizontal;
84-
expect(tester.getSize(find.byWidget(getMaterialFromDialog(tester))), Size(width, height));
84+
Size size = tester.getSize(find.byWidget(getMaterialFromDialog(tester)));
85+
expect(size.width, width);
86+
expect(size.height, lessThan(height));
8587

8688
await tester.tap(find.text(okString)); // dismiss the dialog
8789
await tester.pumpAndSettle();
@@ -93,7 +95,9 @@ void main() {
9395
materialType: MaterialType.material2,
9496
);
9597
width = timePickerInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal + 16;
96-
expect(tester.getSize(find.byWidget(getMaterialFromDialog(tester))), Size(width, height));
98+
size = tester.getSize(find.byWidget(getMaterialFromDialog(tester)));
99+
expect(size.width, width);
100+
expect(size.height, lessThan(height));
97101
});
98102

99103
testWidgets('Material2 - respects MediaQueryData.alwaysUse24HourFormat == true', (
@@ -163,7 +167,7 @@ void main() {
163167
final ThemeData theme = ThemeData();
164168
const TimePickerEntryMode entryMode = TimePickerEntryMode.input;
165169
const double textScaleFactor = 1.0;
166-
const Size timePickerMinInputSize = Size(312, 216);
170+
const Size timePickerMinInputSize = Size(312, 252);
167171
const Size dayPeriodPortraitSize = Size(52, 80);
168172
const EdgeInsets padding = EdgeInsets.all(24.0);
169173
final double height = timePickerMinInputSize.height * textScaleFactor + padding.vertical;
@@ -172,7 +176,9 @@ void main() {
172176
await mediaQueryBoilerplate(tester, entryMode: entryMode, materialType: MaterialType.material3);
173177

174178
width = timePickerMinInputSize.width - (theme.useMaterial3 ? 32 : 0) + padding.horizontal;
175-
expect(tester.getSize(find.byWidget(getMaterialFromDialog(tester))), Size(width, height));
179+
Size size = tester.getSize(find.byWidget(getMaterialFromDialog(tester)));
180+
expect(size.width, width);
181+
expect(size.height, lessThan(height));
176182

177183
await tester.tap(find.text(okString)); // dismiss the dialog
178184
await tester.pumpAndSettle();
@@ -185,7 +191,9 @@ void main() {
185191
);
186192

187193
width = timePickerMinInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal;
188-
expect(tester.getSize(find.byWidget(getMaterialFromDialog(tester))), Size(width, height));
194+
size = tester.getSize(find.byWidget(getMaterialFromDialog(tester)));
195+
expect(size.width, width);
196+
expect(size.height, lessThan(height));
189197
});
190198

191199
testWidgets('Material3 - respects MediaQueryData.alwaysUse24HourFormat == true', (
@@ -594,6 +602,24 @@ void main() {
594602
expect(find.text('Cancel'), findsOneWidget);
595603
});
596604

605+
testWidgets(
606+
'Material3 - large actions label should not overflow in input mode',
607+
(WidgetTester tester) async {
608+
await startPicker(
609+
tester,
610+
(TimeOfDay? time) {},
611+
entryMode: TimePickerEntryMode.input,
612+
materialType: MaterialType.material3,
613+
cancelText: 'Very very very long cancel text',
614+
confirmText: 'Very very very long confirm text',
615+
);
616+
617+
// Verify that no overflow errors occur.
618+
expect(tester.takeException(), isNull);
619+
},
620+
variant: TargetPlatformVariant.mobile(),
621+
);
622+
597623
testWidgets('respects MediaQueryData.alwaysUse24HourFormat == false', (
598624
WidgetTester tester,
599625
) async {
@@ -2325,11 +2351,15 @@ class _TimePickerLauncher extends StatefulWidget {
23252351
required this.onChanged,
23262352
this.entryMode = TimePickerEntryMode.dial,
23272353
this.restorationId,
2354+
this.cancelText,
2355+
this.confirmText,
23282356
});
23292357

23302358
final ValueChanged<TimeOfDay?> onChanged;
23312359
final TimePickerEntryMode entryMode;
23322360
final String? restorationId;
2361+
final String? cancelText;
2362+
final String? confirmText;
23332363

23342364
@override
23352365
_TimePickerLauncherState createState() => _TimePickerLauncherState();
@@ -2346,7 +2376,11 @@ class _TimePickerLauncherState extends State<_TimePickerLauncher> with Restorati
23462376
onPresent: (NavigatorState navigator, Object? arguments) {
23472377
return navigator.restorablePush(
23482378
_timePickerRoute,
2349-
arguments: <String, String>{'entry_mode': widget.entryMode.name},
2379+
arguments: <String, String>{
2380+
'entry_mode': widget.entryMode.name,
2381+
if (widget.cancelText != null) 'cancel_text': widget.cancelText!,
2382+
if (widget.confirmText != null) 'confirm_text': widget.confirmText!,
2383+
},
23502384
);
23512385
},
23522386
);
@@ -2363,13 +2397,17 @@ class _TimePickerLauncherState extends State<_TimePickerLauncher> with Restorati
23632397
final TimePickerEntryMode entryMode = TimePickerEntryMode.values.firstWhere(
23642398
(TimePickerEntryMode element) => element.name == args['entry_mode'],
23652399
);
2400+
final String? cancelText = args['cancel_text'] as String?;
2401+
final String? confirmText = args['confirm_text'] as String?;
23662402
return DialogRoute<TimeOfDay>(
23672403
context: context,
23682404
builder: (BuildContext context) {
23692405
return TimePickerDialog(
23702406
restorationId: 'time_picker_dialog',
23712407
initialTime: const TimeOfDay(hour: 7, minute: 0),
23722408
initialEntryMode: entryMode,
2409+
cancelText: cancelText,
2410+
confirmText: confirmText,
23732411
);
23742412
},
23752413
);
@@ -2426,6 +2464,8 @@ Future<Offset?> startPicker(
24262464
String? restorationId,
24272465
ThemeData? theme,
24282466
MaterialType? materialType,
2467+
String? cancelText,
2468+
String? confirmText,
24292469
}) async {
24302470
await tester.pumpWidget(
24312471
MaterialApp(
@@ -2436,6 +2476,8 @@ Future<Offset?> startPicker(
24362476
onChanged: onChanged,
24372477
entryMode: entryMode,
24382478
restorationId: restorationId,
2479+
cancelText: cancelText,
2480+
confirmText: confirmText,
24392481
),
24402482
),
24412483
);

packages/flutter/test/painting/colors_test.dart

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,44 @@ void main() {
323323
expect(output, equals(expectedColors));
324324
});
325325

326+
group('HSLColor.fromColor tests', () {
327+
test('Pink', () {
328+
const Color color = Color.fromARGB(255, 255, 51, 152);
329+
final HSLColor hslColor = HSLColor.fromColor(color);
330+
expect(hslColor.alpha, 1.0);
331+
expect(hslColor.hue, within<double>(distance: .3, from: 330));
332+
expect(hslColor.saturation, 1.0);
333+
expect(hslColor.lightness, within<double>(distance: _doubleColorPrecision, from: 0.6));
334+
});
335+
336+
test('White', () {
337+
const Color color = Color(0xffffffff);
338+
final HSLColor hslColor = HSLColor.fromColor(color);
339+
expect(hslColor.alpha, 1.0);
340+
expect(hslColor.hue, 0.0);
341+
expect(hslColor.saturation, 0.0);
342+
expect(hslColor.lightness, 1.0);
343+
});
344+
345+
test('Black', () {
346+
const Color color = Color(0xff000000);
347+
final HSLColor hslColor = HSLColor.fromColor(color);
348+
expect(hslColor.alpha, 1.0);
349+
expect(hslColor.hue, 0.0);
350+
expect(hslColor.saturation, 0.0);
351+
expect(hslColor.lightness, 0.0);
352+
});
353+
354+
test('Gray', () {
355+
const Color color = Color(0xff808080);
356+
final HSLColor hslColor = HSLColor.fromColor(color);
357+
expect(hslColor.alpha, 1.0);
358+
expect(hslColor.hue, 0.0);
359+
expect(hslColor.saturation, 0.0);
360+
expect(hslColor.lightness, within<double>(distance: _doubleColorPrecision, from: 0.5));
361+
});
362+
});
363+
326364
test('HSLColor.lerp identical a,b', () {
327365
expect(HSLColor.lerp(null, null, 0), null);
328366
const HSLColor color = HSLColor.fromAHSL(1.0, 0.0, 0.5, 0.5);
@@ -414,6 +452,88 @@ void main() {
414452
expect(output, equals(expectedColors));
415453
});
416454

455+
// Tests the implementation against these colors from Wikipedia
456+
// https://en.wikipedia.org/wiki/HSL_and_HSV#Examples
457+
test('Wikipedia Examples Table test', () {
458+
// ignore: always_specify_types
459+
final colors = <(int, double, double, double, double, double, double, double, double, String)>[
460+
// RGB, r, g, b, hue, v, l,s(hsv),s(hsl)
461+
(0xFFFFFFFF, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 'white'),
462+
(0xFF808080, 0.5, 0.5, 0.5, 0.0, 0.5, 0.5, 0.0, 0.0, 'gray'),
463+
(0xFF000000, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 'black'),
464+
(0xFFFF0000, 1.0, 0.0, 0.0, 0.0, 1.0, 0.5, 1.0, 1.0, 'red'),
465+
(0xFFBFBF00, .75, .75, 0.0, 60, .75, .375, 1.0, 1.0, 'lime'),
466+
(0xFF008000, 0.0, 0.5, 0.0, 120, 0.5, .25, 1.0, 1.0, 'green'),
467+
(0xFF80FFFF, 0.5, 1.0, 1.0, 180, 1.0, 0.75, 0.5, 1, 'cyan'),
468+
(0xFF8080FF, 0.5, 0.5, 1.0, 240, 1.0, 0.75, 0.5, 1, 'light purple'),
469+
(0xFFBF40BF, 0.75, 0.25, 0.75, 300, .75, .5, 2.0 / 3, .5, 'mute magenta'),
470+
];
471+
472+
for (final (
473+
int rgb,
474+
double r,
475+
double g,
476+
double b,
477+
double hue,
478+
double v,
479+
double l,
480+
double sHSV,
481+
double sHSL,
482+
String name,
483+
)
484+
in colors) {
485+
final Color color = Color.from(alpha: 1.0, red: r, green: g, blue: b);
486+
final String debugColorConstructor = 'Color.from(alpha: 1.0, red: $r, green: $g, blue: $b)';
487+
final Color intColor = Color(rgb);
488+
expect(
489+
intColor.r,
490+
within<double>(distance: _doubleColorPrecision, from: r),
491+
reason: '$name: Color($rgb).r should be $r',
492+
);
493+
expect(
494+
intColor.g,
495+
within<double>(distance: _doubleColorPrecision, from: g),
496+
reason: '$name: Color($rgb).g should be $g',
497+
);
498+
expect(
499+
intColor.b,
500+
within<double>(distance: _doubleColorPrecision, from: b),
501+
reason: '$name: Color($rgb).b should be $b',
502+
);
503+
final HSVColor hsv = HSVColor.fromAHSV(1.0, hue, sHSV, v);
504+
final HSLColor hsl = HSLColor.fromAHSL(1.0, hue, sHSL, l);
505+
expect(
506+
color,
507+
within<Color>(distance: _doubleColorPrecision, from: intColor),
508+
reason: '$name: $debugColorConstructor should be close to Color($rgb)',
509+
);
510+
expect(
511+
hsv.toColor(),
512+
within<Color>(distance: _doubleColorPrecision, from: color),
513+
reason:
514+
'$name: HSVColor.fromAHSV(1.0, $hue, $sHSV, $v).hsv should be close to $debugColorConstructor',
515+
);
516+
expect(
517+
hsl.toColor(),
518+
within<Color>(distance: _doubleColorPrecision, from: color),
519+
reason:
520+
'$name: HSLColor.fromAHSL(1.0, $hue, $sHSL, $l).hsl should be close to $debugColorConstructor',
521+
);
522+
expect(
523+
HSVColor.fromColor(color),
524+
within<HSVColor>(distance: _doubleColorPrecision, from: hsv),
525+
reason:
526+
'$name: HSVColor.fromColor($debugColorConstructor) should be close to HSVColor.fromAHSV(1.0, $hue, $sHSV, $v)',
527+
);
528+
expect(
529+
HSLColor.fromColor(color),
530+
within<HSLColor>(distance: _doubleColorPrecision, from: hsl),
531+
reason:
532+
'$name: HSLColor.fromColor($debugColorConstructor) should be close to HSLColor.fromAHSL(1.0, $hue, $sHSL, $l)',
533+
);
534+
}
535+
});
536+
417537
test('ColorSwatch test', () {
418538
final int color = nonconst(0xFF027223);
419539
final ColorSwatch<String> greens1 = ColorSwatch<String>(color, const <String, Color>{

0 commit comments

Comments
 (0)