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.
Updating the docs to reflect the change in https://github.com/flutter/engine/pull/53278.
`Semantics(identifier: '...')` can now be used on web to facilitate testing and DOM lookup when it comes to semantics nodes.
This PR resolves [some problems I was having with `DataTable`](https://github.com/flutter/flutter/issues/151005), based on advice from the style guide:
> ### Answer your own questions straight away
> If you find yourself asking a question about our systems, please place whatever answer you subsequently discover into the documentation in the same place where you first looked for the answer. That way, the documentation will consist of answers to real questions, where people would look to find them.
The `DataTable` documentation now specifies that the widget is based on the Material 2 spec, and it offers a list of useful alternatives.
<br>
Additionally, an item in the "See also" section was updated to use a reliable Go link:
```diff
- /// * <https://material.io/design/components/data-tables.html>
+ /// * <https://material.io/go/design-data-tables>
```
Documentation was migrated as follows:
1. did a RegEx search for `(///.*)MaterialState` and replaced with `$1WidgetState`
2. made sure that `MaterialStateOutlineInputBorder` & `MaterialStateUnderlineInputBorder` were unaffected
3. removed unused imports
<br>
The following files & directories were excluded:
- examples/
- packages/flutter/test/
- material_state.dart
- material_state_mixin.dart
- widget_state.dart
<br>
I believe this should be very straightforward, but I'd also be happy to break the PR in half to make it easier to review.
(related: #151373)
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 relatively elaborate PinnedSliverHeader example which creates an app bar that's similar to the one that appears in the iOS Settings app. In this example the pinned header starts out transparent and the first item in the list serves as the app's "Settings" title. When the title item has been scrolled completely behind the pinned header, the header animates its opacity from 0 to 1 and its (centered) "Settings" title appears. The fact that the header's opacity depends on the height of the title item - which is unknown until the list has been laid out - necessitates monitoring its SliverConstraints.scrollExtent from a scroll NotificationListener.
https://github.com/flutter/flutter/assets/1377460/539e2591-d0d7-4508-8ce8-4b8f587d7648
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.
Adds a new ScrollNotificationEnd example that demonstrates how to trigger an auto-scroll based on an individual sliver's `SliverConstraints` and `SliverGeometry`.
Then new example auto-scrolls one special "aligned item" sliver to the top or bottom of the viewport, whenever it's partially visible (because it overlaps the top or bottom of the viewport). This example differs from the existing ScrollEndNotification example because the layout of the to-be aligned sliver is retrieved from its `RenderSliver` via a
GlobalKey. The new example does not rely on all of the list items having the same extent.
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;
}
}
```