Implementing switch expressions in widgets/ (#143293)

This PR is the 7ᵗʰ 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)

This pull request covers everything in `packages/flutter/lib/src/widgets/`. Most of it should be really straightforward, but there was some refactoring in the `getOffsetToReveal()` function in `two_dimensional_viewport.dart`. I'll add some comments to describe those changes.
This commit is contained in:
Nate 2024-02-13 11:51:03 -07:00 committed by GitHub
parent e94e406224
commit 8eea4f175f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 169 additions and 306 deletions

View file

@ -1244,12 +1244,10 @@ class _FocusableActionDetectorState extends State<FocusableActionDetector> {
bool _canShowHighlight = false;
void _updateHighlightMode(FocusHighlightMode mode) {
_mayTriggerCallback(task: () {
switch (FocusManager.instance.highlightMode) {
case FocusHighlightMode.touch:
_canShowHighlight = false;
case FocusHighlightMode.traditional:
_canShowHighlight = true;
}
_canShowHighlight = switch (FocusManager.instance.highlightMode) {
FocusHighlightMode.touch => false,
FocusHighlightMode.traditional => true,
};
});
}
@ -1303,13 +1301,10 @@ class _FocusableActionDetectorState extends State<FocusableActionDetector> {
}
bool canRequestFocus(FocusableActionDetector target) {
final NavigationMode mode = MediaQuery.maybeNavigationModeOf(context) ?? NavigationMode.traditional;
switch (mode) {
case NavigationMode.traditional:
return target.enabled;
case NavigationMode.directional:
return true;
}
return switch (MediaQuery.maybeNavigationModeOf(context)) {
NavigationMode.traditional || null => target.enabled,
NavigationMode.directional => true,
};
}
bool shouldShowFocusHighlight(FocusableActionDetector target) {
@ -1344,13 +1339,10 @@ class _FocusableActionDetectorState extends State<FocusableActionDetector> {
}
bool get _canRequestFocus {
final NavigationMode mode = MediaQuery.maybeNavigationModeOf(context) ?? NavigationMode.traditional;
switch (mode) {
case NavigationMode.traditional:
return widget.enabled;
case NavigationMode.directional:
return true;
}
return switch (MediaQuery.maybeNavigationModeOf(context)) {
NavigationMode.traditional || null => widget.enabled,
NavigationMode.directional => true,
};
}
// This global key is needed to keep only the necessary widgets in the tree

View file

@ -178,64 +178,32 @@ class BannerPainter extends CustomPainter {
bool hitTest(Offset position) => false;
double _translationX(double width) {
switch (layoutDirection) {
case TextDirection.rtl:
switch (location) {
case BannerLocation.bottomEnd:
return _kBottomOffset;
case BannerLocation.topEnd:
return 0.0;
case BannerLocation.bottomStart:
return width - _kBottomOffset;
case BannerLocation.topStart:
return width;
}
case TextDirection.ltr:
switch (location) {
case BannerLocation.bottomEnd:
return width - _kBottomOffset;
case BannerLocation.topEnd:
return width;
case BannerLocation.bottomStart:
return _kBottomOffset;
case BannerLocation.topStart:
return 0.0;
}
}
return switch ((layoutDirection, location)) {
(TextDirection.rtl, BannerLocation.topStart) => width,
(TextDirection.ltr, BannerLocation.topStart) => 0.0,
(TextDirection.rtl, BannerLocation.topEnd) => 0.0,
(TextDirection.ltr, BannerLocation.topEnd) => width,
(TextDirection.rtl, BannerLocation.bottomStart) => width - _kBottomOffset,
(TextDirection.ltr, BannerLocation.bottomStart) => _kBottomOffset,
(TextDirection.rtl, BannerLocation.bottomEnd) => _kBottomOffset,
(TextDirection.ltr, BannerLocation.bottomEnd) => width - _kBottomOffset,
};
}
double _translationY(double height) {
switch (location) {
case BannerLocation.bottomStart:
case BannerLocation.bottomEnd:
return height - _kBottomOffset;
case BannerLocation.topStart:
case BannerLocation.topEnd:
return 0.0;
}
return switch (location) {
BannerLocation.bottomStart || BannerLocation.bottomEnd => height - _kBottomOffset,
BannerLocation.topStart || BannerLocation.topEnd => 0.0,
};
}
double get _rotation {
switch (layoutDirection) {
case TextDirection.rtl:
switch (location) {
case BannerLocation.bottomStart:
case BannerLocation.topEnd:
return -math.pi / 4.0;
case BannerLocation.bottomEnd:
case BannerLocation.topStart:
return math.pi / 4.0;
}
case TextDirection.ltr:
switch (location) {
case BannerLocation.bottomStart:
case BannerLocation.topEnd:
return math.pi / 4.0;
case BannerLocation.bottomEnd:
case BannerLocation.topStart:
return -math.pi / 4.0;
}
}
return math.pi / 4.0 * switch ((layoutDirection, location)) {
(TextDirection.rtl, BannerLocation.topStart || BannerLocation.bottomEnd) => 1,
(TextDirection.ltr, BannerLocation.topStart || BannerLocation.bottomEnd) => -1,
(TextDirection.rtl, BannerLocation.bottomStart || BannerLocation.topEnd) => -1,
(TextDirection.ltr, BannerLocation.bottomStart || BannerLocation.topEnd) => 1,
};
}
}

View file

@ -2813,16 +2813,11 @@ class UnconstrainedBox extends StatelessWidget {
final Widget? child;
BoxConstraintsTransform _axisToTransform(Axis? constrainedAxis) {
if (constrainedAxis != null) {
switch (constrainedAxis) {
case Axis.horizontal:
return ConstraintsTransformBox.heightUnconstrained;
case Axis.vertical:
return ConstraintsTransformBox.widthUnconstrained;
}
} else {
return ConstraintsTransformBox.unconstrained;
}
return switch (constrainedAxis) {
Axis.horizontal => ConstraintsTransformBox.heightUnconstrained,
Axis.vertical => ConstraintsTransformBox.widthUnconstrained,
null => ConstraintsTransformBox.unconstrained,
};
}
@override
@ -4263,16 +4258,10 @@ class Positioned extends ParentDataWidget<StackParentData> {
double? height,
required Widget child,
}) {
double? left;
double? right;
switch (textDirection) {
case TextDirection.rtl:
left = end;
right = start;
case TextDirection.ltr:
left = start;
right = end;
}
final (double? left, double? right) = switch (textDirection) {
TextDirection.rtl => (end, start),
TextDirection.ltr => (start, end),
};
return Positioned(
key: key,
left: left,

View file

@ -785,15 +785,12 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
}
Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) {
switch (methodCall.method) {
case 'popRoute':
return handlePopRoute();
case 'pushRoute':
return handlePushRoute(methodCall.arguments as String);
case 'pushRouteInformation':
return _handlePushRouteInformation(methodCall.arguments as Map<dynamic, dynamic>);
}
return Future<dynamic>.value();
return switch (methodCall.method) {
'popRoute' => handlePopRoute(),
'pushRoute' => handlePushRoute(methodCall.arguments as String),
'pushRouteInformation' => _handlePushRouteInformation(methodCall.arguments as Map<dynamic, dynamic>),
_ => Future<dynamic>.value(),
};
}
@override

View file

@ -92,13 +92,10 @@ class DecoratedBox extends SingleChildRenderObjectWidget {
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
final String label;
switch (position) {
case DecorationPosition.background:
label = 'bg';
case DecorationPosition.foreground:
label = 'fg';
}
final String label = switch (position) {
DecorationPosition.background => 'bg',
DecorationPosition.foreground => 'fg',
};
properties.add(EnumProperty<DecorationPosition>('position', position, level: DiagnosticLevel.hidden));
properties.add(DiagnosticsProperty<Decoration>(label, decoration));
}

View file

@ -76,13 +76,10 @@ class DecoratedSliver extends SingleChildRenderObjectWidget {
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
final String label;
switch (position) {
case DecorationPosition.background:
label = 'bg';
case DecorationPosition.foreground:
label = 'fg';
}
final String label = switch (position) {
DecorationPosition.background => 'bg',
DecorationPosition.foreground => 'fg',
};
properties.add(EnumProperty<DecorationPosition>('position', position, level: DiagnosticLevel.hidden));
properties.add(DiagnosticsProperty<Decoration>(label, decoration));
}

View file

@ -472,20 +472,14 @@ class DefaultTextEditingShortcuts extends StatelessWidget {
};
static Map<ShortcutActivator, Intent> get _shortcuts {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return _androidShortcuts;
case TargetPlatform.fuchsia:
return _fuchsiaShortcuts;
case TargetPlatform.iOS:
return _iOSShortcuts;
case TargetPlatform.linux:
return _linuxShortcuts;
case TargetPlatform.macOS:
return _macShortcuts;
case TargetPlatform.windows:
return _windowsShortcuts;
}
return switch (defaultTargetPlatform) {
TargetPlatform.android => _androidShortcuts,
TargetPlatform.fuchsia => _fuchsiaShortcuts,
TargetPlatform.iOS => _iOSShortcuts,
TargetPlatform.linux => _linuxShortcuts,
TargetPlatform.macOS => _macShortcuts,
TargetPlatform.windows => _windowsShortcuts,
};
}
Map<ShortcutActivator, Intent>? _getDisablingShortcut() {

View file

@ -341,12 +341,11 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
return DismissDirection.none;
}
if (_directionIsXAxis) {
switch (Directionality.of(context)) {
case TextDirection.rtl:
return extent < 0 ? DismissDirection.startToEnd : DismissDirection.endToStart;
case TextDirection.ltr:
return extent > 0 ? DismissDirection.startToEnd : DismissDirection.endToStart;
}
return switch (Directionality.of(context)) {
TextDirection.rtl when extent < 0 => DismissDirection.startToEnd,
TextDirection.ltr when extent > 0 => DismissDirection.startToEnd,
TextDirection.rtl || TextDirection.ltr => DismissDirection.endToStart,
};
}
return extent > 0 ? DismissDirection.down : DismissDirection.up;
}

