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`.
I really like how patterns can be used for variable assignment and avoiding duplicated logic. (related: #150942)
```dart
// before
final GestureRecognizer? recognizer = info.recognizer;
if (recognizer is TapGestureRecognizer) {
if (recognizer.onTap != null) {
configuration.onTap = recognizer.onTap;
configuration.isLink = true;
}
} else if (recognizer is DoubleTapGestureRecognizer) {
if (recognizer.onDoubleTap != null) {
configuration.onTap = recognizer.onDoubleTap;
configuration.isLink = true;
}
}
// after
switch (info.recognizer) {
case TapGestureRecognizer(:final VoidCallback? onTap):
case DoubleTapGestureRecognizer(onDoubleTap: final VoidCallback? onTap):
if (onTap != null) {
configuration.onTap = onTap;
configuration.isLink = true;
}
}
```
This changes how the `IconThemeData` is passed to the child of `CupertinoButton`.
Previously, it would derive the foreground color from the current theme and create a new `IconThemeData` object.
This causes any `IconThemeData` to be overwritten.
This change uses `IconTheme.of` to get the currently applied icon theme and only overwrites the properties provided by the `CupertinoButton` instead of the whole object.
Fixes#149172.
MenuAnchor for Material 3 is great for contextual menus but there are some minor issues related to accessibility.
This PR aims to close the gap by adding `autofocus` to the menu item button so keyboard navigation is more intuitive. Otherwise, it becomes a mess to navigate through just keyboards.
Partially resolves#139395
## Additional Notes
I should mention, I have not written tests for this due to it's trivial nature. I also lack the experience of writing Flutter tests in general, so if someone feels inclined to take over this PR and add it they're welcome to.
This PR removes the usage of Material widgets from unit tests of `CupertinoAlertDialog`. Other than it being just wrong, it also introduces bad behavior, such as the scroll view can't be overscrolled so that the overscroll behavior can't be tested.
* Since there are no longer M2 or M3 variants of tests, I straight up rewrote the unit tests for "default look" with similar tests as those of `CupertinoActionSheet` ([here](https://github.com/flutter/flutter/blob/master/packages/flutter/test/cupertino/action_sheet_test.dart#L21))
This PR also replaces `showCupertinoModalPopup` with `showCupertinoDialog` in `CupertinoAlertDialog`'s example code. The former should only be used by `CupertinoActionSheet`, which has a different animation from the correct `showCupertinoDialog`.