Following https://github.com/flutter/flutter/pull/151914, this PR is to normalize `ThemeData.cardTheme`; change the `CardTheme cardTheme` property to `CardThemeData cardTheme` in `ThemeData`. In `ThemeData()` and `ThemeData.copyWith()`, the `cardTheme` parameter type is changed to `Object?` to accept both `CardTheme` and `CardThemeData` so that we won't cause immediate breaking change and make sure rolling is smooth. Once all component themes are normalized, these `Object?` types should be changed to `xxxThemeData`.
There's no way to create a dart fix because we can't add a "@deprecated" label for `CardTheme` because `CardTheme` is a new InheritedWidget subclass now.
Addresses the "theme normalization" sub project within https://github.com/flutter/flutter/issues/91772
This PR adjusts the implementation of handling navigational shortcuts (i.e. arrow keys) on `MenuAnchor` and `DropdownMenu`.
## Motivation
The direct outcome of this PR is to allow keyboard to enter submenus on Web: When the focus is on a `MenuAnchor` while the menu is open, pressing arrow keys should move the focus to the menu item.
* Before the PR, this works for all platforms but Web, a problem described in https://github.com/flutter/flutter/issues/119532#issuecomment-2274705565.
It is caused by the fact that `MenuAnchor` does not wrap itself with a `Shortcuts`, and therefore key events when the focus is on a `MenuAnchor` has been working only because the event falls back to the `Shortcuts` widget defined by `WidgetsApp`, whose default value happens to satisfy `MenuAnchor`'s needs - except on Web where arrow keys are defined to scroll instead of traverse.
Instead of defining this problem as "just a patch for Web", I think it's better to define it as a problem of all platforms: `MenuAnchor`'s shortcuts should be independent of `WidgetsApp.shortcuts`. Because even if `WidgetsApp.shortcuts` is redefined as something else, people should probably still expect arrow keys to work on `MenuAnchor`.
Therefore this PR makes `MenuAnchor` produce a `Shortcuts` by itself.
### Dropdown menu
The fix above breaks `DropdownMenu`. `DropdownMenu` uses `MenuAnchor`, while defining its own shortcuts because, when filter is enabled:
* The left and right arrow keys need to move the text carets instead
* The up and down arrow keys need to "fake" directional navigation - the focus needs to stay on the text field, while some menu item is highlighted as if it is focused.
Before the PR, `DropdownMenu` defines these shortcuts out of `MenuAnchor`. In order for the `DropdownMenu`'s shortcuts to take priority, these shortcuts are moved to between `MenuAnchor` and the `Textfield`.
A test is added to verify that the left/right keys move text carets.
Below are psuedo-widget-trees after the PR:
```
MenuAnchor
|- Shortcuts(arrows->DirectionalFocusIntent)
|- MenuAnchor.child
|- menu
DropdownMenu
|- Actions(DirectionalFocusIntent->_dropdownMenuNavigation)
|- MenuAnchor
|- Shortcuts(arrows->DirectionalFocusIntent)
|- Shortcuts(leftright->ExtendSelectionByCharacterIntent, updown->_dropdownMenuArrowIntent)
| |- TextField
| |- EditableText
| |- Actions(DirectionalFocusIntent->DirectionalFocusAction.forTextField)
|- menu
```
## Known issues
After this PR, traversing the menu still have quite a few problems, which are left for other PRs.
> ### Write Test, Find Bug
>
> When you fix a bug, first write a test that fails, then fix the bug and verify the test passes.
<br>
When `Theme.of(context)` is called in a `build()` method, the widget is rebuilt each frame during an `AnimatedTheme` transition.
I wanted to create a way for `RenderObject`s to be updated directly, so I wrote a test:
```dart
testWidgets('InheritedWidgets can trigger RenderObject updates', (WidgetTester tester) async {
// ...
});
```
â¦and it passed.
<br><br>
As it turns out, no change is needed at all!
This PR resolves#155852 by adding the "InheritedWidgets can trigger RenderObject updates" test, to ensure that this awesome capability doesn't break in the future.
This pull request aims to improve code readability, based on feedback gathered in a recent design doc.
<br>
There are two factors that hugely impact how easy it is to understand a piece of code: **verbosity** and **complexity**.
Reducing **verbosity** is important, because boilerplate makes a project more difficult to navigate. It also has a tendency to make one's eyes gloss over, and subtle typos/bugs become more likely to slip through.
Reducing **complexity** makes the code more accessible to more people. This is especially important for open-source projects like Flutter, where the code is read by those who make contributions, as well as others who read through source code as they debug their own projects.
<hr>
<br>
The following examples show how pattern-matching might affect these two factors:
<details> <summary><h3>Example 1 (GOOD)</h3> [click to expand]</summary>
```dart
if (ancestor case InheritedElement(:final InheritedTheme widget)) {
themes.add(widget);
}
```
Without using patterns, this might expand to
```dart
if (ancestor is InheritedElement) {
final InheritedWidget widget = ancestor.widget;
if (widget is InheritedTheme) {
themes.add(widget);
}
}
```
Had `ancestor` been a non-local variable, it would need to be "converted" as well:
```dart
final Element ancestor = this.ancestor;
if (ancestor is InheritedElement) {
final InheritedWidget inheritedWidget = ancestor.widget;
if (widget is InheritedTheme) {
themes.add(theme);
}
}
```
</details>
<details> <summary><h3>Example 2 (BAD) </h3> [click to expand]</summary>
```dart
if (widget case PreferredSizeWidget(preferredSize: Size(:final double height))) {
return height;
}
```
Assuming `widget` is a non-local variable, this would expand to:
```dart
final Widget widget = this.widget;
if (widget is PreferredSizeWidget) {
return widget.preferredSize.height;
}
```
<br>
</details>
In both of the examples above, an `if-case` statement simultaneously verifies that an object meets the specified criteria and performs a variable assignment accordingly.
But there are some differences: Example 2 uses a more deeply-nested pattern than Example 1 but makes fewer useful checks.
**Example 1:**
- checks that `ancestor` is an `InheritedElement`
- checks that the inherited element's `widget` is an `InheritedTheme`
**Example 2:**
- checks that `widget` is a `PreferredSizeWidget`
(every `PreferredSizeWidget` has a `size` field, and every `Size` has a `height` field)
<br>
<hr>
I feel hesitant to try presenting a set of cut-and-dry rules as to which scenarios should/shouldn't use pattern-matching, since there are an abundance of different types of patterns, and an abundance of different places where they might be used.
But hopefully the conversations we've had recently will help us converge toward a common intuition of how pattern-matching can best be utilized for improved readability.
<br><br>
- resolves https://github.com/flutter/flutter/issues/152313
- Design Doc: [flutter.dev/go/dart-patterns](https://flutter.dev/go/dart-patterns)
Add `autocorrect` and `enableSuggestions` to `SearchDelegate`, so that autocompletion can be disabled in search.
*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.*
* https://github.com/flutter/flutter/issues/98241
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
Following https://github.com/flutter/flutter/pull/153982, this PR is to normalize `ThemeData.dialogTheme`; change the `DialogTheme dialogTheme` property to `DialogThemeData dialogTheme` in ThemeData. In `ThemeData()` and `ThemeData.copyWith()`, the dialogTheme parameter type is changed to `Object?` to accept both `DialogTheme` and `DialogThemeData` so that we won't cause immediate breaking change and make sure rolling is smooth. Once all component themes are normalized, these `Object?` types should be changed to `xxxThemeData`.
There's no way to create a dart fix because we can't add a "@deprecated" label for `DialogTheme`; `DialogTheme` is a new `InheritedWidget` subclass now.
Addresses the "theme normalization" sub project within https://github.com/flutter/flutter/issues/91772
Fixes#33799
Allows for a route to inform the route below it in the navigation stack how to animate when the topmost route enters are leaves the stack.
It does this by making a `DelegatedTransition` available for the previous route to look up and use. If available, the route lower in the stack will wrap it's transition builders with that delegated transition and use it instead of it's default secondary transition.
This is what the sample code in this PR shows an app that is able to use both a Material zoom transition and a Cupertino slide transition in one app. It also includes a custom vertical transition. Every page animates off the screen in a way to match up with the incoming page's transition. When popped, the correct transitions play in reverse.
https://github.com/user-attachments/assets/1fc910fa-8cde-4e05-898e-daad8ff4a697
The below video shows this logic making a pseudo iOS styled sheet transition.
https://github.com/flutter/flutter/assets/58190796/207163d8-d87f-48b1-aad9-7e770d1d96c5
All existing page transitions in Flutter will be overwritten by the incoming route if a `delegatedTransition` is provided. This can be opted out of through `canTransitionTo` for a new route widget. Of Flutter's existing page transitions, this PR only adds a `DelegatedTransition` for the Zoom and Cupertino transitions. The other transitions possible in Material will get delegated transitions in a later PR.
This PR fixes the `ReorderableList` in `flutter/widgets.dart` not passing the item extent builder to the underlying SliverReorderableList. I double checked and the material equivalent is working as intended.
Fixes https://github.com/flutter/flutter/issues/155936
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
## Description
This PR makes DropdownMenu rematching the initialSelection when the entries are updated.
If the new entries contains one entry whose value matches `initialSelection` this entry's label is used to initialize the inner text field, if no entries matches `initialSelection` the text field is emptied.
## Related Issue
Fixes [DropdownMenu.didUpdateWidget should re-match initialSelection when dropdownMenuEntries have changed](https://github.com/flutter/flutter/issues/155660).
## Tests
Adds 3 tests.
This PR fixes#154701 by adding a new parameter to the CarouselView widget that allows developers to control which parts of the carousel are clickable. Currently, an InkWell covers the entire carousel, preventing child widgets from being clickable even when children widget have their clickable widgets.
The new `enableSplash` parameter allows developers to disable this default behavior of `InkWell` without breaking any existing code. If `enableSplash` is `false`, the `onTap` of the `CarouselView` will be disabled. And developer can define their own click behavior likes animation, the clickable widget and so on.
Fixes#133637
This change updates the `_SelectableFragment.boundingBoxes` logic to consider the max line height. Previously we were using boxes that were tightly bound around each glyph, so you would have to click within the bounds of the glyph for double tap to select word to work. This is different than `SelectableText` which considers the max line height, as well as the native web behavior that also considers the max line height.
## Web
https://github.com/user-attachments/assets/4ce8c0ca-ec6f-4969-88b1-baa356be8278
## Flutter SelectableText
https://github.com/user-attachments/assets/54c22ad3-75d7-475b-856b-e9b2dbe09d54
## Flutter Text widget under SelectionArea
https://github.com/user-attachments/assets/27db0e2b-1d19-43cc-8ab3-16050e3a5bc7
After this change, Flutter's Text widget under a SelectionArea now matches the SelectableText and native web behavior.
This change also:
* Invalidates the cached bounding boxes when the paragraph layout changes.
* Updates `textOffsetToPosition` to consider `preferredLineHeight`. In cases when the text wraps, it was sometimes inaccurate.
Add `magnificationScale `to `CupertinoMagnifier` for Zoom Effect
The CupertinoMagnifier widget is not displaying the expected zoom effect.
This issue arises because the widget internally wraps the RawMagnifier, which has its magnificationScale attribute set to the default value of 1. As a result, no magnification is applied, and the zoom effect is absent.
Fixes#155275
## Description
This PR changes the `MenuAnchor` implementation in order to always show the menu on the root overlay. Doing so menus can't be hidden by other widgets especially when using go_router.
See [[go_router] DropdownMenu behind NavigationBar](https://github.com/flutter/flutter/issues/155034) where the DropdownMenu menu was displayed behind the navigation bar.
I did not make this configurable for the moment to avoid introducing a new parameter until there is a clear use case for it.
## Related Issue
Fixes [[go_router] DropdownMenu behind NavigationBar](https://github.com/flutter/flutter/issues/155034).
## Tests
Adds 1 test.
This PR tweaks `wrapWithDefaultView` (used by `runApp`) to raise a StateError with a legible error message when the `platformDispatcher.implicitView` is missing (for example, when enabling multi-view embedding on the web), instead of crashing with an unexpected `nullCheck` a few lines below.
* Before:
<img width="619" alt="Screenshot 2024-09-25 at 7 33 47â¯PM" src="https://github.com/user-attachments/assets/4897dd3c-bdd0-4217-9f23-7eee9fab4999">
* After:
<img width="613" alt="Screenshot 2024-09-26 at 5 01 49â¯PM" src="https://github.com/user-attachments/assets/3febb91d-a8c3-41b6-bf34-c2c8743b637c">
## Issues
* Fixes https://github.com/flutter/flutter/issues/153198
## Tests
Added a test to ensure the assertion is thrown when the `implicitView` is missing. Had to hack a little because I couldn't find any clean way of overriding the `implicitView`. The problem is that the flutter_test bindings [use `runApp` internally](8925e1ffdf/packages/flutter_test/lib/src/binding.dart (L1020)) a couple of times, so I can only disable the implicitView inside the test body (and must re-enable it before returning). Not sure if it's the best way, but it seems to do the trick for this simple test case!
This change updates the behavior of `SelectableText`, to clear its selection when it loses focus and the application is currently running. This fixes the behavior where you may have multiple active highlights if you have `SelectableText` along with other "selectable" widgets such as `TextField`, or `Text` widgets under a `SelectionArea`.
If the application is in the background, for example when another window is focused, the selection should be retained so when a user returns to the application it is still there.
This change also updates the behavior of selection on macOS, single tap up, previously it was selecting the word edge closest to the tapped position, the correct behavior on native is to select the precise position. This was causing `onSelectionChanged` to be called twice, once for tap down (sets the precise tapped position, handled by logic in `TextSelectionGestureDetector`), and a second time for single tap up (moves the cursor to closest word edge, handled by logic in `_SelectableTextSelectionGestureDetectorBuilder`). This type of selection inconsistency is related to this issue https://github.com/flutter/flutter/issues/129726, I plan to look into this further in a separate PR.
Fixes#117573Fixes#103725
Reverts: flutter/flutter#155476
Initiated by: eyebrowsoffire
Reason for reverting: The newly added tests are failing in postsubmit. See https://ci.chromium.org/ui/p/flutter/builders/prod/Windows%20framework_tests_libraries/19062/overview
Original PR Author: QuncCccccc
Reviewed By: {TahaTesser}
This change reverts the following previous change:
This PR is to make preparations to make `TabBarTheme` conform to Flutter's conventions for component themes:
* Added a `TabBarThemeData` class which defines overrides for the defaults for `TabBar` properties.
* Added 2 `TabBarTheme` constructor parameters: `TabBarThemeData? data` and `Widget? child`. This is now the preferred way to configure a `TabBarTheme`:
```
TabBarTheme(
data: TabBarThemeData(labelColor: xxx, indicatorColor: xxx, ...),
child: TabBar(...)
)
```
These two properties are made nullable to not break existing apps which has customized `ThemeData.tabBarTheme`.
* Changed the type of component theme defaults from `TabBarTheme` to `TabBarThemeData`.
TODO:
* Fix internal failures.
* Change the type of `ThemeData.tabBarTheme` from `TabBarTheme` to `TabBarThemeData`. This may cause breaking changes, a migration guide will be created.
Addresses the "theme normalization" sub project within https://github.com/flutter/flutter/issues/91772
This PR is to make preparations to make `TabBarTheme` conform to Flutter's conventions for component themes:
* Added a `TabBarThemeData` class which defines overrides for the defaults for `TabBar` properties.
* Added 2 `TabBarTheme` constructor parameters: `TabBarThemeData? data` and `Widget? child`. This is now the preferred way to configure a `TabBarTheme`:
```
TabBarTheme(
data: TabBarThemeData(labelColor: xxx, indicatorColor: xxx, ...),
child: TabBar(...)
)
```
These two properties are made nullable to not break existing apps which has customized `ThemeData.tabBarTheme`.
* Changed the type of component theme defaults from `TabBarTheme` to `TabBarThemeData`.
TODO:
* Fix internal failures.
* Change the type of `ThemeData.tabBarTheme` from `TabBarTheme` to `TabBarThemeData`. This may cause breaking changes, a migration guide will be created.
Addresses the "theme normalization" sub project within https://github.com/flutter/flutter/issues/91772
fixes https://github.com/flutter/flutter/issues/155180
New behaviour: SearchAnchor now closes the menu when itself is disposed while the menu is still open. This is the behaviour of `MenuAnchor`/`OverlayPortal`.
fixes#154515, #150048 and other similar issues where user non-draggable scrolls (mouse wheel, two-fingers) should behave same as draggable ones.
In this PR, scrollUpdateNotification.dragDetails check is removed and it has a supporting test which simulates a scroll which does not produce a drag.
This PR adds "sliding tap" to `CupertinoAlertDialog` and fixes https://github.com/flutter/flutter/issues/19786.
Much of the needed infrastructure has been implemented in https://github.com/flutter/flutter/pull/150219, but this time with a new challenge to support disabled buttons, i.e. the button should not show tap highlight when pressed (https://github.com/flutter/flutter/issues/107371).
* Why? Because whether a button is disabled is assigned to `CupertinoDialogAction`, while the background is rendered by a private class that wraps the action widget and built by the dialog body. We need a way to pass the boolean "enabled" from the child to the parent when the action is pressed. After much experimentation, I think the best way is to propagate this boolean using the custom gesture callback.
* An alternative way is to make the wrapper widget use an inherited widget, which allows the child `CupertinoDialogAction` to place a `ValueGetter<bool> getEnabled` to the parent as soon as it's mounted. However, this is pretty ugly...
This PR also fixes https://github.com/flutter/flutter/issues/107371, i.e. disabled `CupertinoDialogAction` no longer triggers the pressing highlight. However, while legacy buttons (custom button classes that are implemented by `GestureDetector.onTap`) still functions (their `onPressed` continues to work), disabled legacy buttons will still show pressing highlight, and there's no plan (actually, no way) to fix it.
All tests related to sliding taps in `CupertinoActionSheet` has been copied to `CupertinoAlertDialog`, with additional tests for disabled buttons.
Fix: Flicker when no update in index of dragged item
Resolves#150843
This PR ensures that even if we move dragged item anywhere in list and comeback to initial position, we smoothly adjust to that position.
## Description
This PR fixes the default selection on desktop when a text field is gaining focus.
Before this PR, when a text field is focused, the selection was collapsed at the end for all platforms except on Web where the entire content was selected.
After this PR, when a text field is focused, the entire content is selected on desktop and Web, and the selection is collapsed at the end on mobile platforms.
The implementation extends the work done in https://github.com/flutter/flutter/pull/119583 which implemented this feature for web.
## Related Issue
Fixes https://github.com/flutter/flutter/issues/150339.
## Tests
Updates 1 test.
Fixes 2 tests.
Fixes https://github.com/flutter/flutter/issues/154060
The error message doesn't make sense to me since one can call `setState` during the idle phase, and I'm not sure what this is guarding against without the right error message.
In the case of #154060 the layout builder was never laid out:
```
ââchild 1: _RenderLayoutBuilder#7c319 NEEDS-LAYOUT NEEDS-PAINT
â creator: LayoutBuilder â _BodyBuilder â MediaQuery â
â LayoutId-[<_ScaffoldSlot.body>] â CustomMultiChildLayout â
â _ActionsScope â Actions â AnimatedBuilder â DefaultTextStyle â
â AnimatedDefaultTextStyle â _InkFeatures-[GlobalKey#1f6eb ink
â renderer] â NotificationListener<LayoutChangedNotification> â â¯
â parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.body
â constraints: MISSING
â size: MISSING
```
So https://github.com/flutter/flutter/pull/154681 doesn't really fix#154060 since the layout callback cannot be run without a set of valid constraints.
Before the `BuildScope` change all `_inDirtyList` flags were unset after the `BuildOwner` finishes rebuilding the widget tree, so `LayoutBuilder._inDirtyLst` is always set to false after a frame even for layout builders that were never laid out.
With the `BuildScope` change, `LayoutBuilder` has its own `BuildScope` which is only flushed after LayoutBuilder gets its constraints.
Fixes https://github.com/flutter/flutter/issues/154156
Some iOS keyboard implementations change the selection in the text field if dismissed with active composing regions. The framework should not call `requestKeyboard` in such cases since that would bring up the keyboard again.
In general the `TextInput.show` call is not needed for selection only changes. For working around https://github.com/flutter/flutter/issues/68571 the show call is needed only if we restarted the input on Android (and we don't restart on selection-only changes any way).
DropdownMenu throws RangeError when both filter and search are enabled because when we search for elements, we have some highlighted element, but if there is no element to highlight it tries to access 0th element is the filtered entries, but entries are empty.
Fixes#151878
This PR add the ability to change buttons of 'SegmentedButton' directionality (In the vertical and horizontal axis) to be 'vertical' or 'horizontal' instead of just horizontally position by adding "direction" argument.
`direction: Axis.horizontal` :

`direction: Axis.vertical` :

Notice: in this example i used:
`style: ButtonStyle( shape: MaterialStateProperty.all<RoundedRectangleBorder>( const RoundedRectangleBorder( borderRadius: BorderRadius.zero, ), ), ) `
To change the Radius of `SegmentedButton`, and the default shape will be like:

I keep it as it is right now, cause its not the main purpose of this BR.
*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.*
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
Fixes: #150416
This migrates the last failing test for https://github.com/flutter/engine/pull/54981. In order to effectively resolve that test I had to make `equalsIgnoringHashCodes` more usable by printing out the line that differs instead of just a huge blob of "expected" vs "actual.
## example
Here's the output after the change.
### test
```
test('equalsIgnoringHashCodes - wrong line', () {
expect(
'1\n2\n3\n4\n5\n6\n7\n8\n9\n10',
equalsIgnoringHashCodes('1\n2\n3\n4\n5\n6\na\n8\n9\n10'),
);
});
```
### output
```
Expected: normalized value matches
'1\n'
'2\n'
'3\n'
'4\n'
'5\n'
'6\n'
'a\n'
'8\n'
'9\n'
'10'
Actual: '1\n'
'2\n'
'3\n'
'4\n'
'5\n'
'6\n'
'7\n'
'8\n'
'9\n'
'10'
Which: Lines 7 differed, expected:
'a'
but got
'7'
```
Fixes#153889 an issue where nodes were being removed incorrectly when using `AnimationStyle.noAnimation `or the animation duration was zero seconds, which previously caused the application to freeze due to hidden state updates. By skipping the animation and updating active nodes immediately in these cases, we avoid these issues and ensure smooth and accurate management of node states.
SearchBar and SearchAnchor can now control their context menu. They both received new contextMenuBuilder parameters. See the docs for EditableText.contextMenuBuilder for how to use this, including how to use the native context menu on iOS and to control the browser's context menu on web.