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 pull request adds a local function `runInTestbed()` to **devfs_web_ddc_modules_test.dart**, which wraps the `testbed.run()` method. Several whitespace adjustments have been made as well.
<br>
It's much easier to read after clicking "hide whitespace".
<br>
Relevant style guidelines:
- Prefer avoiding line breaks after assignment operators.
- If you have a newline after some opening punctuation, match it on the closing punctuation.
- Only use `=>` when everything, including the function declaration, fits on a single line.
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].*
5eca44a1c4 moved some ownership of tests from @christopherfujino to @andrewkolos since Chris was no longer leading engineering efforts for the `flutter` tool. Now that @bkonyi is leading, this PR moves ownership of these test suites to him.
@bkonyi, note that this doesn't imply that you will be responsible for fixing any issues in these tests. This just means that the bot will assign flake issues to you for further triage.
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
Prior to this fix, `_TaskRunner.run` would immediately cleanup the
keep-alive port once the task completed, which would result in the
isolate shutting down as soon as the task result was returned from
`ext.cocoonRunTask` callback in the form of a
`ServiceExtensionResponse`. Since the service extension response is
processed by the service isolate, it was possible for the VM to start
shutting down before the service isolate could send the task result data
back to the task runner.
This change introduces a new service extension,
`ext.cocoonTaskResultReceived`, that the task runner invokes after it
receives the task result from `ext.cocoonRunTask`, notifying the task
process that it can close the keep-alive port and shutdown.
Fixes https://github.com/flutter/flutter/issues/155475
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].*
Reverts: flutter/flutter#154125
Initiated by: bartekpacia
Reason for reverting: broke postsubmit
Original PR Author: bartekpacia
Reviewed By: {reidbaker, gmackall}
This change reverts the following previous change:
Attempt to reland #142008 half a year later.
Benefit: this will be the first plugin in Flutter repo that uses Gradle KTS for Android buildscripts. Once it works fine, we can follow up with migration of more plugins later.
[The previous error message](https://github.com/flutter/flutter/pull/142008#issuecomment-1939558432) was:
```
e: /b/s/w/ir/cache/gradle/caches/jars-8/42139b5be0c79e133a7b5c5c5d5bf731/gradle-7.3.1.jar!/com/android/build/gradle/LibraryExtension.class: Class 'com/android/build/gradle/LibraryExtension' was compiled with an incompatible version of Kotlin. The binary version of its bytecode is unknown, expected version is 1.0.3
e: /b/s/w/ir/cache/gradle/caches/jars-8/043c0d54e2c1bb39208ec4477607cdf5/gradle-api-7.3.1.jar!/com/android/build/api/dsl/LibraryVariantDimension.class: Class 'com/android/build/api/dsl/LibraryVariantDimension' was compiled with an incompatible version of Kotlin. The binary version of its bytecode is unknown, expected version is 1.0.3
FAILURE: Build failed with an exception.
* Where:
Build file '/b/s/w/ir/x/w/flutter/packages/integration_test/android/build.gradle.kts' line: 36
* What went wrong:
com.android.build.gradle.LibraryExtension.setNamespace(Ljava/lang/String;)V
```
The `integration_test` plugin now puts `com.android.tools.build:gradle:8.1.0` on its classpath since https://github.com/flutter/flutter/issues/153795.
This makes me take an optimistic bet that it won't kill the autoroller now 🤞