View file

@ -114,13 +114,10 @@ class DisplayFeatureSubScreen extends StatelessWidget {
}
static Offset _fallbackAnchorPoint(BuildContext context) {
final TextDirection textDirection = Directionality.of(context);
switch (textDirection) {
case TextDirection.rtl:
return const Offset(double.maxFinite, 0);
case TextDirection.ltr:
return Offset.zero;
}
return switch (Directionality.of(context)) {
TextDirection.rtl => const Offset(double.maxFinite, 0),
TextDirection.ltr => Offset.zero,
};
}
/// Returns the areas of the screen that are obstructed by display features.

View file

@ -109,26 +109,20 @@ class _ToolbarLayout extends MultiChildLayoutDelegate {
maxHeight: size.height,
);
leadingWidth = layoutChild(_ToolbarSlot.leading, constraints).width;
final double leadingX;
switch (textDirection) {
case TextDirection.rtl:
leadingX = size.width - leadingWidth;
case TextDirection.ltr:
leadingX = 0.0;
}
final double leadingX = switch (textDirection) {
TextDirection.rtl => size.width - leadingWidth,
TextDirection.ltr => 0.0,
};
positionChild(_ToolbarSlot.leading, Offset(leadingX, 0.0));
}
if (hasChild(_ToolbarSlot.trailing)) {
final BoxConstraints constraints = BoxConstraints.loose(size);
final Size trailingSize = layoutChild(_ToolbarSlot.trailing, constraints);
final double trailingX;
switch (textDirection) {
case TextDirection.rtl:
trailingX = 0.0;
case TextDirection.ltr:
trailingX = size.width - trailingSize.width;
}
final double trailingX = switch (textDirection) {
TextDirection.rtl => 0.0,
TextDirection.ltr => size.width - trailingSize.width,
};
final double trailingY = (size.height - trailingSize.height) / 2.0;
trailingWidth = trailingSize.width;
positionChild(_ToolbarSlot.trailing, Offset(trailingX, trailingY));
@ -153,13 +147,10 @@ class _ToolbarLayout extends MultiChildLayoutDelegate {
}
}
final double middleX;
switch (textDirection) {
case TextDirection.rtl:
middleX = size.width - middleSize.width - middleStart;
case TextDirection.ltr:
middleX = middleStart;
}
final double middleX = switch (textDirection) {
TextDirection.rtl => size.width - middleSize.width - middleStart,
TextDirection.ltr => middleStart,
};
positionChild(_ToolbarSlot.middle, Offset(middleX, middleY));
}

