mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
switch
expressions: finale (#148711)
### fixes #136139 <br> <details open> <summary><b>getting sentimental in the PR description</b> (click to collapse)<br><br></summary> The past 7 months have been quite the journeyâI made some huge blunders and some huge accomplishmentsâa very fun time overall. I really appreciate the people who took the time to perform code review for my refactoring shenanigans: **christopherfujino**, **andrewkolos**, **LongCatIsLooong**, **gspencergoog**, **loic-sharma**, **Piinks**, **bernaferrari**, **bartekpacia**, **bleroux**, **kevmoo**, **rakudrama**, **XilaiZhang**, **QuncCccccc**, **MominRaza**, and **victorsanni**. And a huge shoutout to 2 individuals: - @justinmc, for offering to sponsor me for commit access (words could not describe my excitement) - @goderbauer, for being super duper proactive and consistent with code review <br> </details> This pull request makes 13 "switch statements â switch expressions" PRs in total, reducing the LOC in this repo by **1,974**! From now on, I'll make sure to request a test exemption for each refactoring PR ð
This commit is contained in:
parent
454dd7e29c
commit
870c5541c3
@ -47,20 +47,14 @@ class StocksAppState extends State<StocksApp> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ThemeData get theme {
|
ThemeData get theme {
|
||||||
switch (_configuration.stockMode) {
|
|
||||||
case StockMode.optimistic:
|
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
useMaterial3: false,
|
useMaterial3: false,
|
||||||
brightness: Brightness.light,
|
brightness: switch (_configuration.stockMode) {
|
||||||
|
StockMode.optimistic => Brightness.light,
|
||||||
|
StockMode.pessimistic => Brightness.dark,
|
||||||
|
},
|
||||||
primarySwatch: Colors.purple,
|
primarySwatch: Colors.purple,
|
||||||
);
|
);
|
||||||
case StockMode.pessimistic:
|
|
||||||
return ThemeData(
|
|
||||||
useMaterial3: false,
|
|
||||||
brightness: Brightness.dark,
|
|
||||||
primarySwatch: Colors.purple,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Route<dynamic>? _getRoute(RouteSettings settings) {
|
Route<dynamic>? _getRoute(RouteSettings settings) {
|
||||||
|
@ -152,21 +152,13 @@ String getNewPrLink({
|
|||||||
}) {
|
}) {
|
||||||
assert(state.releaseChannel.isNotEmpty);
|
assert(state.releaseChannel.isNotEmpty);
|
||||||
assert(state.releaseVersion.isNotEmpty);
|
assert(state.releaseVersion.isNotEmpty);
|
||||||
late final String candidateBranch;
|
final (pb.Repository repository, String repoLabel) = switch (repoName) {
|
||||||
late final String workingBranch;
|
'flutter' => (state.framework, 'Framework'),
|
||||||
late final String repoLabel;
|
'engine' => (state.engine, 'Engine'),
|
||||||
switch (repoName) {
|
_ => throw ConductorException('Expected repoName to be one of flutter or engine but got $repoName.'),
|
||||||
case 'flutter':
|
};
|
||||||
candidateBranch = state.framework.candidateBranch;
|
final String candidateBranch = repository.candidateBranch;
|
||||||
workingBranch = state.framework.workingBranch;
|
final String workingBranch = repository.workingBranch;
|
||||||
repoLabel = 'Framework';
|
|
||||||
case 'engine':
|
|
||||||
candidateBranch = state.engine.candidateBranch;
|
|
||||||
workingBranch = state.engine.workingBranch;
|
|
||||||
repoLabel = 'Engine';
|
|
||||||
default:
|
|
||||||
throw ConductorException('Expected repoName to be one of flutter or engine but got $repoName.');
|
|
||||||
}
|
|
||||||
assert(candidateBranch.isNotEmpty);
|
assert(candidateBranch.isNotEmpty);
|
||||||
assert(workingBranch.isNotEmpty);
|
assert(workingBranch.isNotEmpty);
|
||||||
final String title = '[flutter_releases] Flutter ${state.releaseChannel} '
|
final String title = '[flutter_releases] Flutter ${state.releaseChannel} '
|
||||||
|
@ -377,22 +377,17 @@ class _CardsDemoState extends State<CardsDemo> {
|
|||||||
child: ListView(
|
child: ListView(
|
||||||
primary: true,
|
primary: true,
|
||||||
padding: const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0),
|
padding: const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0),
|
||||||
children: destinations.map<Widget>((TravelDestination destination) {
|
children: <Widget>[
|
||||||
Widget? child;
|
for (final TravelDestination destination in destinations)
|
||||||
switch (destination.type) {
|
Padding(
|
||||||
case CardDemoType.standard:
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
child = TravelDestinationItem(destination: destination, shape: _shape);
|
child: switch (destination.type) {
|
||||||
case CardDemoType.tappable:
|
CardDemoType.standard => TravelDestinationItem(destination: destination, shape: _shape),
|
||||||
child = TappableTravelDestinationItem(destination: destination, shape: _shape);
|
CardDemoType.tappable => TappableTravelDestinationItem(destination: destination, shape: _shape),
|
||||||
case CardDemoType.selectable:
|
CardDemoType.selectable => SelectableTravelDestinationItem(destination: destination, shape: _shape),
|
||||||
child = SelectableTravelDestinationItem(destination: destination, shape: _shape);
|
},
|
||||||
}
|
),
|
||||||
|
],
|
||||||
return Container(
|
|
||||||
margin: const EdgeInsets.only(bottom: 8.0),
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -100,20 +100,13 @@ class CutCornersBorder extends OutlineInputBorder {
|
|||||||
if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) {
|
if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) {
|
||||||
canvas.drawPath(_notchedCornerPath(outer.middleRect), paint);
|
canvas.drawPath(_notchedCornerPath(outer.middleRect), paint);
|
||||||
} else {
|
} else {
|
||||||
final double? extent = lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage);
|
final double extent = lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage)!;
|
||||||
switch (textDirection) {
|
if (textDirection != null) {
|
||||||
case TextDirection.rtl: {
|
final double start = switch (textDirection) {
|
||||||
final Path path = _notchedCornerPath(outer.middleRect, gapStart + gapPadding - extent!, extent);
|
TextDirection.rtl => gapStart + gapPadding - extent,
|
||||||
canvas.drawPath(path, paint);
|
TextDirection.ltr => gapStart - gapPadding,
|
||||||
break;
|
};
|
||||||
}
|
canvas.drawPath(_notchedCornerPath(outer.middleRect, start, extent), paint);
|
||||||
case TextDirection.ltr: {
|
|
||||||
final Path path = _notchedCornerPath(outer.middleRect, gapStart - gapPadding, extent);
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case null:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,37 +298,26 @@ class _CupertinoAlertDemoState extends State<CupertinoAlertDemo>
|
|||||||
),
|
),
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
|
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
|
||||||
|
final Widget showAlertButton = CupertinoButton.filled(
|
||||||
|
onPressed: () => switch (widget.type) {
|
||||||
|
AlertDemoType.alert => _alertDialogRoute,
|
||||||
|
AlertDemoType.alertTitle => _alertWithTitleDialogRoute,
|
||||||
|
AlertDemoType.alertButtons => _alertWithButtonsDialogRoute,
|
||||||
|
AlertDemoType.alertButtonsOnly => _alertWithButtonsOnlyDialogRoute,
|
||||||
|
AlertDemoType.actionSheet => _modalPopupRoute,
|
||||||
|
}.present(),
|
||||||
|
child: Text(localizations.cupertinoShowAlert),
|
||||||
|
);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(child: Center(child: showAlertButton)),
|
||||||
child: Center(
|
|
||||||
child: CupertinoButton.filled(
|
|
||||||
onPressed: () {
|
|
||||||
switch (widget.type) {
|
|
||||||
case AlertDemoType.alert:
|
|
||||||
_alertDialogRoute.present();
|
|
||||||
case AlertDemoType.alertTitle:
|
|
||||||
_alertWithTitleDialogRoute.present();
|
|
||||||
case AlertDemoType.alertButtons:
|
|
||||||
_alertWithButtonsDialogRoute.present();
|
|
||||||
case AlertDemoType.alertButtonsOnly:
|
|
||||||
_alertWithButtonsOnlyDialogRoute.present();
|
|
||||||
case AlertDemoType.actionSheet:
|
|
||||||
_modalPopupRoute.present();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
GalleryLocalizations.of(context)!.cupertinoShowAlert,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (lastSelectedValue.value != null)
|
if (lastSelectedValue.value != null)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
GalleryLocalizations.of(context)!
|
localizations.dialogSelectedOption(lastSelectedValue.value!),
|
||||||
.dialogSelectedOption(lastSelectedValue.value!),
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle,
|
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
@ -24,26 +24,18 @@ class ButtonDemo extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget? buttons;
|
|
||||||
switch (type) {
|
|
||||||
case ButtonDemoType.text:
|
|
||||||
buttons = _TextButtonDemo();
|
|
||||||
case ButtonDemoType.elevated:
|
|
||||||
buttons = _ElevatedButtonDemo();
|
|
||||||
case ButtonDemoType.outlined:
|
|
||||||
buttons = _OutlinedButtonDemo();
|
|
||||||
case ButtonDemoType.toggle:
|
|
||||||
buttons = _ToggleButtonsDemo();
|
|
||||||
case ButtonDemoType.floating:
|
|
||||||
buttons = _FloatingActionButtonDemo();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
title: Text(_title(context)),
|
title: Text(_title(context)),
|
||||||
),
|
),
|
||||||
body: buttons,
|
body: switch (type) {
|
||||||
|
ButtonDemoType.text => _TextButtonDemo(),
|
||||||
|
ButtonDemoType.elevated => _ElevatedButtonDemo(),
|
||||||
|
ButtonDemoType.outlined => _OutlinedButtonDemo(),
|
||||||
|
ButtonDemoType.toggle => _ToggleButtonsDemo(),
|
||||||
|
ButtonDemoType.floating => _FloatingActionButtonDemo(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,24 +26,17 @@ class ChipDemo extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget? buttons;
|
|
||||||
switch (type) {
|
|
||||||
case ChipDemoType.action:
|
|
||||||
buttons = _ActionChipDemo();
|
|
||||||
case ChipDemoType.choice:
|
|
||||||
buttons = _ChoiceChipDemo();
|
|
||||||
case ChipDemoType.filter:
|
|
||||||
buttons = _FilterChipDemo();
|
|
||||||
case ChipDemoType.input:
|
|
||||||
buttons = _InputChipDemo();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
title: Text(_title(context)),
|
title: Text(_title(context)),
|
||||||
),
|
),
|
||||||
body: buttons,
|
body: switch (type) {
|
||||||
|
ChipDemoType.action => _ActionChipDemo(),
|
||||||
|
ChipDemoType.choice => _ChoiceChipDemo(),
|
||||||
|
ChipDemoType.filter => _FilterChipDemo(),
|
||||||
|
ChipDemoType.input => _InputChipDemo(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,33 +11,23 @@ class DividerDemo extends StatelessWidget {
|
|||||||
|
|
||||||
final DividerDemoType type;
|
final DividerDemoType type;
|
||||||
|
|
||||||
String _title(BuildContext context) {
|
|
||||||
switch (type) {
|
|
||||||
case DividerDemoType.horizontal:
|
|
||||||
return GalleryLocalizations.of(context)!.demoDividerTitle;
|
|
||||||
case DividerDemoType.vertical:
|
|
||||||
return GalleryLocalizations.of(context)!.demoVerticalDividerTitle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
late Widget dividers;
|
final GalleryLocalizations localizations = GalleryLocalizations.of(context)!;
|
||||||
switch (type) {
|
|
||||||
case DividerDemoType.horizontal:
|
|
||||||
dividers = _HorizontalDividerDemo();
|
|
||||||
case DividerDemoType.vertical:
|
|
||||||
dividers = _VerticalDividerDemo();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
title: Text(
|
title: Text(
|
||||||
_title(context),
|
switch (type) {
|
||||||
|
DividerDemoType.horizontal => localizations.demoDividerTitle,
|
||||||
|
DividerDemoType.vertical => localizations.demoVerticalDividerTitle,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: dividers,
|
body: switch (type) {
|
||||||
|
DividerDemoType.horizontal => _HorizontalDividerDemo(),
|
||||||
|
DividerDemoType.vertical => _VerticalDividerDemo(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,14 +172,12 @@ class _PickerDemoState extends State<PickerDemo> with RestorationMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String get _labelText {
|
String get _labelText {
|
||||||
switch (widget.type) {
|
final DateFormat yMMMd = DateFormat.yMMMd();
|
||||||
case PickerDemoType.date:
|
return switch (widget.type) {
|
||||||
return DateFormat.yMMMd().format(_fromDate.value);
|
PickerDemoType.date => yMMMd.format(_fromDate.value),
|
||||||
case PickerDemoType.time:
|
PickerDemoType.time => _fromTime.value.format(context),
|
||||||
return _fromTime.value.format(context);
|
PickerDemoType.range => '${yMMMd.format(_startDate.value)} - ${yMMMd.format(_endDate.value)}',
|
||||||
case PickerDemoType.range:
|
};
|
||||||
return '${DateFormat.yMMMd().format(_startDate.value)} - ${DateFormat.yMMMd().format(_endDate.value)}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -199,16 +197,11 @@ class _PickerDemoState extends State<PickerDemo> with RestorationMixin {
|
|||||||
Text(_labelText),
|
Text(_labelText),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () => switch (widget.type) {
|
||||||
switch (widget.type) {
|
PickerDemoType.date => _restorableDatePickerRouteFuture,
|
||||||
case PickerDemoType.date:
|
PickerDemoType.time => _restorableTimePickerRouteFuture,
|
||||||
_restorableDatePickerRouteFuture.present();
|
PickerDemoType.range => _restorableDateRangePickerRouteFuture,
|
||||||
case PickerDemoType.time:
|
}.present(),
|
||||||
_restorableTimePickerRouteFuture.present();
|
|
||||||
case PickerDemoType.range:
|
|
||||||
_restorableDateRangePickerRouteFuture.present();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text(
|
child: Text(
|
||||||
GalleryLocalizations.of(context)!.demoPickersShowPicker,
|
GalleryLocalizations.of(context)!.demoPickersShowPicker,
|
||||||
),
|
),
|
||||||
|
@ -27,22 +27,16 @@ class SelectionControlsDemo extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget? controls;
|
|
||||||
switch (type) {
|
|
||||||
case SelectionControlsDemoType.checkbox:
|
|
||||||
controls = _CheckboxDemo();
|
|
||||||
case SelectionControlsDemoType.radio:
|
|
||||||
controls = _RadioDemo();
|
|
||||||
case SelectionControlsDemoType.switches:
|
|
||||||
controls = _SwitchDemo();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
title: Text(_title(context)),
|
title: Text(_title(context)),
|
||||||
),
|
),
|
||||||
body: controls,
|
body: switch (type) {
|
||||||
|
SelectionControlsDemoType.checkbox => _CheckboxDemo(),
|
||||||
|
SelectionControlsDemoType.radio => _RadioDemo(),
|
||||||
|
SelectionControlsDemoType.switches => _SwitchDemo(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,21 +27,16 @@ class SlidersDemo extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget sliders;
|
|
||||||
switch (type) {
|
|
||||||
case SlidersDemoType.sliders:
|
|
||||||
sliders = _Sliders();
|
|
||||||
case SlidersDemoType.rangeSliders:
|
|
||||||
sliders = _RangeSliders();
|
|
||||||
case SlidersDemoType.customSliders:
|
|
||||||
sliders = _CustomSliders();
|
|
||||||
}
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
title: Text(_title(context)),
|
title: Text(_title(context)),
|
||||||
),
|
),
|
||||||
body: sliders,
|
body: switch (type) {
|
||||||
|
SlidersDemoType.sliders => _Sliders(),
|
||||||
|
SlidersDemoType.rangeSliders => _RangeSliders(),
|
||||||
|
SlidersDemoType.customSliders => _CustomSliders(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,25 +340,13 @@ class _CustomRangeThumbShape extends RangeSliderThumbShape {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final double size = _thumbSize * sizeTween.evaluate(enableAnimation);
|
final double size = _thumbSize * sizeTween.evaluate(enableAnimation);
|
||||||
Path thumbPath;
|
|
||||||
switch (textDirection!) {
|
|
||||||
case TextDirection.rtl:
|
|
||||||
switch (thumb!) {
|
|
||||||
case Thumb.start:
|
|
||||||
thumbPath = _rightTriangle(size, center);
|
|
||||||
case Thumb.end:
|
|
||||||
thumbPath = _leftTriangle(size, center);
|
|
||||||
}
|
|
||||||
case TextDirection.ltr:
|
|
||||||
switch (thumb!) {
|
|
||||||
case Thumb.start:
|
|
||||||
thumbPath = _leftTriangle(size, center);
|
|
||||||
case Thumb.end:
|
|
||||||
thumbPath = _rightTriangle(size, center);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
canvas.drawPath(
|
canvas.drawPath(
|
||||||
thumbPath,
|
switch ((textDirection!, thumb!)) {
|
||||||
|
(TextDirection.rtl, Thumb.start) => _rightTriangle(size, center),
|
||||||
|
(TextDirection.rtl, Thumb.end) => _leftTriangle(size, center),
|
||||||
|
(TextDirection.ltr, Thumb.start) => _leftTriangle(size, center),
|
||||||
|
(TextDirection.ltr, Thumb.end) => _rightTriangle(size, center),
|
||||||
|
},
|
||||||
Paint()..color = colorTween.evaluate(enableAnimation)!,
|
Paint()..color = colorTween.evaluate(enableAnimation)!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -102,23 +102,12 @@ class CutCornersBorder extends OutlineInputBorder {
|
|||||||
if (gapStart == null || gapExtent <= 0 || gapPercentage == 0) {
|
if (gapStart == null || gapExtent <= 0 || gapPercentage == 0) {
|
||||||
canvas.drawPath(_notchedCornerPath(outer.middleRect), paint);
|
canvas.drawPath(_notchedCornerPath(outer.middleRect), paint);
|
||||||
} else {
|
} else {
|
||||||
final double? extent = lerpDouble(0.0, gapExtent + gapPadding * 2, gapPercentage);
|
final double extent = lerpDouble(0.0, gapExtent + gapPadding * 2, gapPercentage)!;
|
||||||
switch (textDirection!) {
|
final double start = switch (textDirection!) {
|
||||||
case TextDirection.rtl:
|
TextDirection.rtl => gapStart + gapPadding - extent,
|
||||||
{
|
TextDirection.ltr => gapStart - gapPadding,
|
||||||
final Path path = _notchedCornerPath(
|
};
|
||||||
outer.middleRect, gapStart + gapPadding - extent!, extent);
|
canvas.drawPath(_notchedCornerPath(outer.middleRect, start, extent), paint);
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TextDirection.ltr:
|
|
||||||
{
|
|
||||||
final Path path = _notchedCornerPath(
|
|
||||||
outer.middleRect, gapStart - gapPadding, extent!);
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,17 +400,12 @@ $factoryDeclaration
|
|||||||
///
|
///
|
||||||
/// Used by [generateGetter] below.
|
/// Used by [generateGetter] below.
|
||||||
String generateType(Map<String, dynamic>? attributes) {
|
String generateType(Map<String, dynamic>? attributes) {
|
||||||
bool optional = false;
|
final bool optional = attributes?.containsKey('optional') ?? false;
|
||||||
String type = 'String';
|
final String type = switch (attributes?['x-flutter-type']) {
|
||||||
if (attributes != null) {
|
'icuShortTimePattern' => 'TimeOfDayFormat',
|
||||||
optional = attributes.containsKey('optional');
|
'scriptCategory' => 'ScriptCategory',
|
||||||
switch (attributes['x-flutter-type'] as String?) {
|
_ => 'String',
|
||||||
case 'icuShortTimePattern':
|
};
|
||||||
type = 'TimeOfDayFormat';
|
|
||||||
case 'scriptCategory':
|
|
||||||
type = 'ScriptCategory';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return type + (optional ? '?' : '');
|
return type + (optional ? '?' : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,33 +35,17 @@ class _MyWidgetState extends State<MyWidget> {
|
|||||||
AxisDirection _axisDirection = AxisDirection.down;
|
AxisDirection _axisDirection = AxisDirection.down;
|
||||||
|
|
||||||
Widget _getArrows() {
|
Widget _getArrows() {
|
||||||
final Widget arrow;
|
final Widget arrow = switch (_axisDirection) {
|
||||||
switch (_axisDirection) {
|
AxisDirection.up => const Icon(Icons.arrow_upward_rounded),
|
||||||
case AxisDirection.up:
|
AxisDirection.down => const Icon(Icons.arrow_downward_rounded),
|
||||||
arrow = const Icon(Icons.arrow_upward_rounded);
|
AxisDirection.left => const Icon(Icons.arrow_back_rounded),
|
||||||
return Row(
|
AxisDirection.right => const Icon(Icons.arrow_forward_rounded),
|
||||||
|
};
|
||||||
|
return Flex(
|
||||||
|
direction: flipAxis(axisDirectionToAxis(_axisDirection)),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[arrow, arrow],
|
children: <Widget>[arrow, arrow],
|
||||||
);
|
);
|
||||||
case AxisDirection.down:
|
|
||||||
arrow = const Icon(Icons.arrow_downward_rounded);
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
case AxisDirection.left:
|
|
||||||
arrow = const Icon(Icons.arrow_back_rounded);
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
case AxisDirection.right:
|
|
||||||
arrow = const Icon(Icons.arrow_forward_rounded);
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
|
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
|
||||||
|
@ -37,33 +37,17 @@ class _MyWidgetState extends State<MyWidget> {
|
|||||||
AxisDirection _axisDirection = AxisDirection.down;
|
AxisDirection _axisDirection = AxisDirection.down;
|
||||||
|
|
||||||
Widget _getArrows(AxisDirection axisDirection) {
|
Widget _getArrows(AxisDirection axisDirection) {
|
||||||
final Widget arrow;
|
final Widget arrow = switch (axisDirection) {
|
||||||
switch (axisDirection) {
|
AxisDirection.up => const Icon(Icons.arrow_upward_rounded),
|
||||||
case AxisDirection.up:
|
AxisDirection.down => const Icon(Icons.arrow_downward_rounded),
|
||||||
arrow = const Icon(Icons.arrow_upward_rounded);
|
AxisDirection.left => const Icon(Icons.arrow_back_rounded),
|
||||||
return Row(
|
AxisDirection.right => const Icon(Icons.arrow_forward_rounded),
|
||||||
|
};
|
||||||
|
return Flex(
|
||||||
|
direction: flipAxis(axisDirectionToAxis(axisDirection)),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[arrow, arrow],
|
children: <Widget>[arrow, arrow],
|
||||||
);
|
);
|
||||||
case AxisDirection.down:
|
|
||||||
arrow = const Icon(Icons.arrow_downward_rounded);
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
case AxisDirection.left:
|
|
||||||
arrow = const Icon(Icons.arrow_back_rounded);
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
case AxisDirection.right:
|
|
||||||
arrow = const Icon(Icons.arrow_forward_rounded);
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
|
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
|
||||||
|
@ -37,33 +37,17 @@ class _MyWidgetState extends State<MyWidget> {
|
|||||||
AxisDirection _axisDirection = AxisDirection.down;
|
AxisDirection _axisDirection = AxisDirection.down;
|
||||||
|
|
||||||
Widget _getArrows() {
|
Widget _getArrows() {
|
||||||
final Widget arrow;
|
final Widget arrow = switch (_axisDirection) {
|
||||||
switch (_axisDirection) {
|
AxisDirection.up => const Icon(Icons.arrow_upward_rounded),
|
||||||
case AxisDirection.up:
|
AxisDirection.down => const Icon(Icons.arrow_downward_rounded),
|
||||||
arrow = const Icon(Icons.arrow_upward_rounded);
|
AxisDirection.left => const Icon(Icons.arrow_back_rounded),
|
||||||
return Row(
|
AxisDirection.right => const Icon(Icons.arrow_forward_rounded),
|
||||||
|
};
|
||||||
|
return Flex(
|
||||||
|
direction: flipAxis(axisDirectionToAxis(_axisDirection)),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[arrow, arrow],
|
children: <Widget>[arrow, arrow],
|
||||||
);
|
);
|
||||||
case AxisDirection.down:
|
|
||||||
arrow = const Icon(Icons.arrow_downward_rounded);
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
case AxisDirection.left:
|
|
||||||
arrow = const Icon(Icons.arrow_back_rounded);
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
case AxisDirection.right:
|
|
||||||
arrow = const Icon(Icons.arrow_forward_rounded);
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[arrow, arrow],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
|
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
|
||||||
|
@ -39,6 +39,24 @@ class _OverlayExampleState extends State<OverlayExample> {
|
|||||||
|
|
||||||
assert(overlayEntry == null);
|
assert(overlayEntry == null);
|
||||||
|
|
||||||
|
Widget builder(BuildContext context) {
|
||||||
|
final (String label, Color? color) = switch (currentPageIndex) {
|
||||||
|
0 => ('Explore page', Colors.red),
|
||||||
|
1 => ('Commute page', Colors.green),
|
||||||
|
2 => ('Saved page', Colors.orange),
|
||||||
|
_ => ('No page selected.', null),
|
||||||
|
};
|
||||||
|
if (color == null) {
|
||||||
|
return Text(label);
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Text(label, style: TextStyle(color: color)),
|
||||||
|
Icon(Icons.arrow_downward, color: color),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
overlayEntry = OverlayEntry(
|
overlayEntry = OverlayEntry(
|
||||||
// Create a new OverlayEntry.
|
// Create a new OverlayEntry.
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
@ -58,57 +76,7 @@ class _OverlayExampleState extends State<OverlayExample> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
const Text('Tap here for'),
|
const Text('Tap here for'),
|
||||||
Builder(builder: (BuildContext context) {
|
Builder(builder: builder),
|
||||||
switch (currentPageIndex) {
|
|
||||||
case 0:
|
|
||||||
return const Column(
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
'Explore page',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Icon(
|
|
||||||
Icons.arrow_downward,
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
case 1:
|
|
||||||
return const Column(
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
'Commute page',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.green,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Icon(
|
|
||||||
Icons.arrow_downward,
|
|
||||||
color: Colors.green,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
case 2:
|
|
||||||
return const Column(
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
'Saved page',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.orange,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Icon(
|
|
||||||
Icons.arrow_downward,
|
|
||||||
color: Colors.orange,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return const Text('No page selected.');
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: MediaQuery.of(context).size.width / 3,
|
width: MediaQuery.of(context).size.width / 3,
|
||||||
height: 80.0,
|
height: 80.0,
|
||||||
|
@ -199,18 +199,13 @@ class _CupertinoScrollbarState extends RawScrollbarState<CupertinoScrollbar> {
|
|||||||
}
|
}
|
||||||
_thicknessAnimationController.reverse();
|
_thicknessAnimationController.reverse();
|
||||||
super.handleThumbPressEnd(localPosition, velocity);
|
super.handleThumbPressEnd(localPosition, velocity);
|
||||||
switch (direction) {
|
final (double axisPosition, double axisVelocity) = switch (direction) {
|
||||||
case Axis.vertical:
|
Axis.horizontal => (localPosition.dx, velocity.pixelsPerSecond.dx),
|
||||||
if (velocity.pixelsPerSecond.dy.abs() < 10 &&
|
Axis.vertical => (localPosition.dy, velocity.pixelsPerSecond.dy),
|
||||||
(localPosition.dy - _pressStartAxisPosition).abs() > 0) {
|
};
|
||||||
|
if (axisPosition != _pressStartAxisPosition && axisVelocity.abs() < 10) {
|
||||||
HapticFeedback.mediumImpact();
|
HapticFeedback.mediumImpact();
|
||||||
}
|
}
|
||||||
case Axis.horizontal:
|
|
||||||
if (velocity.pixelsPerSecond.dx.abs() < 10 &&
|
|
||||||
(localPosition.dx - _pressStartAxisPosition).abs() > 0) {
|
|
||||||
HapticFeedback.mediumImpact();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -560,20 +560,17 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
|
|||||||
|
|
||||||
bool _previouslyOpened = false;
|
bool _previouslyOpened = false;
|
||||||
|
|
||||||
|
int get _directionFactor {
|
||||||
|
return switch ((Directionality.of(context), widget.alignment)) {
|
||||||
|
(TextDirection.rtl, DrawerAlignment.start) => -1,
|
||||||
|
(TextDirection.rtl, DrawerAlignment.end) => 1,
|
||||||
|
(TextDirection.ltr, DrawerAlignment.start) => 1,
|
||||||
|
(TextDirection.ltr, DrawerAlignment.end) => -1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void _move(DragUpdateDetails details) {
|
void _move(DragUpdateDetails details) {
|
||||||
double delta = details.primaryDelta! / _width;
|
_controller.value += details.primaryDelta! / _width * _directionFactor;
|
||||||
switch (widget.alignment) {
|
|
||||||
case DrawerAlignment.start:
|
|
||||||
break;
|
|
||||||
case DrawerAlignment.end:
|
|
||||||
delta = -delta;
|
|
||||||
}
|
|
||||||
switch (Directionality.of(context)) {
|
|
||||||
case TextDirection.rtl:
|
|
||||||
_controller.value -= delta;
|
|
||||||
case TextDirection.ltr:
|
|
||||||
_controller.value += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
final bool opened = _controller.value > 0.5;
|
final bool opened = _controller.value > 0.5;
|
||||||
if (opened != _previouslyOpened && widget.drawerCallback != null) {
|
if (opened != _previouslyOpened && widget.drawerCallback != null) {
|
||||||
@ -586,22 +583,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
|
|||||||
if (_controller.isDismissed) {
|
if (_controller.isDismissed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (details.velocity.pixelsPerSecond.dx.abs() >= _kMinFlingVelocity) {
|
final double xVelocity = details.velocity.pixelsPerSecond.dx;
|
||||||
double visualVelocity = details.velocity.pixelsPerSecond.dx / _width;
|
if (xVelocity.abs() >= _kMinFlingVelocity) {
|
||||||
switch (widget.alignment) {
|
final double visualVelocity = xVelocity / _width * _directionFactor;
|
||||||
case DrawerAlignment.start:
|
|
||||||
break;
|
|
||||||
case DrawerAlignment.end:
|
|
||||||
visualVelocity = -visualVelocity;
|
|
||||||
}
|
|
||||||
switch (Directionality.of(context)) {
|
|
||||||
case TextDirection.rtl:
|
|
||||||
_controller.fling(velocity: -visualVelocity);
|
|
||||||
widget.drawerCallback?.call(visualVelocity < 0.0);
|
|
||||||
case TextDirection.ltr:
|
|
||||||
_controller.fling(velocity: visualVelocity);
|
_controller.fling(velocity: visualVelocity);
|
||||||
widget.drawerCallback?.call(visualVelocity > 0.0);
|
widget.drawerCallback?.call(visualVelocity > 0.0);
|
||||||
}
|
|
||||||
} else if (_controller.value < 0.5) {
|
} else if (_controller.value < 0.5) {
|
||||||
close();
|
close();
|
||||||
} else {
|
} else {
|
||||||
|
@ -539,15 +539,12 @@ class OutlineInputBorder extends InputBorder {
|
|||||||
canvas.drawRRect(center, paint);
|
canvas.drawRRect(center, paint);
|
||||||
} else {
|
} else {
|
||||||
final double extent = lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage)!;
|
final double extent = lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage)!;
|
||||||
switch (textDirection!) {
|
final double start = switch (textDirection!) {
|
||||||
case TextDirection.rtl:
|
TextDirection.rtl => gapStart + gapPadding - extent,
|
||||||
final Path path = _gapBorderPath(canvas, center, math.max(0.0, gapStart + gapPadding - extent), extent);
|
TextDirection.ltr => gapStart - gapPadding,
|
||||||
|
};
|
||||||
|
final Path path = _gapBorderPath(canvas, center, math.max(0.0, start), extent);
|
||||||
canvas.drawPath(path, paint);
|
canvas.drawPath(path, paint);
|
||||||
|
|
||||||
case TextDirection.ltr:
|
|
||||||
final Path path = _gapBorderPath(canvas, center, math.max(0.0, gapStart - gapPadding), extent);
|
|
||||||
canvas.drawPath(path, paint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,36 +456,20 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
|
|||||||
|
|
||||||
Widget _buildCircleChild(int index, bool oldState) {
|
Widget _buildCircleChild(int index, bool oldState) {
|
||||||
final StepState state = oldState ? _oldStates[index]! : widget.steps[index].state;
|
final StepState state = oldState ? _oldStates[index]! : widget.steps[index].state;
|
||||||
final bool isDarkActive = _isDark() && widget.steps[index].isActive;
|
if (widget.stepIconBuilder?.call(index, state) case final Widget icon) {
|
||||||
final Widget? icon = widget.stepIconBuilder?.call(index, state);
|
|
||||||
if (icon != null) {
|
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
TextStyle? textStyle = _stepStyle(index)?.indexStyle;
|
TextStyle? textStyle = _stepStyle(index)?.indexStyle;
|
||||||
|
final bool isDarkActive = _isDark() && widget.steps[index].isActive;
|
||||||
|
final Color iconColor = isDarkActive ? _kCircleActiveDark : _kCircleActiveLight;
|
||||||
textStyle ??= isDarkActive ? _kStepStyle.copyWith(color: Colors.black87) : _kStepStyle;
|
textStyle ??= isDarkActive ? _kStepStyle.copyWith(color: Colors.black87) : _kStepStyle;
|
||||||
|
|
||||||
switch (state) {
|
return switch (state) {
|
||||||
case StepState.indexed:
|
StepState.indexed || StepState.disabled => Text('${index + 1}', style: textStyle),
|
||||||
case StepState.disabled:
|
StepState.editing => Icon(Icons.edit, color: iconColor, size: 18.0),
|
||||||
return Text(
|
StepState.complete => Icon(Icons.check, color: iconColor, size: 18.0),
|
||||||
'${index + 1}',
|
StepState.error => const Center(child: Text('!', style: _kStepStyle)),
|
||||||
style: textStyle,
|
};
|
||||||
);
|
|
||||||
case StepState.editing:
|
|
||||||
return Icon(
|
|
||||||
Icons.edit,
|
|
||||||
color: isDarkActive ? _kCircleActiveDark : _kCircleActiveLight,
|
|
||||||
size: 18.0,
|
|
||||||
);
|
|
||||||
case StepState.complete:
|
|
||||||
return Icon(
|
|
||||||
Icons.check,
|
|
||||||
color: isDarkActive ? _kCircleActiveDark : _kCircleActiveLight,
|
|
||||||
size: 18.0,
|
|
||||||
);
|
|
||||||
case StepState.error:
|
|
||||||
return const Center(child: Text('!', style: _kStepStyle));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Color _circleColor(int index) {
|
Color _circleColor(int index) {
|
||||||
|
@ -705,25 +705,14 @@ mixin DirectionalFocusTraversalPolicyMixin on FocusTraversalPolicy {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
FocusNode? findFirstFocusInDirection(FocusNode currentNode, TraversalDirection direction) {
|
FocusNode? findFirstFocusInDirection(FocusNode currentNode, TraversalDirection direction) {
|
||||||
switch (direction) {
|
|
||||||
case TraversalDirection.up:
|
|
||||||
// Find the bottom-most node so we can go up from there.
|
|
||||||
return _sortAndFindInitial(currentNode, vertical: true, first: false);
|
|
||||||
case TraversalDirection.down:
|
|
||||||
// Find the top-most node so we can go down from there.
|
|
||||||
return _sortAndFindInitial(currentNode, vertical: true, first: true);
|
|
||||||
case TraversalDirection.left:
|
|
||||||
// Find the right-most node so we can go left from there.
|
|
||||||
return _sortAndFindInitial(currentNode, vertical: false, first: false);
|
|
||||||
case TraversalDirection.right:
|
|
||||||
// Find the left-most node so we can go right from there.
|
|
||||||
return _sortAndFindInitial(currentNode, vertical: false, first: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FocusNode? _sortAndFindInitial(FocusNode currentNode, {required bool vertical, required bool first}) {
|
|
||||||
final Iterable<FocusNode> nodes = currentNode.nearestScope!.traversalDescendants;
|
final Iterable<FocusNode> nodes = currentNode.nearestScope!.traversalDescendants;
|
||||||
final List<FocusNode> sorted = nodes.toList();
|
final List<FocusNode> sorted = nodes.toList();
|
||||||
|
final (bool vertical, bool first) = switch (direction) {
|
||||||
|
TraversalDirection.up => (true, false), // Start with the bottom-most node.
|
||||||
|
TraversalDirection.down => (true, true), // Start with the topmost node.
|
||||||
|
TraversalDirection.left => (false, false), // Start with the rightmost node.
|
||||||
|
TraversalDirection.right => (false, true), // Start with the leftmost node.
|
||||||
|
};
|
||||||
mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) {
|
mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) {
|
||||||
if (vertical) {
|
if (vertical) {
|
||||||
if (first) {
|
if (first) {
|
||||||
@ -740,11 +729,7 @@ mixin DirectionalFocusTraversalPolicyMixin on FocusTraversalPolicy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sorted.isNotEmpty) {
|
return sorted.firstOrNull;
|
||||||
return sorted.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _verticalCompare(Offset target, Offset a, Offset b) {
|
static int _verticalCompare(Offset target, Offset a, Offset b) {
|
||||||
@ -849,17 +834,11 @@ mixin DirectionalFocusTraversalPolicyMixin on FocusTraversalPolicy {
|
|||||||
Iterable<FocusNode> nodes,
|
Iterable<FocusNode> nodes,
|
||||||
) {
|
) {
|
||||||
assert(direction == TraversalDirection.left || direction == TraversalDirection.right);
|
assert(direction == TraversalDirection.left || direction == TraversalDirection.right);
|
||||||
final Iterable<FocusNode> filtered;
|
final List<FocusNode> sorted = nodes.where(switch (direction) {
|
||||||
switch (direction) {
|
TraversalDirection.left => (FocusNode node) => node.rect != target && node.rect.center.dx <= target.left,
|
||||||
case TraversalDirection.left:
|
TraversalDirection.right => (FocusNode node) => node.rect != target && node.rect.center.dx >= target.right,
|
||||||
filtered = nodes.where((FocusNode node) => node.rect != target && node.rect.center.dx <= target.left);
|
TraversalDirection.up || TraversalDirection.down => throw ArgumentError('Invalid direction $direction'),
|
||||||
case TraversalDirection.right:
|
}).toList();
|
||||||
filtered = nodes.where((FocusNode node) => node.rect != target && node.rect.center.dx >= target.right);
|
|
||||||
case TraversalDirection.up:
|
|
||||||
case TraversalDirection.down:
|
|
||||||
throw ArgumentError('Invalid direction $direction');
|
|
||||||
}
|
|
||||||
final List<FocusNode> sorted = filtered.toList();
|
|
||||||
// Sort all nodes from left to right.
|
// Sort all nodes from left to right.
|
||||||
mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) => a.rect.center.dx.compareTo(b.rect.center.dx));
|
mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) => a.rect.center.dx.compareTo(b.rect.center.dx));
|
||||||
return sorted;
|
return sorted;
|
||||||
@ -874,17 +853,11 @@ mixin DirectionalFocusTraversalPolicyMixin on FocusTraversalPolicy {
|
|||||||
Iterable<FocusNode> nodes,
|
Iterable<FocusNode> nodes,
|
||||||
) {
|
) {
|
||||||
assert(direction == TraversalDirection.up || direction == TraversalDirection.down);
|
assert(direction == TraversalDirection.up || direction == TraversalDirection.down);
|
||||||
final Iterable<FocusNode> filtered;
|
final List<FocusNode> sorted = nodes.where(switch (direction) {
|
||||||
switch (direction) {
|
TraversalDirection.up => (FocusNode node) => node.rect != target && node.rect.center.dy <= target.top,
|
||||||
case TraversalDirection.up:
|
TraversalDirection.down => (FocusNode node) => node.rect != target && node.rect.center.dy >= target.bottom,
|
||||||
filtered = nodes.where((FocusNode node) => node.rect != target && node.rect.center.dy <= target.top);
|
TraversalDirection.left || TraversalDirection.right => throw ArgumentError('Invalid direction $direction'),
|
||||||
case TraversalDirection.down:
|
}).toList();
|
||||||
filtered = nodes.where((FocusNode node) => node.rect != target && node.rect.center.dy >= target.bottom);
|
|
||||||
case TraversalDirection.left:
|
|
||||||
case TraversalDirection.right:
|
|
||||||
throw ArgumentError('Invalid direction $direction');
|
|
||||||
}
|
|
||||||
final List<FocusNode> sorted = filtered.toList();
|
|
||||||
mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) => a.rect.center.dy.compareTo(b.rect.center.dy));
|
mergeSort<FocusNode>(sorted, compare: (FocusNode a, FocusNode b) => a.rect.center.dy.compareTo(b.rect.center.dy));
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user