In order to prevent the widget inspector from being able to select and
inspect elements of the widget previewer's scaffolding, this commit
consists of two notable changes:
1) A `debugWillManuallyInjectWidgetInspector` property has been added to
`WidgetsBinding`. Setting this property to true before running the
application will prevent `WidgetsApp` from injecting a `WidgetInspector`
instance into the widget tree, even if the widget inspector is enabled.
This means that the widget inspector will not be able to select and
highlight widgets by default, requiring `WidgetInspector` to be manually
wrapped around widget trees that should be inspectable.
2) The widget_preview_scaffold template has been updated to set
`debugWillManuallyInjectWidgetInspector` to true by default, and to wrap
individual previews provided by the developer with an instance of
`WidgetInspector` to restrict widget inspection to the contents of the
preview.
This change also includes a minor bug fix for situations where
`WidgetInspector` is inserted into an unconstrained context. Previously,
the `WidgetInspector`'s `_InspectorOverlay` would attempt to take up as
much space as possible, causing an overflow. To fix this, the
`_InspectorOverlay` is wrapped with `Positioned.fill(...)` to force it
to take on the same size as its parent `Stack`.
Work towards https://github.com/flutter/flutter/issues/166423
**Demo:**
https://github.com/user-attachments/assets/6d9d384c-5470-4828-983d-a6d9051a2282
A soft restart simply removes the previewed widget from the widget tree
for a frame before re-inserting it on the next frame. This has the
effect of re-running local initializers in `State` objects, which would
normally require a hot restart to accomplish. This reduces the number of
cases where a full hot restart of the preview environment would be
needed to pick up state-related changes.
Fixes https://github.com/flutter/flutter/issues/166450
**Updated Controls:**

**Demo:** updates a string initialized in `initState`, triggering a hot
reload. The updated string isn't rendered until the restart button is
pressed, causing the widget to be reloaded with the new state
initialized.
https://github.com/user-attachments/assets/ab4abf8a-7823-491a-ad90-f83d877600ec
<!-- start_original_pr_link -->
Reverts: flutter/flutter#166698
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: jonahwilliams
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: tests are timing out in presubmit
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: bkonyi
<!-- end_original_pr_author -->
<!-- start_reviewers -->
Reviewed By: {jyameo}
<!-- end_reviewers -->
<!-- start_revert_body -->
This change reverts the following previous change:
This will eventually be used as the main communication channel between
the widget preview scaffold, the Flutter tool, and other developer
tooling (e.g., IDEs).
Fixes#166417
<!-- end_revert_body -->
Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com>
This will eventually be used as the main communication channel between
the widget preview scaffold, the Flutter tool, and other developer
tooling (e.g., IDEs).
Fixes#166417
Adds a new `widget_preview_scaffold.shard` directory which contains a
hydrated `widget_preview_scaffold` template. This will allow for us to
write widget tests against the widgets defined in the templates.
This PR doesn't add any widget tests and is only adding the ability to
run these tests in follow up changes.
Fixes https://github.com/flutter/flutter/issues/166416
This change reworks how users define previews in their code, expands the
number of valid 'functions' that can be used to create previews, and
allows for specifying a 'wrapper' function to wrap the previewed widget
with
The `WidgetPreview` class has been removed from the framework, with its
properties being added to the `Preview` annotation class instead to
remove some boilerplate from the preview declaration workflow.
Before:
```dart
@Preview()
List<WidgetPreview> previews() => <WidgetPreview>[
WidgetPreview(
name: 'Top-level preview',
child: Text('Foo'),
),
];
```
After:
```dart
@Preview(name: 'Top-level preview')
Widget previews() => Text('Foo');
```
Previews can now be defined using top-level functions, constructors and
factories which take no arguments, and static methods within classes:
Examples:
```dart
@Preview(name: 'Top-level preview')
Widget previews() => Text('Foo');
class MyWidget extends StatelessWidget {
@Preview(name: 'Constructor preview')
MyWidget.preview();
@Preview(name: 'Factory preview')
factory MyWidget.factoryPreview() => MyWidget.preview();
@Preview(name: 'Static preview')
static Widget previewStatic() => Text('Static');
@override
Widget build(BuildContext context) {
return Text('MyWidget');
}
}
```
Users can also provide a `wrapper` function with the signature `Widget
Function(Widget)` to easily wrap previewed widget with shared
bootstrapping logic.
Example:
```dart
Widget testWrapper(Widget child) {
return Provider<int>.value(
value: 42,
child: child,
);
}
@Preview(name: 'Preview with wrapper', wrapper: testWrapper)
Widget preview() {
return Text('Attributes');
}
```
Which is effectively the same as:
```dart
@Preview(name: 'Preview with wrapper')
Widget preview() {
return Provider<int>.value(
value: 42,
child: Text('Attributes'),
);
}
```
Finally, for situations where a `BuildContext` is needed, users can
return a `WidgetBuilder` from their preview function:
```dart
@Preview('Builder preview')
WidgetBuilder builderPreview() {
return (BuildContext context) {
// TODO: retrieve state from context.
return Text('Foo');
};
}
```
`flutter widget-preview start --web` will cause the widget preview
scaffold to be run as a Flutter Web application using experimental hot
reload support. This will eventually be the default, with the desktop
environment being put behind a flag for use as a fallback under the
assumption that the desktop environment will be removed in the future.
With this change, `flutter widget-preview start` will launch a working
widget preview environment that can render previews from a target
project.
Also fixes an issue where `--offline` wasn't being respected by some pub
operations.
This also wires up the preview detector to trigger hot reloads when new
previews are detected or previews are removed.
Note: while this change results in lib/generated_preview.dart being
generated and updated, it's not currently referenced by lib/main.dart
and the preview environment will render a black screen.
---------
Co-authored-by: Andrew Kolos <andrewrkolos@gmail.com>
This is the initial tooling work for Flutter Widget Previews, adding two
commands: `flutter widget-preview start` and `flutter widget-preview
clean`.
The `start` command currently only checks to see if
`.dart_tool/widget_preview_scaffold/` exists and creates a new Flutter
project using the widget_preview_scaffold template if one isn't found.
The widget_preview_scaffold template currently only contains some
placeholder files and will be updated to include additional code
required by the scaffold.
The `clean` command simply deletes `.dart_tool/widget_preview_scaffold/`
if it's found.
This change also includes some refactoring of the `create` command in
order to share some project creation logic without requiring `flutter
widget-preview start` to spawn a new process simply to run `flutter
create -t widget_preview .dart_tool/widget_preview_scaffold`.
Related issue: https://github.com/flutter/flutter/issues/115704
---------
Co-authored-by: Andrew Kolos <andrewrkolos@gmail.com>