## What's new?
- Add `PopupWindowController`, `PopupWindowControllerDelegate`, and
`PopupWindow`
- Implement reference logic for popup windows in the test bindings
- Add tests for the popup windows API
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
This PR adds the framework support for a new iOS-style blur. The new
style, which I call "bounded blur", works by adding parameters to the
blur filter that specify the bounds for the region that the filter
sources pixels from.
As discussed in design doc
[flutter.dev/go/ios-style-blur-support](http://flutter.dev/go/ios-style-blur-support),
it's impossible to pass layout information to filters with the current
`ImageFilter` design. Therefore this PR creates a new class
`ImageFilterConfig`.
This PR also applies bounded blur to `CupertinoPopupSurface`. The
following images show the different looks of a dialog in front of
background with abrupt color changes just outside of the border. Notice
how the abrupt color changes no longer bleed in.
<img width="639" height="411" alt="image"
src="https://github.com/user-attachments/assets/4ceb9620-1056-45c3-b5fa-2ed16d90aace"
/>
<img width="639" height="411" alt="image"
src="https://github.com/user-attachments/assets/abe564f7-ea60-4d07-ad58-063c0e3794a5"
/>
This feature continues to matter for iOS 26, since the liquid glass
design also heavily features blurring.
### API changes
* `BackdropFilter`: Add `filterConfig`
* `RenderBackdropFilter`: Add `filterConfig`. Deprecate `filter`.
* `ImageFilter`: Add `debugShortDescription` (previously private
property `_shortDescription`)
### Demo
The following video compares the effect of a bounded blur and an
unbounded blur.
https://github.com/user-attachments/assets/f715db44-c0a0-4ac8-a163-6b859665b032
<details>
<summary>
Demo source
</summary>
```
// Add to pubspec.yaml:
//
// assets:
// - assets/kalimba.jpg
//
// and download the image from
// ec6f550237/engine/src/flutter/impeller/fixtures/kalimba.jpg
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: BlurEditorApp()));
class ControlPoint extends StatefulWidget {
const ControlPoint({
super.key,
required this.position,
required this.onPanUpdate,
this.radius = 20.0,
});
final Offset position;
final GestureDragUpdateCallback onPanUpdate;
final double radius;
@override
ControlPointState createState() => ControlPointState();
}
class ControlPointState extends State<ControlPoint> {
bool isHovering = false;
@override
Widget build(BuildContext context) {
return Positioned(
left: widget.position.dx - widget.radius,
top: widget.position.dy - widget.radius,
child: MouseRegion(
onEnter: (_) { setState((){ isHovering = true; }); },
onExit: (_) { setState((){ isHovering = false; }); },
cursor: SystemMouseCursors.move,
child: GestureDetector(
onPanUpdate: widget.onPanUpdate,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: widget.radius * 2,
height: widget.radius * 2,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isHovering
? Colors.white.withValues(alpha: 0.8)
: Colors.white.withValues(alpha: 0.4),
border: Border.all(color: Colors.white, width: 2),
boxShadow: [
if (isHovering)
BoxShadow(
color: Colors.white.withValues(alpha: 0.5),
blurRadius: 10,
spreadRadius: 2,
)
],
),
child: const Icon(Icons.drag_indicator, size: 16, color: Colors.black54),
),
),
),
);
}
}
class BlurPanel extends StatelessWidget {
const BlurPanel({super.key, required this.blurRect, required this.bounded});
final Rect blurRect;
final bool bounded;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: Stack(
children: [
Positioned.fill(
child: Image.asset(
'assets/kalimba.jpg',
fit: BoxFit.cover,
),
),
Positioned.fromRect(
rect: blurRect,
child: ClipRect(
child: BackdropFilter(
filterConfig: ImageFilterConfig.blur(
sigmaX: 10, sigmaY: 10, bounded: bounded),
child: Container(),
)),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
bounded ? 'Bounded Blur' : 'Unbounded Blur',
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
],
),
);
}
}
class BlurEditorApp extends StatefulWidget {
const BlurEditorApp({super.key});
@override
State<BlurEditorApp> createState() => _BlurEditorAppState();
}
class _BlurEditorAppState extends State<BlurEditorApp> {
Offset p1 = const Offset(100, 100);
Offset p2 = const Offset(300, 300);
@override
Widget build(BuildContext context) {
final blurRect = Rect.fromPoints(p1, p2);
return Scaffold(
body: Stack(
children: [
Positioned.fill(
child: Row(
children: [
Expanded(
child: BlurPanel(blurRect: blurRect, bounded: true),
),
Expanded(
child: BlurPanel(blurRect: blurRect, bounded: false),
),
],
),
),
ControlPoint(position: p1, onPanUpdate: (details) { setState(() => p1 = details.globalPosition); }),
ControlPoint(position: p2, onPanUpdate: (details) { setState(() => p2 = details.globalPosition); }),
],
),
);
}
}
```
</details>
## Pre-launch Checklist
- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.
If you need help, consider asking for advice on the #hackers-new channel
on [Discord].
**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This PR adds `SingleActivator` mappings for IBM CUA style clipboard
accessors, with which Shift-Delete, Ctrl-Insert and Shift-Insert are
equivalent to ^X ^C ^V. These mappings are natively supported on Windows
and Linux (but not OS X).
~Not sure what to do about:~
- ~Documentation: Are ^X ^C ^V already documented?~
- ~Tests: Are there existing tests for ^X ^C ^V already? Is it possible
to mock out the clipboard so that a test of this functionality doesn't
hit the actual system clipboard?~
- ~OS X: Is it a problem that, with this change, Flutter will accept
these additional shortcuts even though they aren't a part of the
platform paradigm?~
UPDATE:
I'm not aware of existing documentation of clipboard shortcuts.
I have added tests, both of the existing ^X ^C ^V and of the IBM CUA
style mappings added by this PR, and in the current iteration the
changes do not add IBM CUA style mappings on OS X.
Fixes: #178483
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
---------
Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com>
## Changes
* Exclude semantics for disabled dates directly in CupertinoDatePicker
fixes: #178713
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
## Description
This PR adds the `SnackBarTheme` subclass of InheritedTheme. Similarly
to other theme classes.
Despite missing, this class was mentioned in
[flutter.dev/go/material-theme-system-updates](http://flutter.dev/go/material-theme-system-updates):
"SnackBarTheme and SnackBarThemeData are conformant.. "
## Related Issue
Fixes [Missing
SnackBarTheme](https://github.com/flutter/flutter/issues/180000)
## Tests
Adds 2 tests.
## Description
This PR adds the `FloatingActionButtonTheme` subclass of InheritedTheme.
Similarly to other theme classes.
This missing theme class was mentioned in
[flutter.dev/go/material-theme-system-updates](http://flutter.dev/go/material-theme-system-updates):
"FloatingActionButtonThemeData is conformant but there’s no
FloatingActionButtonTheme class. "
## Related Issue
Fixes [Missing
FloatingActionButtonTheme](https://github.com/flutter/flutter/issues/179735)
## Tests
Adds 2 tests.
Feat: Add top gap for cupertino sheet
fixes: #169465
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
<!-- start_original_pr_link -->
Reverts: flutter/flutter#175679
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: jtmcdole
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: Linux linux_unopt is now timing out in postsubmit
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: bkonyi
<!-- end_original_pr_author -->
<!-- start_reviewers -->
Reviewed By: {srawlins}
<!-- end_reviewers -->
<!-- start_revert_body -->
This change reverts the following previous change:
The `flutter_analyzer_plugin` implements rules previously enforced by
the `dev/bots/analyze.dart` check run on the CI, allowing for earlier
detection of custom lint violations before a change is uploaded for
review.
Currently, the plugin implements the following rules:
- avoid_future_catch_error
- no_double_clamp
- no_stopwatches
- protect_public_state_subtypes
- render_box_intrinsics
Towards https://github.com/flutter/flutter/issues/175276
<!-- end_revert_body -->
Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com>
The `flutter_analyzer_plugin` implements rules previously enforced by
the `dev/bots/analyze.dart` check run on the CI, allowing for earlier
detection of custom lint violations before a change is uploaded for
review.
Currently, the plugin implements the following rules:
- avoid_future_catch_error
- no_double_clamp
- no_stopwatches
- protect_public_state_subtypes
- render_box_intrinsics
Towards https://github.com/flutter/flutter/issues/175276
This is a reland of #178817, which was reverted in #179100 due to test
failures.
The original PR introduced `hitTestBehavior` to the semantics framework
but incorrectly applied `opaque` behavior to `ModalRoute`, which blocked
platform views from receiving pointer events.
Instead of making the entire modal opaque, we:
1. Keep `ModalRoute` without explicit `hitTestBehavior` (defaults to
`defer`)
2. Make only the dialog/sheet content opaque (blocks clicks to barrier)
3. Platform views remain clickable because they're outside the opaque
content boundary
Fixes#149001
Original PR: #177570
Revert: #178744
This PR adds a new `AutovalidateMode` value:
`onUserInteractionIfError`.
This mode allows `Form` and `FormField` widgets to auto-validate **only
when a field already has an error and the user interacts with it
again**.
### Why
- Current modes (`disabled`, `always`, `onUserInteraction`, `onUnfocus`)
do not cover the case where developers want validation **only when
correcting an error**.
- This improves UX by reducing unnecessary validation calls while still
ensuring errors disappear as soon as the user fixes them.
### How
- Added `onUserInteractionIfError` to `AutovalidateMode`.
- Updated Dartdoc with detailed description and example snippet.
- Added new unit tests to validate behavior.
- Verified no regressions in other modes (`always`, `onUnfocus`,
`onUserInteraction`).
### Example
```dart
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteractionIfError,
validator: (value) => value!.isEmpty ? 'Required field' : null,
)
````
---
## Related Issues
Fixes #\<INSERT\_RELATED\_ISSUE\_NUMBER\_IF\_ANY>
---
## Tests
* Added widget tests to confirm that:
* No validation occurs until a field has an error.
* Once an error exists, validation runs automatically on user
interaction.
* Resetting the form clears errors correctly.
* Regression tests ensure that `always`, `onUserInteraction`, and
`onUnfocus` modes still behave correctly.
---
## Pre-launch / Reviewer Checklist
* [x] I have read the [[Contributor
Guide](https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md)](https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md)
* [x] I have read the \[Tree Hygiene] wiki page and followed its
guidance
* [x] I have read and followed the \[Flutter Style Guide]
* [x] I signed the \[CLA]
* [x] I added a new enum value with clear Dartdoc
(`onUserInteractionIfError`)
* [x] I added example code in the Dartdoc
* [x] I added new widget/unit tests for the new mode
* [x] All existing and new tests pass
* [x] I ran `flutter analyze` and fixed all issues
* [x] No breaking changes introduced (or marked accordingly)
---
## Breaking Change
* [x] Yes
* [x] No
---
## Screenshots / Demo (if applicable)
*(N/A — logic-only change)*
---
## Reviewer Notes
* The new mode reduces unnecessary validation until the user corrects an
error.
* All tests confirm correct behavior and no regressions in existing
modes.
---------
Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com>
This is my attempt to handle
https://github.com/flutter/flutter/issues/6537 for the
CupertinoListSection widget.
Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com>
Co-authored-by: Victor Sanni <victorsanniay@gmail.com>
This is my attempt to handle
https://github.com/flutter/flutter/issues/6537 for the
CupertinoFormSection widget.
Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com>
Co-authored-by: Victor Sanni <victorsanniay@gmail.com>
This is my attempt to handle
https://github.com/flutter/flutter/issues/6537 for the
CupertinoMagnifier widget.
Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com>
Co-authored-by: Victor Sanni <victorsanniay@gmail.com>
This is my attempt to handle
https://github.com/flutter/flutter/issues/6537 for the Tooltip widget.
---------
Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com>
Co-authored-by: Victor Sanni <victorsanniay@gmail.com>
This is my attempt to handle
https://github.com/flutter/flutter/issues/6537 for the
CupertinoPageScaffold widget.
Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com>
Co-authored-by: Victor Sanni <victorsanniay@gmail.com>