Upcoming changes to DDC change the async semantics of code produced by the compiler. The changes will bring the semantics more in line with those of dart2js and fix several bugs in the old semantics. However in landing those changes I experienced a test failure in [obscured_animated_image_test](https://github.com/flutter/flutter/blob/master/packages/flutter/test/widgets/obscured_animated_image_test.dart).
Some debugging uncovered that this is due to the use of `SynchronousFuture` in this `FakeCodec`. The old DDC async semantics forced an async gap when that future was [awaited](https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/painting/image_stream.dart#L1064). The new async semantics do not create an async gap here. This changes the render ordering of the widget tree created in the test leading to the test failure.
`Future.value` should be a reasonable substitute here and should achieve what the test was trying to achieve while also preserving the correct render ordering given the new DDC semantics.
This PR rewrites `CupertinoAlertDialog` in a cleaner logic, mostly its layout.
There are two major difficulties to lay out `CupertinoAlertDialog`:
* Laying out the actions section, which switches between a horizontal mode (two buttons in a row) and a vertical mode (several buttons in a column). This PR rewrites it in a special layout widget, `_CupertinoAlertActionSection`.
* Allocating vertical space between the content section and the actions section. This reuses `_PriorityColumn`, which was created for the action sheet.
In a similar fashion to the action sheet, the management and configuration for dividers and background (overscrolls) were rewritten as well.
This PR tries to keep as much original code and behavior as possible since this PR is already very large. As a result, almost no tests are broken. Further improvement will be done in future PRs.
* The test that verifies painting overscrolls is replaced by a golden test, since the original test assumes that the background is painted in one rectangle.
Fixes#150268
The issue was related to the check for selection geometry here: 22a5c6cb0a/packages/flutter/lib/src/widgets/selectable_region.dart (L2469-L2476) . Since `otherList == myList` is a reference check this would fail even if the selection rects inside the list contained in SelectionGeometry where the same causing the selectables inside the selection but outside the selectable containing the tapped position to have their selection cleared, use `listEquals` instead.
Changes:
- Introduced `alignmentOffset` property to `DropdownMenu` to allow adjustment of menu alignment.
- Updated the `MenuAnchor` widget to utilize the new `alignmentOffset` property.
- Default value for `alignmentOffset` is `Offset.zero`, meaning no additional spacing by default.
Motivation:
- This PR closes#151524
- @nate-thegrate, please let me know if I need to make changes in order for this PR to be merged
The motivation behind this change is to provide developers with more control over the spacing between the `MenuAnchor` and `dropdownMenuEntries` in the `DropdownMenu` widget. This enhancement allows for better alignment and customization of the dropdown menu appearance.
| before | after |
| :---: | :---: |
| <img width="372" alt="Screenshot 2024-07-14 at 8 03 14â¯PM" src="https://github.com/user-attachments/assets/4a45b843-7fa4-44fd-843c-c7209c6f57ae"> | <img width="364" alt="Screenshot 2024-07-14 at 8 03 27â¯PM" src="https://github.com/user-attachments/assets/12e8b857-aefb-4aaf-a310-4a002abcbc2f"> |
Initially, it was suggested to use a `SizedBox` to introduce spacing. However, upon further examination of the source code, it was discovered that the `DropdownMenuEntries` are rendered on the screen via an `OverlayPortal`. This necessitated leveraging the existing `alignmentOffset` property within the `MenuAnchor` for a more seamless and effective alignment adjustment.
OverlayPortal attaches its overlaychild's renderobject to overlay directly while keeps its semantics tree under overlayportal.
This become a problem when the `overlaychild` markNeedsSemanticsUpdate that it propagate upward the rendering tree.
This means instead of marking dirty upward to the OverlayPortal, it directly mark Overlay dirty instead and skip `OverlayPortal`.
Currently this does not pose an issue other than unnecessary rebuilds, but it become a problem when I try to optimize the semantics tree compilation https://github.com/flutter/flutter/pull/150394.
After the optimization it won't rebuild semantics node unless it is marked dirty. Since the OverlayPortal widget does not get marked dirty, it won't update the subtree.
Adds an `includeSemantics` property to the Shortcuts widget.
@gspencergoog and I discussed this change to make introducing Shortcuts easier on the MenuAnchor widget. This change should also make testing semantics trees slightly less onerous (assuming this doesn't harm accessibility, that is).
On the point of accessibility, I'm not sure what useful semantic information is exposed by the Shortcuts widget's semantic node, since it's basically just an unfocusable keyboard listener. However, I kept the `includeSemantics` defaulting to true so as to not break semantics tests in the Flutter repo.
Fixes https://github.com/flutter/flutter/issues/152076
Fixes a bug where WillPopScope no longer worked on the home route.
With this PR, Android's predictive back feature will be explicitly disabled when a WillPopScope widget is in the widget tree. To get the same behavior and still support predictive back, use PopScope.
This PR properly resets the drag state when losing the gesture arena or when the recognizer stops tracking the current pointer. The _dragState enum was reset properly, but I had forgotten to also reset the `_start`, this caused an issue when the recognizer won the gesture arena the next time, as it tries to detect a drag given the old `_start` in `acceptGesture`, but the `_dragState` has been reset causing an assertion to trigger.
This pull request implements [enhanced enum](https://dart.dev/language/enums#declaring-enhanced-enums) features for the new `WidgetState` enum, in order to improve the developer experience when creating and using `WidgetStateProperty` objects.
`WidgetState` now has a `.matchesSet()` method:
```dart
// identical to "states.contains(WidgetState.error)"
final bool hasError = WidgetState.error.isSatisfiedBy(states);
```
This addition allows for wide variety of `WidgetStateProperty` objects to be constructed in a simple manner.
<br><br>
```dart
// before
final style = MaterialStateTextStyle.resolveWith((states) {
if (states.contains(MaterialState.error)) {
return TextStyle(color: Colors.red);
} else if (states.contains(MaterialState.focused)) {
return TextStyle(color: Colors.blue);
}
return TextStyle(color: Colors.black);
});
// after
final style = WidgetStateTextStyle.fromMap({
WidgetState.error: TextStyle(color: Colors.red),
WidgetState.focused: TextStyle(color: Colors.blue),
WidgetState.any: TextStyle(color: Colors.black), // "any" is a static const member, not an enum value
});
```
```dart
// before
final color = MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.focused)) {
return Colors.blue;
} else if (!states.contains(MaterialState.disabled)) {
return Colors.black;
}
return null;
});
// after
final color = WidgetStateProperty<Color?>.fromMap({
WidgetState.focused: Colors.blue,
~WidgetState.disabled: Colors.black,
});
```
```dart
// before
const activeStates = [MaterialState.selected, MaterialState.focused, MaterialState.scrolledUnder];
final color = MaterialStateColor.resolveWith((states) {
if (activeStates.any(states.contains)) {
if (states.contains(MaterialState.hovered) {
return Colors.blueAccent;
}
return Colors.blue;
}
return Colors.black;
});
// after
final active = WidgetState.selected | WidgetState.focused | WidgetState.scrolledUnder;
final color = WidgetStateColor.fromMap({
active & WidgetState.hovered: Colors.blueAccent,
active: Colors.blue,
~active: Colors.black,
});
```
<br>
(fixes#146042, and also fixes#143488)
fixes https://github.com/flutter/flutter/issues/146414
---
I saw @abikko submitted a PR https://github.com/flutter/flutter/pull/146630, but it was not completed due to CLA and lack of test cases.
I am willing to complete this PR in combination with @abikko's code (I don't know if this is allowed)
This PR adds contorlAffinity to ListTileTheme so that [CheckboxListTile], [RadioListTile], [SwitchListTile], and [ExpansionTile] can read and use it
For example: If ListTileTheme in Theme sets contorlAffinity, then [CheckboxListTile] can directly use contorlAffinity in ListTileTheme. Of course, if contorlAffinity is also set in [CheckboxListTile], the property in [CheckboxListTile] will be used first.
This PR allows for an optional argument [inverted[ to be passed to the [getOuterPath] method of a CircularNotchedRectangle object in order to invert the notch for situations where it is desired to draw the notch on the bottom of the path. This allows both of the below paths in the below screenshot to be drawn and changes no default behavior.

*List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.*
This add a feature similar to the one discussed in #49973, original feature proposal #151381
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
Brings over the changes from `Switch.adaptive` into `CupertinoSwitch`.
This change adds the following `Switch` parameters to `CupertinoSwitch`:
`inactiveThumbColor,` `activeThumbImage`, `onActiveThumbImageError`, `inactiveThumbImage`, `onInactiveThumbImageError`, `trackOutlineColor`, `trackOutlineWidth`, `thumbIcon`, `mouseCursor`.
The following `Switch` parameters are ignored:
* `activeTrackColor`: because `activeColor` has the same function.
* `inactiveTrackColor`: because `trackColor` has the same function.
* `materialTapTargetSize`: because it is only applicable in `Material`.
* `hoverColor`, `overlayColor`, `splashRadius`: because these parameters configure the radial reaction overlay in `Material`, so are not applicable here.
The following `CupertinoSwitch` parameters which are absent from `Switch.adaptive` are retained:
* `onLabelColor`,
* `offLabelColor`,
* `applyTheme`
`trackColor` and `thumbColor` are of type `WidgetStateProperty` in Material `Switch`, but are currently of type `Color` in `CupertinoSwitch`. For backwards compatibility, both parameters are kept as `Color`s, but can be resolved in different `WidgetState`s using `WidgetStateColor.resolve()`.
This PR does not apply any fidelity updates to `CupertinoSwitch`.
Part of https://github.com/flutter/flutter/issues/149275
Related PRs: https://github.com/flutter/flutter/pull/130425https://github.com/flutter/flutter/pull/148804
Fix: Submenu anchor misaligned with child panel in web (Resolved#151081)
- The issue comes from different in calculating the position of the menu in web and mobile.
- The calculation is currently base on function `getPositionForChild()` inside `_MenuLayout` in `menu_anchor.dart`, which base on the `anchorRect`
- The calculation of `anchorRect` is from `upperLeft` and `bottomRight`
- `upperLeft` is result of `localToGlobal()` function, which take the `point` arguments to be the base line. Right now, `point` is refer to `Offset.zero`, but it should not be Offset.zero since we having `densityAdjustment`, which is different between web and mobile
- Change `point` from `Offset.zero` to `Offset(dx, -dy)` should fix the error. Use `dx` instead of `-dx` since `dx` already be recalculated refer to the above comment on `densityAdjustment`.
Before:

After:

Issue: https://github.com/flutter/flutter/issues/151081
Implement Comparable for the TimeOfDay class as discussed in #139098.
Also implements utility methods as `isBefore`, `isAfter` and `isAtSameTimeAs` for convenience and parity with `DateTime` from the dart sdk.
Multiple fixes related to heading levels:
* Fix heading level absorption. Heading level would get erased when a semantics config is absorbed into another. With this change the highest heading level wins.
* Add `headingLevel` to the diagnostics of `SemanticsNode`.
* Add unit-tests for heading levels.
* Add an a11y use-case for headings.
Improves https://github.com/flutter/flutter/issues/46789 and general accessibility of headings.
## Description
This re-enables the `SemanticsAction.focus` matchers so that they actually do something now instead of ignoring the action.
This was so that we could land the focus action changes without causing breakages in customer tests, and now that customer tests have been updated, we can land this PR turning it on again.
## Related Issues
- Fixes https://github.com/flutter/flutter/issues/149842
## Related PRs
- https://github.com/flutter/flutter/pull/149840
## Tests
- Updates semantics tests to actually look for the focus action.
When a user scroll gesture ends, Material Design floating headers snap into place by animating as far as needed and overlaying the underlying scrollable content. For example Gmail's search header works this way. Other apps handle the snap animation by scrolling content out of the way. Instagram for example.
Added `SliverFloatingHeader.snapMode`, whose value can be `FloatingHeaderSnapMode.overlay` (the default) or `FloatingHeaderSnapMode.scroll`, so that developers can choose the snap animation style they want.
| FloatingHeaderSnapMode.overlay | FloatingHeaderSnapMode.scroll |
| --- | --- |
| <video src="https://github.com/flutter/flutter/assets/1377460/05c82ddf-05a6-4431-9b1e-88b901feea68" /> | <video src="https://github.com/flutter/flutter/assets/1377460/fedc34de-0b55-4f0d-976f-2df1965c90bc" /> |
This PR is making the `CupertinoNavigationBar` and `CupertinoSliverNavigationBar` appear transparent as long as the content is not scrolled under them, so they look like standard iOS apps nav bars.
https://github.com/flutter/flutter/assets/423393/eee2700b-2a91-4577-922c-6163d47cb357https://github.com/flutter/flutter/assets/423393/3847f2b5-0dac-4d5e-aa6f-03c1d2893e30
<details>
<summary>Demo app code</summary>
```dart
import 'package:flutter/cupertino.dart';
/// Flutter code sample for [CupertinoTabScaffold].
void main() => runApp(const TabScaffoldApp());
class TabScaffoldApp extends StatefulWidget {
const TabScaffoldApp({super.key});
@override
State<TabScaffoldApp> createState() => _TabScaffoldAppState();
}
class _TabScaffoldAppState extends State<TabScaffoldApp> {
Brightness _brightness = Brightness.light;
@override
Widget build(BuildContext context) {
return CupertinoApp(
theme: CupertinoThemeData(brightness: _brightness),
home: TabScaffoldExample(
brightness: _brightness, onBrightnessToggle: _toggleBrightness),
);
}
void _toggleBrightness() {
setState(() {
_brightness =
_brightness == Brightness.light ? Brightness.dark : Brightness.light;
});
}
}
class TabScaffoldExample extends StatefulWidget {
const TabScaffoldExample(
{required this.brightness, required this.onBrightnessToggle, super.key});
final VoidCallback onBrightnessToggle;
final Brightness brightness;
@override
State<TabScaffoldExample> createState() => _TabScaffoldExampleState();
}
class _TabScaffoldExampleState extends State<TabScaffoldExample> {
@override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.search_circle_fill),
label: 'Explore',
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.person_fill),
label: 'Profile',
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.settings_solid),
label: 'Settings',
),
],
),
tabBuilder: (BuildContext context, int index) {
return CupertinoTabView(
builder: (BuildContext context) {
return CupertinoPageScaffold(
backgroundColor: index == 3
? CupertinoColors.secondarySystemBackground
.resolveFrom(context)
: null,
child: CustomScrollView(
slivers: [
CupertinoSliverNavigationBar(
largeTitle: Text('Tab $index'),
initiallyTransparent: index != 2,
trailing: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: widget.onBrightnessToggle,
child: Icon(
widget.brightness == Brightness.light
? CupertinoIcons.moon_stars
: CupertinoIcons.sun_max,
),
),
),
SliverSafeArea(
top: false,
sliver: SliverList.list(
children: [
CupertinoButton(
child: const Text('Next page'),
onPressed: () {
Navigator.of(context).push(
CupertinoPageRoute<void>(
builder: (BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Inner page of tab $index'),
),
child: ListView(
children: [
Center(
child: CupertinoButton(
child: const Text('Back'),
onPressed: () {
Navigator.of(context).pop();
},
),
),
if (index == 0) const _LongList(),
const SizedBox(height: 20),
],
),
);
},
),
);
},
),
if (index == 1) const _LongList(),
const SizedBox(height: 20),
],
),
),
],
),
);
},
);
},
);
}
}
class _LongList extends StatelessWidget {
const _LongList();
@override
Widget build(BuildContext context) {
return Column(
children: [
for (int i = 0; i < 50; i++) ...[
CupertinoListTile(
leading: const Icon(CupertinoIcons.book),
title: Text('Bookstore item $i'),
),
],
],
);
}
}
```
</details>
This is the continuation of https://github.com/flutter/flutter/pull/142439.
I tried to keep the simplest API possible, so it's only introducing a new `automaticBackgroundVisibility` boolean parameter.
In the implementation I had to use the `CupertinoPageScaffold` background color to make it look transparent instead of a 0 opacity, because of issues with route transitions.
I used an `InheritedWidget` so the nav bar is always getting the right background color from the parent scaffold, whether it is overridden or not. It would probably be better to make the inherited widget private but we'd need to move all the nav bar code to the same file as the scaffold, so for now I've just hidden it from the export. Let me know if it is okay to do that.
This PR is not dealing with the bottom tab bar, because the same [straightforward approach](dde8ec6dc7) doesn't work here. The problem is that the scroll notification is sent only when the scroll view is created or updated, so it doesn't work if one pushes a screen and navigates back.
Issues:
- #78607
- #60411
A sliver that shows its [child] when the user scrolls forward and hides it when the user scrolls backwards. Similar headers can be found in Google Photos and Facebook.
This sliver is preferable to the general purpose SliverPersistentHeader for its relatively narrow use case because there's no need to create a SliverPersistentHeaderDelegate or to predict the header's size.
https://github.com/flutter/flutter/assets/1377460/82b67dfb-5d38-4adf-9415-fc8527d0eb9f
Feat: Add withOpacity to gradient because sometimes it's required to call withOpacity directly on gradient
Resolves#150501
This adds a `withOpacity` feature to a gradient, given user has given colors this will override opacity to given opacity for them.
`handleEventLoopCallback()` should return `true` rather than `false` when there are tasks in the queue but the highest priority task is not run because of the `schedulingStrategy`. If `false` is returned when the queue still has tasks, the event loop stops, causing existing and new tasks to never be scheduled.
For full context, see https://github.com/flutter/flutter/issues/73766#issuecomment-2202427256.
Fixes#73766 and #82016.
This PR addresses a bug from the previous rewrite of the `CupertinoActionSheet` height allocation algorithm.
The previous approach assigns the content section with a minimal height. As a result, if the actions section is shorter than `_kActionSheetActionsSectionMinHeight`, the remaining space will not be taken by the content section.
As far as I know, this algorithm can not be implemented by simply compositing simple layout widgets, and therefore I created a new widget `_PriorityColumn` that uses a custom layout algorithm. (The resulting code is still shorter (and cleaner) than before the rewrite!)
Some other trivial refactor is also done to clean up the code around parameters of `_ActionSheetMainSheet`.