View file

@ -1686,17 +1686,11 @@ class SliverOverlapAbsorberHandle extends ChangeNotifier {
@override
String toString() {
String? extra;
switch (_writers) {
case 0:
extra = ', orphan';
case 1:
// normal case
break;
default:
extra = ', $_writers WRITERS ASSIGNED';
break;
}
final String? extra = switch (_writers) {
0 => ', orphan',
1 => null, // normal case
_ => ', $_writers WRITERS ASSIGNED',
};
return '${objectRuntimeType(this, 'SliverOverlapAbsorberHandle')}($layoutExtent$extra)';
}
}

View file

@ -467,15 +467,11 @@ class _RenderOverflowBar extends RenderBox
double y = 0;
while (child != null) {
final _OverflowBarParentData childParentData = child.parentData! as _OverflowBarParentData;
double x = 0;
switch (overflowAlignment) {
case OverflowBarAlignment.start:
x = rtl ? constraints.maxWidth - child.size.width : 0;
case OverflowBarAlignment.center:
x = (constraints.maxWidth - child.size.width) / 2;
case OverflowBarAlignment.end:
x = rtl ? 0 : constraints.maxWidth - child.size.width;
}
final double x = switch (overflowAlignment) {
OverflowBarAlignment.center => (constraints.maxWidth - child.size.width) / 2,
OverflowBarAlignment.start => rtl ? constraints.maxWidth - child.size.width : 0,
OverflowBarAlignment.end => rtl ? 0 : constraints.maxWidth - child.size.width,
};
childParentData.offset = Offset(x, y);
y += child.size.height + overflowSpacing;
child = nextChild();

View file

@ -972,12 +972,10 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
Widget _itemBuilder(BuildContext context, int index) {
if (_dragInfo != null && index >= widget.itemCount) {
switch (_scrollDirection) {
case Axis.horizontal:
return SizedBox(width: _dragInfo!.itemExtent);
case Axis.vertical:
return SizedBox(height: _dragInfo!.itemExtent);
}
return switch (_scrollDirection) {
Axis.horizontal => SizedBox(width: _dragInfo!.itemExtent),
Axis.vertical => SizedBox(height: _dragInfo!.itemExtent),
};
}
final Widget child = widget.itemBuilder(context, index);
assert(child.key != null, 'All list items must have a key');
@ -1500,39 +1498,31 @@ class _DragItemProxy extends StatelessWidget {
}
double _sizeExtent(Size size, Axis scrollDirection) {
switch (scrollDirection) {
case Axis.horizontal:
return size.width;
case Axis.vertical:
return size.height;
}
return switch (scrollDirection) {
Axis.horizontal => size.width,
Axis.vertical => size.height,
};
}
double _offsetExtent(Offset offset, Axis scrollDirection) {
switch (scrollDirection) {
case Axis.horizontal:
return offset.dx;
case Axis.vertical:
return offset.dy;
}
return switch (scrollDirection) {
Axis.horizontal => offset.dx,
Axis.vertical => offset.dy,
};
}
Offset _extentOffset(double extent, Axis scrollDirection) {
switch (scrollDirection) {
case Axis.horizontal:
return Offset(extent, 0.0);
case Axis.vertical:
return Offset(0.0, extent);
}
return switch (scrollDirection) {
Axis.horizontal => Offset(extent, 0.0),
Axis.vertical => Offset(0.0, extent),
};
}
Offset _restrictAxis(Offset offset, Axis scrollDirection) {
switch (scrollDirection) {
case Axis.horizontal:
return Offset(offset.dx, 0.0);
case Axis.vertical:
return Offset(0.0, offset.dy);
}
return switch (scrollDirection) {
Axis.horizontal => Offset(offset.dx, 0.0),
Axis.vertical => Offset(0.0, offset.dy),
};
}
// A global key that takes its identity from the object and uses a value of a

View file

@ -461,15 +461,11 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe
}
void _updateSelectionStatus() {
final TextSelection selection;
final SelectionGeometry geometry = _selectionDelegate.value;
switch (geometry.status) {
case SelectionStatus.uncollapsed:
case SelectionStatus.collapsed:
selection = const TextSelection(baseOffset: 0, extentOffset: 1);
case SelectionStatus.none:
selection = const TextSelection.collapsed(offset: 1);
}
final TextSelection selection = switch (geometry.status) {
SelectionStatus.uncollapsed || SelectionStatus.collapsed => const TextSelection(baseOffset: 0, extentOffset: 1),
SelectionStatus.none => const TextSelection.collapsed(offset: 1),
};
textEditingValue = TextEditingValue(text: '__', selection: selection);
if (_hasSelectionOverlayGeometry) {
_updateSelectionOverlay();

View file

@ -316,12 +316,10 @@ class _SemanticsDebuggerPainter extends CustomPainter {
effectivelabel = '${Unicode.FSI}$tooltipAndLabel${Unicode.PDI}';
annotations.insert(0, 'MISSING TEXT DIRECTION');
} else {
switch (data.textDirection!) {
case TextDirection.rtl:
effectivelabel = '${Unicode.RLI}$tooltipAndLabel${Unicode.PDI}';
case TextDirection.ltr:
effectivelabel = tooltipAndLabel;
}
effectivelabel = switch (data.textDirection!) {
TextDirection.rtl => '${Unicode.RLI}$tooltipAndLabel${Unicode.PDI}',
TextDirection.ltr => tooltipAndLabel,
};
}
if (annotations.isEmpty) {
message = effectivelabel;

View file

@ -1063,13 +1063,10 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
void debugVisitOnstageChildren(ElementVisitor visitor) {
_childElements.values.cast<Element>().where((Element child) {
final SliverMultiBoxAdaptorParentData parentData = child.renderObject!.parentData! as SliverMultiBoxAdaptorParentData;
final double itemExtent;
switch (renderObject.constraints.axis) {
case Axis.horizontal:
itemExtent = child.renderObject!.paintBounds.width;
case Axis.vertical:
itemExtent = child.renderObject!.paintBounds.height;
}
final double itemExtent = switch (renderObject.constraints.axis) {
Axis.horizontal => child.renderObject!.paintBounds.width,
Axis.vertical => child.renderObject!.paintBounds.height,
};
return parentData.layoutOffset != null &&
parentData.layoutOffset! < renderObject.constraints.scrollOffset + renderObject.constraints.remainingPaintExtent &&

View file

@ -913,12 +913,10 @@ class TextSelectionOverlay {
return TextSelectionHandleType.collapsed;
}
switch (textDirection) {
case TextDirection.ltr:
return ltrType;
case TextDirection.rtl:
return rtlType;
}
return switch (textDirection) {
TextDirection.ltr => ltrType,
TextDirection.rtl => rtlType,
};
}
}

View file

@ -296,19 +296,13 @@ class MatrixTransition extends AnimatedWidget {
// a saveLayer call. This is usually worthwhile when animating the layer,
// but leaving it in the layer tree before the animation has started or after
// it has finished significantly hurts performance.
final bool useFilterQuality;
switch (animation.status) {
case AnimationStatus.dismissed:
case AnimationStatus.completed:
useFilterQuality = false;
case AnimationStatus.forward:
case AnimationStatus.reverse:
useFilterQuality = true;
}
return Transform(
transform: onTransform(animation.value),
alignment: alignment,
filterQuality: useFilterQuality ? filterQuality : null,
filterQuality: switch (animation.status) {
AnimationStatus.forward || AnimationStatus.reverse => filterQuality,
AnimationStatus.dismissed || AnimationStatus.completed => null,
},
child: child,
);
}

View file

@ -947,31 +947,23 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA
final RenderBox box = child as RenderBox;
final Rect rectLocal = MatrixUtils.transformRect(target.getTransformTo(child), rect);
final double targetMainAxisExtent;
double leadingScrollOffset = offset;
// The scroll offset of `rect` within `child`.
switch (axisDirection) {
case AxisDirection.up:
leadingScrollOffset += child.size.height - rectLocal.bottom;
targetMainAxisExtent = rectLocal.height;
case AxisDirection.right:
leadingScrollOffset += rectLocal.left;
targetMainAxisExtent = rectLocal.width;
case AxisDirection.down:
leadingScrollOffset += rectLocal.top;
targetMainAxisExtent = rectLocal.height;
case AxisDirection.left:
leadingScrollOffset += child.size.width - rectLocal.right;
targetMainAxisExtent = rectLocal.width;
}
leadingScrollOffset += switch (axisDirection) {
AxisDirection.up => child.size.height - rectLocal.bottom,
AxisDirection.left => child.size.width - rectLocal.right,
AxisDirection.right => rectLocal.left,
AxisDirection.down => rectLocal.top,
};
// The scroll offset in the viewport to `rect`.
final TwoDimensionalViewportParentData childParentData = parentDataOf(box);
final Offset paintOffset = parentDataOf(box).paintOffset!;
leadingScrollOffset += switch (axisDirection) {
AxisDirection.down => childParentData.paintOffset!.dy,
AxisDirection.up => viewportDimension.height - childParentData.paintOffset!.dy - box.size.height,
AxisDirection.right => childParentData.paintOffset!.dx,
AxisDirection.left => viewportDimension.width - childParentData.paintOffset!.dx - box.size.width,
AxisDirection.up => viewportDimension.height - paintOffset.dy - box.size.height,
AxisDirection.left => viewportDimension.width - paintOffset.dx - box.size.width,
AxisDirection.right => paintOffset.dx,
AxisDirection.down => paintOffset.dy,
};
// This step assumes the viewport's layout is up-to-date, i.e., if
@ -980,27 +972,24 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA
final Matrix4 transform = target.getTransformTo(this);
Rect targetRect = MatrixUtils.transformRect(transform, rect);
final double mainAxisExtent = switch (axisDirectionToAxis(axisDirection)) {
Axis.horizontal => viewportDimension.width,
Axis.vertical => viewportDimension.height,
final double mainAxisExtentDifference = switch (axis) {
Axis.horizontal => viewportDimension.width - rectLocal.width,
Axis.vertical => viewportDimension.height - rectLocal.height,
};
final double targetOffset = leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment;
final double targetOffset = leadingScrollOffset - mainAxisExtentDifference * alignment;
final double offsetDifference = switch (axisDirectionToAxis(axisDirection)){
Axis.vertical => verticalOffset.pixels - targetOffset,
final double offsetDifference = switch (axis) {
Axis.horizontal => horizontalOffset.pixels - targetOffset,
Axis.vertical => verticalOffset.pixels - targetOffset,
};
targetRect = switch (axisDirection) {
AxisDirection.up => targetRect.translate(0.0, -offsetDifference),
AxisDirection.down => targetRect.translate(0.0, offsetDifference),
AxisDirection.left => targetRect.translate(-offsetDifference, 0.0),
AxisDirection.right => targetRect.translate( offsetDifference, 0.0),
};
switch (axisDirection) {
case AxisDirection.down:
targetRect = targetRect.translate(0.0, offsetDifference);
case AxisDirection.right:
targetRect = targetRect.translate(offsetDifference, 0.0);
case AxisDirection.up:
targetRect = targetRect.translate(0.0, -offsetDifference);
case AxisDirection.left:
targetRect = targetRect.translate(-offsetDifference, 0.0);
}
final RevealedOffset revealedOffset = RevealedOffset(
offset: targetOffset,
@ -1566,26 +1555,16 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA
// This is only usable once we have sizes.
assert(hasSize);
assert(child.hasSize);
final double xOffset;
final double yOffset;
switch (verticalAxisDirection) {
case AxisDirection.up:
yOffset = viewportDimension.height - (layoutOffset.dy + child.size.height);
case AxisDirection.down:
yOffset = layoutOffset.dy;
case AxisDirection.right:
case AxisDirection.left:
throw Exception('This should not happen');
}
switch (horizontalAxisDirection) {
case AxisDirection.right:
xOffset = layoutOffset.dx;
case AxisDirection.left:
xOffset = viewportDimension.width - (layoutOffset.dx + child.size.width);
case AxisDirection.up:
case AxisDirection.down:
throw Exception('This should not happen');
}
final double xOffset = switch (horizontalAxisDirection) {
AxisDirection.right => layoutOffset.dx,
AxisDirection.left => viewportDimension.width - (layoutOffset.dx + child.size.width),
AxisDirection.up || AxisDirection.down => throw Exception('This should not happen'),
};
final double yOffset = switch (verticalAxisDirection) {
AxisDirection.up => viewportDimension.height - (layoutOffset.dy + child.size.height),
AxisDirection.down => layoutOffset.dy,
AxisDirection.right || AxisDirection.left => throw Exception('This should not happen'),
};
return Offset(xOffset, yOffset);
}