Skip to content

Commit 944cd11

Browse files
Implementing switch expressions [refactoring flutter/lib/src/] (#143496)
This PR is the 8�ʰ step in the journey to solve issue #136139 and make the entire Flutter repo more readable. (previous pull requests: #139048, #139882, #141591, #142279, #142634, #142793, #143293) I did a pass through all of `packages/flutter/lib/src/` and found a whole bunch of `switch` statements to improve: most of them were really simple, but many involved some thorough refactoring. This pull request is just the complicated stuff. � I'll make comments to describe the changes, and then in the future there will be another PR (and it'll be much easier to review than this one).
1 parent 383067f commit 944cd11

14 files changed

+152
-305
lines changed

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

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,36 +1013,27 @@ class CupertinoDynamicColor extends Color with Diagnosticable {
10131013
/// brightness, normal contrast, [CupertinoUserInterfaceLevelData.base]
10141014
/// elevation level).
10151015
CupertinoDynamicColor resolveFrom(BuildContext context) {
1016-
Brightness brightness = Brightness.light;
1017-
if (_isPlatformBrightnessDependent) {
1018-
brightness = CupertinoTheme.maybeBrightnessOf(context) ?? Brightness.light;
1019-
}
1020-
bool isHighContrastEnabled = false;
1021-
if (_isHighContrastDependent) {
1022-
isHighContrastEnabled = MediaQuery.maybeHighContrastOf(context) ?? false;
1023-
}
1016+
final Brightness brightness = _isPlatformBrightnessDependent
1017+
? CupertinoTheme.maybeBrightnessOf(context) ?? Brightness.light
1018+
: Brightness.light;
10241019

10251020
final CupertinoUserInterfaceLevelData level = _isInterfaceElevationDependent
10261021
? CupertinoUserInterfaceLevel.maybeOf(context) ?? CupertinoUserInterfaceLevelData.base
10271022
: CupertinoUserInterfaceLevelData.base;
10281023

1029-
final Color resolved;
1030-
switch (brightness) {
1031-
case Brightness.light:
1032-
switch (level) {
1033-
case CupertinoUserInterfaceLevelData.base:
1034-
resolved = isHighContrastEnabled ? highContrastColor : color;
1035-
case CupertinoUserInterfaceLevelData.elevated:
1036-
resolved = isHighContrastEnabled ? highContrastElevatedColor : elevatedColor;
1037-
}
1038-
case Brightness.dark:
1039-
switch (level) {
1040-
case CupertinoUserInterfaceLevelData.base:
1041-
resolved = isHighContrastEnabled ? darkHighContrastColor : darkColor;
1042-
case CupertinoUserInterfaceLevelData.elevated:
1043-
resolved = isHighContrastEnabled ? darkHighContrastElevatedColor : darkElevatedColor;
1044-
}
1045-
}
1024+
final bool highContrast = _isHighContrastDependent
1025+
&& (MediaQuery.maybeHighContrastOf(context) ?? false);
1026+
1027+
final Color resolved = switch ((brightness, level, highContrast)) {
1028+
(Brightness.light, CupertinoUserInterfaceLevelData.base, false) => color,
1029+
(Brightness.light, CupertinoUserInterfaceLevelData.base, true) => highContrastColor,
1030+
(Brightness.light, CupertinoUserInterfaceLevelData.elevated, false) => elevatedColor,
1031+
(Brightness.light, CupertinoUserInterfaceLevelData.elevated, true) => highContrastElevatedColor,
1032+
(Brightness.dark, CupertinoUserInterfaceLevelData.base, false) => darkColor,
1033+
(Brightness.dark, CupertinoUserInterfaceLevelData.base, true) => darkHighContrastColor,
1034+
(Brightness.dark, CupertinoUserInterfaceLevelData.elevated, false) => darkElevatedColor,
1035+
(Brightness.dark, CupertinoUserInterfaceLevelData.elevated, true) => darkHighContrastElevatedColor,
1036+
};
10461037

10471038
Element? debugContext;
10481039
assert(() {

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

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,10 +1925,11 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
19251925
assert(sizes.content >= boxSize.height);
19261926
switch (textDirection!) {
19271927
case TextDirection.rtl:
1928-
return Offset(x - boxSize.width, (sizes.content - boxSize.height + sizes.densityAdjustment.dy) / 2.0);
1928+
x -= boxSize.width;
19291929
case TextDirection.ltr:
1930-
return Offset(x, (sizes.content - boxSize.height + sizes.densityAdjustment.dy) / 2.0);
1930+
break;
19311931
}
1932+
return Offset(x, (sizes.content - boxSize.height + sizes.densityAdjustment.dy) / 2.0);
19321933
}
19331934

19341935
// These are the offsets to the upper left corners of the boxes (including
@@ -2036,20 +2037,11 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
20362037
if (enableAnimation.isCompleted) {
20372038
return Colors.white;
20382039
}
2039-
final ColorTween enableTween;
2040-
switch (theme.brightness) {
2041-
case Brightness.light:
2042-
enableTween = ColorTween(
2043-
begin: Colors.white.withAlpha(_kDisabledAlpha),
2044-
end: Colors.white,
2045-
);
2046-
case Brightness.dark:
2047-
enableTween = ColorTween(
2048-
begin: Colors.black.withAlpha(_kDisabledAlpha),
2049-
end: Colors.black,
2050-
);
2051-
}
2052-
return enableTween.evaluate(enableAnimation)!;
2040+
final Color color = switch (theme.brightness) {
2041+
Brightness.light => Colors.white,
2042+
Brightness.dark => Colors.black,
2043+
};
2044+
return ColorTween(begin: color.withAlpha(_kDisabledAlpha), end: color).evaluate(enableAnimation)!;
20532045
}
20542046

20552047
void _paintCheck(Canvas canvas, Offset origin, double size) {

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

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -482,26 +482,20 @@ class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMix
482482

483483
Size _dialogSize(BuildContext context) {
484484
final bool useMaterial3 = Theme.of(context).useMaterial3;
485+
final bool isCalendar = switch (_entryMode.value) {
486+
DatePickerEntryMode.calendar || DatePickerEntryMode.calendarOnly => true,
487+
DatePickerEntryMode.input || DatePickerEntryMode.inputOnly => false,
488+
};
485489
final Orientation orientation = MediaQuery.orientationOf(context);
486490

487-
switch (_entryMode.value) {
488-
case DatePickerEntryMode.calendar:
489-
case DatePickerEntryMode.calendarOnly:
490-
switch (orientation) {
491-
case Orientation.portrait:
492-
return useMaterial3 ? _calendarPortraitDialogSizeM3 : _calendarPortraitDialogSizeM2;
493-
case Orientation.landscape:
494-
return _calendarLandscapeDialogSize;
495-
}
496-
case DatePickerEntryMode.input:
497-
case DatePickerEntryMode.inputOnly:
498-
switch (orientation) {
499-
case Orientation.portrait:
500-
return useMaterial3 ? _inputPortraitDialogSizeM3 : _inputPortraitDialogSizeM2;
501-
case Orientation.landscape:
502-
return _inputLandscapeDialogSize;
503-
}
504-
}
491+
return switch ((isCalendar, orientation)) {
492+
(true, Orientation.portrait) when useMaterial3 => _calendarPortraitDialogSizeM3,
493+
(false, Orientation.portrait) when useMaterial3 => _inputPortraitDialogSizeM3,
494+
(true, Orientation.portrait) => _calendarPortraitDialogSizeM2,
495+
(false, Orientation.portrait) => _inputPortraitDialogSizeM2,
496+
(true, Orientation.landscape) => _calendarLandscapeDialogSize,
497+
(false, Orientation.landscape) => _inputLandscapeDialogSize,
498+
};
505499
}
506500

507501
static const Map<ShortcutActivator, Intent> _formShortcutMap = <ShortcutActivator, Intent>{

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

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -662,8 +662,6 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
662662
}
663663

664664
Widget _buildDrawer(BuildContext context) {
665-
final bool drawerIsStart = widget.alignment == DrawerAlignment.start;
666-
final TextDirection textDirection = Directionality.of(context);
667665
final bool isDesktop;
668666
switch (Theme.of(context).platform) {
669667
case TargetPlatform.android:
@@ -676,18 +674,13 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
676674
isDesktop = true;
677675
}
678676

679-
double? dragAreaWidth = widget.edgeDragWidth;
680-
if (widget.edgeDragWidth == null) {
681-
final EdgeInsets padding = MediaQuery.paddingOf(context);
682-
switch (textDirection) {
683-
case TextDirection.ltr:
684-
dragAreaWidth = _kEdgeDragWidth +
685-
(drawerIsStart ? padding.left : padding.right);
686-
case TextDirection.rtl:
687-
dragAreaWidth = _kEdgeDragWidth +
688-
(drawerIsStart ? padding.right : padding.left);
689-
}
690-
}
677+
final double dragAreaWidth = widget.edgeDragWidth
678+
?? _kEdgeDragWidth + switch ((widget.alignment, Directionality.of(context))) {
679+
(DrawerAlignment.start, TextDirection.ltr) => MediaQuery.paddingOf(context).left,
680+
(DrawerAlignment.start, TextDirection.rtl) => MediaQuery.paddingOf(context).right,
681+
(DrawerAlignment.end, TextDirection.rtl) => MediaQuery.paddingOf(context).left,
682+
(DrawerAlignment.end, TextDirection.ltr) => MediaQuery.paddingOf(context).right,
683+
};
691684

692685
if (_controller.status == AnimationStatus.dismissed) {
693686
if (widget.enableOpenDragGesture && !isDesktop) {

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

Lines changed: 21 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,55 +1377,27 @@ class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_
13771377
}
13781378
}
13791379

1380-
final double leadingY;
1381-
final double trailingY;
1382-
1383-
switch (titleAlignment) {
1384-
case ListTileTitleAlignment.threeLine: {
1385-
if (isThreeLine) {
1386-
leadingY = _minVerticalPadding;
1387-
trailingY = _minVerticalPadding;
1388-
} else {
1389-
leadingY = (tileHeight - leadingSize.height) / 2.0;
1390-
trailingY = (tileHeight - trailingSize.height) / 2.0;
1391-
}
1392-
break;
1393-
}
1394-
case ListTileTitleAlignment.titleHeight: {
1395-
// This attempts to implement the redlines for the vertical position of the
1396-
// leading and trailing icons on the spec page:
1397-
// https://m2.material.io/components/lists#specs
1398-
// The interpretation for these redlines is as follows:
1399-
// - For large tiles (> 72dp), both leading and trailing controls should be
1400-
// a fixed distance from top. As per guidelines this is set to 16dp.
1401-
// - For smaller tiles, trailing should always be centered. Leading can be
1402-
// centered or closer to the top. It should never be further than 16dp
1403-
// to the top.
1404-
if (tileHeight > 72.0) {
1405-
leadingY = 16.0;
1406-
trailingY = 16.0;
1407-
} else {
1408-
leadingY = math.min((tileHeight - leadingSize.height) / 2.0, 16.0);
1409-
trailingY = (tileHeight - trailingSize.height) / 2.0;
1410-
}
1411-
break;
1412-
}
1413-
case ListTileTitleAlignment.top: {
1414-
leadingY = _minVerticalPadding;
1415-
trailingY = _minVerticalPadding;
1416-
break;
1417-
}
1418-
case ListTileTitleAlignment.center: {
1419-
leadingY = (tileHeight - leadingSize.height) / 2.0;
1420-
trailingY = (tileHeight - trailingSize.height) / 2.0;
1421-
break;
1422-
}
1423-
case ListTileTitleAlignment.bottom: {
1424-
leadingY = tileHeight - leadingSize.height - _minVerticalPadding;
1425-
trailingY = tileHeight - trailingSize.height - _minVerticalPadding;
1426-
break;
1427-
}
1428-
}
1380+
final double leadingDiff = tileHeight - leadingSize.height;
1381+
final double trailingDiff = tileHeight - trailingSize.height;
1382+
1383+
final (double leadingY, double trailingY) = switch (titleAlignment) {
1384+
ListTileTitleAlignment.threeLine when isThreeLine => (_minVerticalPadding, _minVerticalPadding),
1385+
ListTileTitleAlignment.threeLine => (leadingDiff / 2.0, trailingDiff / 2.0),
1386+
// This attempts to implement the redlines for the vertical position of the
1387+
// leading and trailing icons on the spec page:
1388+
// https://m2.material.io/components/lists#specs
1389+
//
1390+
// For large tiles (> 72dp), both leading and trailing controls should be
1391+
// a fixed distance from top. As per guidelines this is set to 16dp.
1392+
ListTileTitleAlignment.titleHeight when tileHeight > 72.0 => (16.0, 16.0),
1393+
// For smaller tiles, trailing should always be centered. Leading can be
1394+
// centered or closer to the top. It should never be further than 16dp
1395+
// to the top.
1396+
ListTileTitleAlignment.titleHeight => (math.min(leadingDiff / 2.0, 16.0), trailingDiff / 2.0),
1397+
ListTileTitleAlignment.top => (_minVerticalPadding, _minVerticalPadding),
1398+
ListTileTitleAlignment.center => (leadingDiff / 2.0, trailingDiff / 2.0),
1399+
ListTileTitleAlignment.bottom => (leadingDiff - _minVerticalPadding, trailingDiff - _minVerticalPadding),
1400+
};
14291401

14301402
switch (textDirection) {
14311403
case TextDirection.rtl: {

packages/flutter/lib/src/rendering/sliver.dart

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,22 +1729,11 @@ abstract class RenderSliver extends RenderObject {
17291729
/// Mixin for [RenderSliver] subclasses that provides some utility functions.
17301730
mixin RenderSliverHelpers implements RenderSliver {
17311731
bool _getRightWayUp(SliverConstraints constraints) {
1732-
bool rightWayUp;
1733-
switch (constraints.axisDirection) {
1734-
case AxisDirection.up:
1735-
case AxisDirection.left:
1736-
rightWayUp = false;
1737-
case AxisDirection.down:
1738-
case AxisDirection.right:
1739-
rightWayUp = true;
1740-
}
1741-
switch (constraints.growthDirection) {
1742-
case GrowthDirection.forward:
1743-
break;
1744-
case GrowthDirection.reverse:
1745-
rightWayUp = !rightWayUp;
1746-
}
1747-
return rightWayUp;
1732+
final bool reversed = axisDirectionIsReversed(constraints.axisDirection);
1733+
return switch (constraints.growthDirection) {
1734+
GrowthDirection.forward => !reversed,
1735+
GrowthDirection.reverse => reversed,
1736+
};
17481737
}
17491738

17501739
/// Utility function for [hitTestChildren] for use when the children are

packages/flutter/lib/src/rendering/sliver_group.dart

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,11 @@ class RenderSliverCrossAxisGroup extends RenderSliver with ContainerRenderObject
3737

3838
@override
3939
double childCrossAxisPosition(RenderSliver child) {
40-
switch (constraints.axisDirection) {
41-
case AxisDirection.up:
42-
case AxisDirection.down:
43-
return (child.parentData! as SliverPhysicalParentData).paintOffset.dx;
44-
case AxisDirection.left:
45-
case AxisDirection.right:
46-
return (child.parentData! as SliverPhysicalParentData).paintOffset.dy;
47-
}
40+
final Offset paintOffset = (child.parentData! as SliverPhysicalParentData).paintOffset;
41+
return switch (constraints.axis) {
42+
Axis.vertical => paintOffset.dx,
43+
Axis.horizontal => paintOffset.dy,
44+
};
4845
}
4946

5047
@override

packages/flutter/lib/src/rendering/viewport.dart

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -925,22 +925,13 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
925925
assert(child is RenderSliver);
926926
final RenderSliver sliver = child as RenderSliver;
927927

928-
final double targetMainAxisExtent;
929928
// The scroll offset of `rect` within `child`.
930-
switch (applyGrowthDirectionToAxisDirection(axisDirection, growthDirection)) {
931-
case AxisDirection.up:
932-
leadingScrollOffset += pivotExtent - rectLocal.bottom;
933-
targetMainAxisExtent = rectLocal.height;
934-
case AxisDirection.right:
935-
leadingScrollOffset += rectLocal.left;
936-
targetMainAxisExtent = rectLocal.width;
937-
case AxisDirection.down:
938-
leadingScrollOffset += rectLocal.top;
939-
targetMainAxisExtent = rectLocal.height;
940-
case AxisDirection.left:
941-
leadingScrollOffset += pivotExtent - rectLocal.right;
942-
targetMainAxisExtent = rectLocal.width;
943-
}
929+
leadingScrollOffset += switch (applyGrowthDirectionToAxisDirection(axisDirection, growthDirection)) {
930+
AxisDirection.up => pivotExtent - rectLocal.bottom,
931+
AxisDirection.left => pivotExtent - rectLocal.right,
932+
AxisDirection.right => rectLocal.left,
933+
AxisDirection.down => rectLocal.top,
934+
};
944935

945936
// So far leadingScrollOffset is the scroll offset of `rect` in the `child`
946937
// sliver's sliver coordinate system. The sign of this value indicates
@@ -973,35 +964,26 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
973964
// If child's growth direction is reverse, when viewport.offset is
974965
// `leadingScrollOffset`, it is positioned just outside of the leading
975966
// edge of the viewport.
976-
switch (axis) {
977-
case Axis.vertical:
978-
leadingScrollOffset -= targetRect.height;
979-
case Axis.horizontal:
980-
leadingScrollOffset -= targetRect.width;
981-
}
967+
leadingScrollOffset -= switch (axis) {
968+
Axis.vertical => targetRect.height,
969+
Axis.horizontal => targetRect.width,
970+
};
982971
}
983972

984-
final double mainAxisExtent;
985-
switch (axis) {
986-
case Axis.horizontal:
987-
mainAxisExtent = size.width - extentOfPinnedSlivers;
988-
case Axis.vertical:
989-
mainAxisExtent = size.height - extentOfPinnedSlivers;
990-
}
973+
final double mainAxisExtentDifference = switch (axis) {
974+
Axis.horizontal => size.width - extentOfPinnedSlivers - rectLocal.width,
975+
Axis.vertical => size.height - extentOfPinnedSlivers - rectLocal.height,
976+
};
991977

992-
final double targetOffset = leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment;
978+
final double targetOffset = leadingScrollOffset - mainAxisExtentDifference * alignment;
993979
final double offsetDifference = offset.pixels - targetOffset;
994980

995-
switch (axisDirection) {
996-
case AxisDirection.down:
997-
targetRect = targetRect.translate(0.0, offsetDifference);
998-
case AxisDirection.right:
999-
targetRect = targetRect.translate(offsetDifference, 0.0);
1000-
case AxisDirection.up:
1001-
targetRect = targetRect.translate(0.0, -offsetDifference);
1002-
case AxisDirection.left:
1003-
targetRect = targetRect.translate(-offsetDifference, 0.0);
1004-
}
981+
targetRect = switch (axisDirection) {
982+
AxisDirection.up => targetRect.translate(0.0, -offsetDifference),
983+
AxisDirection.down => targetRect.translate(0.0, offsetDifference),
984+
AxisDirection.left => targetRect.translate(-offsetDifference, 0.0),
985+
AxisDirection.right => targetRect.translate( offsetDifference, 0.0),
986+
};
1005987

1006988
return RevealedOffset(offset: targetOffset, rect: targetRect);
1007989
}

0 commit comments

Comments
 (0)