mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Implement framework interface for the dialog window archetype (#176202)
## What's new? - 🍏 Added the concept of dialogs to the windowing API. New symbols: - `DialogWindowControllerDelegate` - `DialogWindowController` - `WindowingOwner.createDialogWindowController` - `DialogWindow` - `WindowControllerCommon` - 🥘 Introduced the `WindowControllerCommon` mixin to share common windowing functionality between controller types - I have NOT yet implemented dialogs. This pull request ONLY adds the idea to the API. Win32 implementation to follow :) ## 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 commit is contained in:
parent
bfde3e8f31
commit
c9608e28d0
@ -96,12 +96,14 @@ class _WindowsTable extends StatelessWidget {
|
||||
context: context,
|
||||
controller: regular,
|
||||
),
|
||||
DialogWindowController() => throw UnimplementedError(),
|
||||
};
|
||||
}
|
||||
|
||||
static String _getWindowTypeName(BaseWindowController controller) {
|
||||
return switch (controller) {
|
||||
RegularWindowController() => 'Regular',
|
||||
DialogWindowController() => 'Dialog',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ class WindowContent extends StatelessWidget {
|
||||
controller: regular,
|
||||
child: MaterialApp(home: RegularWindowContent(window: regular)),
|
||||
),
|
||||
DialogWindowController() => throw UnimplementedError(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +159,9 @@ mixin class RegularWindowControllerDelegate {
|
||||
/// {@tool snippet}
|
||||
/// An example usage might look like:
|
||||
///
|
||||
///
|
||||
/// ```dart
|
||||
/// // TODO(mattkae): remove invalid_use_of_internal_member ignore comment when this API is stable.
|
||||
/// // ignore_for_file: invalid_use_of_internal_member
|
||||
/// import 'package:flutter/widgets.dart';
|
||||
/// import 'package:flutter/material.dart';
|
||||
@ -181,7 +183,7 @@ mixin class RegularWindowControllerDelegate {
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// Children of a [RegularWindow] widget can access the [RegularWindowController]
|
||||
/// via the [WindowControllerScope] inherited widget.
|
||||
/// via the [WindowScope] inherited widget.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
@ -190,6 +192,7 @@ abstract class RegularWindowController extends BaseWindowController {
|
||||
///
|
||||
/// Upon construction, the window is created by the platform.
|
||||
///
|
||||
/// {@template flutter.widgets.windowing.constraints}
|
||||
/// The [preferredSize] is the preferred content size of the window.
|
||||
/// This might not be honored by the platform. This is the size that
|
||||
/// the platform will try to apply to the window when it is created. In contrast,
|
||||
@ -209,6 +212,7 @@ abstract class RegularWindowController extends BaseWindowController {
|
||||
///
|
||||
/// If both [preferredSize] and [preferredConstraints] are null,
|
||||
/// then the platform will use its own default size for the window.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// The [title] argument configures the window's initial title.
|
||||
/// If omitted, some platforms might fall back to the app's name.
|
||||
@ -372,6 +376,250 @@ abstract class RegularWindowController extends BaseWindowController {
|
||||
void setFullscreen(bool fullscreen, {Display? display});
|
||||
}
|
||||
|
||||
/// Delegate class for dialog window controller.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [DialogWindowController], the controller that creates and manages dialog windows.
|
||||
/// * [DialogWindow], the widget for a dialog window.
|
||||
/// * [RegularWindowControllerDelegate], the delegate for regular window controllers.
|
||||
@internal
|
||||
mixin class DialogWindowControllerDelegate {
|
||||
/// Invoked when the user attempts to close the window.
|
||||
///
|
||||
/// The default implementation destroys the window. Subclasses
|
||||
/// can override the behavior to delay or prevent the window from closing.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [onWindowDestroyed], which is invoked after the window is closed.
|
||||
@internal
|
||||
void onWindowCloseRequested(DialogWindowController controller) {
|
||||
if (!isWindowingEnabled) {
|
||||
throw UnsupportedError(_kWindowingDisabledErrorMessage);
|
||||
}
|
||||
|
||||
controller.destroy();
|
||||
}
|
||||
|
||||
/// Invoked after the window is closed.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [onWindowCloseRequested], which is invoked when the user attempts to close the window.
|
||||
@internal
|
||||
void onWindowDestroyed() {
|
||||
if (!isWindowingEnabled) {
|
||||
throw UnsupportedError(_kWindowingDisabledErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A controller for a dialog window.
|
||||
///
|
||||
/// Two types of dialogs are supported:
|
||||
/// * Modal dialogs: created with a non-null parent. These dialogs are modal
|
||||
/// to the parent, do not have a system menu, and are not selectable from the
|
||||
/// window switcher.
|
||||
/// * Modeless dialogs: created with a null parent. These dialogs can be
|
||||
/// minimized (but not maximized), and have a disabled close button.
|
||||
///
|
||||
/// This class does not interact with the widget tree. Instead, it is typically
|
||||
/// provided to the [DialogWindow] widget, which renders the content inside the
|
||||
/// dialog window.
|
||||
///
|
||||
/// The user of this class is responsible for managing the lifecycle of the window.
|
||||
/// When the window is no longer needed, the user should call [destroy] on this
|
||||
/// controller to release the resources associated with the window.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
/// An example usage might look like:
|
||||
///
|
||||
/// ```dart
|
||||
/// // TODO(mattkae): remove invalid_use_of_internal_member ignore comment when this API is stable.
|
||||
/// // ignore_for_file: invalid_use_of_internal_member
|
||||
/// import 'package:flutter/widgets.dart';
|
||||
/// import 'package:flutter/material.dart';
|
||||
/// import 'package:flutter/src/widgets/_window.dart';
|
||||
///
|
||||
/// void main() {
|
||||
/// runWidget(
|
||||
/// RegularWindow(
|
||||
/// controller: RegularWindowController(
|
||||
/// preferredSize: const Size(800, 600),
|
||||
/// preferredConstraints: const BoxConstraints(minWidth: 640, minHeight: 480),
|
||||
/// title: 'Example Window',
|
||||
/// ),
|
||||
/// child: const MyApp()
|
||||
/// )
|
||||
/// );
|
||||
/// }
|
||||
///
|
||||
/// class MyApp extends StatelessWidget {
|
||||
/// const MyApp({super.key});
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return MaterialApp(
|
||||
/// home: DialogWindow(
|
||||
/// controller: DialogWindowController(
|
||||
/// preferredSize: const Size(400, 300),
|
||||
/// parent: WindowScope.of(context),
|
||||
/// title: 'Example Dialog'
|
||||
/// ),
|
||||
/// child: const Text('Hello, World!')
|
||||
/// )
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// Children of a [DialogWindow] widget can access the [DialogWindowController]
|
||||
/// via the [WindowScope] inherited widget.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
abstract class DialogWindowController extends BaseWindowController {
|
||||
/// Creates a [DialogWindowController] with the provided properties.
|
||||
///
|
||||
/// Upon construction, the window is created by the platform.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.constraints}
|
||||
///
|
||||
/// The [parent] argument specifies the parent window of this dialog.
|
||||
///
|
||||
/// If the [parent] is null, then the dialog is modeless. Such dialogs can
|
||||
/// be minimized but not maximized. They also have a disabled close button.
|
||||
///
|
||||
/// If the [parent] is non-null, then the dialog is modal to the parent.
|
||||
/// Such dialogs do not have a system menu. They are also not selectable
|
||||
/// from the window switcher and they are closed when the parent is closed.
|
||||
///
|
||||
/// The [title] argument configures the window's initial title.
|
||||
/// If omitted, some platforms might fall back to the app's name.
|
||||
///
|
||||
/// The [delegate] argument can be used to listen to the window's
|
||||
/// lifecycle. For example, it can be used to save state before
|
||||
/// a window is closed.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
factory DialogWindowController({
|
||||
Size? preferredSize,
|
||||
BoxConstraints? preferredConstraints,
|
||||
BaseWindowController? parent,
|
||||
String? title,
|
||||
DialogWindowControllerDelegate? delegate,
|
||||
}) {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final WindowingOwner owner = WidgetsBinding.instance.windowingOwner;
|
||||
return owner.createDialogWindowController(
|
||||
delegate: delegate ?? DialogWindowControllerDelegate(),
|
||||
preferredSize: preferredSize,
|
||||
preferredConstraints: preferredConstraints,
|
||||
title: title,
|
||||
parent: parent,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates an empty [DialogWindowController].
|
||||
///
|
||||
/// This method is only intended to be used by subclasses of the
|
||||
/// [DialogWindowController].
|
||||
///
|
||||
/// Users who want to instantiate a new [DialogWindowController] should
|
||||
/// always use the factory method to create a controller that is valid
|
||||
/// for their particular platform.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
@protected
|
||||
DialogWindowController.empty();
|
||||
|
||||
/// The parent controller of this dialog, if any.
|
||||
///
|
||||
/// If null, this dialog is modeless.
|
||||
/// If non-null, this dialog is modal to the parent.
|
||||
BaseWindowController? get parent;
|
||||
|
||||
/// The current title of the window.
|
||||
///
|
||||
/// This might differ from the requested title.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
String get title;
|
||||
|
||||
/// Whether the window is currently activated.
|
||||
///
|
||||
/// If `true` this means that the window is currently focused and
|
||||
/// can receive user input.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
bool get isActivated;
|
||||
|
||||
/// Whether or not window is currently minimized.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
bool get isMinimized;
|
||||
|
||||
/// Request change to the content size of the window.
|
||||
///
|
||||
/// The [size] describes the new requested window size. If the size disagrees
|
||||
/// with the current constraints placed upon the window, the platform might
|
||||
/// clamp the size within the constraints.
|
||||
///
|
||||
/// The platform is free to ignore this request.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
void setSize(Size size);
|
||||
|
||||
/// Request change to the constraints of the window.
|
||||
///
|
||||
/// The [constraints] describes the new constraints that the window should
|
||||
/// satisfy. If the constraints disagree with the current size of the window,
|
||||
/// the platform might resize the window to satisfy the new constraints.
|
||||
///
|
||||
/// The platform is free to ignore this request.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
void setConstraints(BoxConstraints constraints);
|
||||
|
||||
/// Request change for the window title.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
void setTitle(String title);
|
||||
|
||||
/// Requests that the window be displayed in its current size and position.
|
||||
///
|
||||
/// The platform may also give the window input focus and bring it to the
|
||||
/// top of the window stack. However, this behavior is platform-dependent.
|
||||
///
|
||||
/// If the window is minimized, the window returns to the size and position
|
||||
/// that it had before that state was applied. The window will also be
|
||||
/// brought to the top of the window stack.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
void activate();
|
||||
|
||||
/// Requests window to be minimized.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
void setMinimized(bool minimized);
|
||||
}
|
||||
|
||||
/// [WindowingOwner] is responsible for creating and managing window controllers.
|
||||
///
|
||||
/// A custom implementation can be provided by setting [WidgetsBinding.windowingOwner].
|
||||
@ -394,6 +642,22 @@ abstract class WindowingOwner {
|
||||
String? title,
|
||||
});
|
||||
|
||||
/// Creates a [DialogWindowController] with the provided properties.
|
||||
///
|
||||
/// Most app developers should use [DialogWindowController]'s constructor
|
||||
/// instead of calling this method directly. This method allows platforms
|
||||
/// to inject platform-specific logic.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
DialogWindowController createDialogWindowController({
|
||||
required DialogWindowControllerDelegate delegate,
|
||||
Size? preferredSize,
|
||||
BoxConstraints? preferredConstraints,
|
||||
BaseWindowController? parent,
|
||||
String? title,
|
||||
});
|
||||
|
||||
/// Returns whether the application has any top level windows created by this
|
||||
/// windowing owner.
|
||||
///
|
||||
@ -435,6 +699,17 @@ class _WindowingOwnerUnsupported extends WindowingOwner {
|
||||
throw UnsupportedError(errorMessage);
|
||||
}
|
||||
|
||||
@override
|
||||
DialogWindowController createDialogWindowController({
|
||||
required DialogWindowControllerDelegate delegate,
|
||||
Size? preferredSize,
|
||||
BoxConstraints? preferredConstraints,
|
||||
BaseWindowController? parent,
|
||||
String? title,
|
||||
}) {
|
||||
throw UnsupportedError(errorMessage);
|
||||
}
|
||||
|
||||
@override
|
||||
bool hasTopLevelWindows() {
|
||||
throw UnsupportedError(errorMessage);
|
||||
@ -458,6 +733,7 @@ class _WindowingOwnerUnsupported extends WindowingOwner {
|
||||
/// An example usage might look like:
|
||||
///
|
||||
/// ```dart
|
||||
/// // TODO(mattkae): remove invalid_use_of_internal_member ignore comment when this API is stable.
|
||||
/// // ignore_for_file: invalid_use_of_internal_member
|
||||
/// import 'package:flutter/widgets.dart';
|
||||
/// import 'package:flutter/material.dart';
|
||||
@ -523,6 +799,107 @@ class RegularWindow extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// The [DialogWindow] widget provides a way to render a dialog window in the
|
||||
/// widget tree.
|
||||
///
|
||||
/// The provided [controller] creates the native window that backs
|
||||
/// the widget. The [child] widget is rendered into this newly created window.
|
||||
///
|
||||
/// When a [DialogWindow] widget is removed from the tree, the window that was created
|
||||
/// by the [controller] remains valid until the caller destroys it by calling
|
||||
/// [DialogWindowController.destroy].
|
||||
///
|
||||
/// Widgets in the same tree as the [child] widget will have access to the
|
||||
/// [DialogWindowController] via the [WindowScope] widget.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
/// An example usage might look like:
|
||||
///
|
||||
/// ```dart
|
||||
/// // TODO(mattkae): remove invalid_use_of_internal_member ignore comment when this API is stable.
|
||||
/// // ignore_for_file: invalid_use_of_internal_member
|
||||
/// import 'package:flutter/widgets.dart';
|
||||
/// import 'package:flutter/material.dart';
|
||||
/// import 'package:flutter/src/widgets/_window.dart';
|
||||
///
|
||||
/// void main() {
|
||||
/// runWidget(
|
||||
/// RegularWindow(
|
||||
/// controller: RegularWindowController(
|
||||
/// preferredSize: const Size(800, 600),
|
||||
/// preferredConstraints: const BoxConstraints(minWidth: 640, minHeight: 480),
|
||||
/// title: 'Example Window',
|
||||
/// ),
|
||||
/// child: const MyApp()
|
||||
/// )
|
||||
/// );
|
||||
/// }
|
||||
///
|
||||
/// class MyApp extends StatelessWidget {
|
||||
/// const MyApp({super.key});
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return MaterialApp(
|
||||
/// home: DialogWindow(
|
||||
/// controller: DialogWindowController(
|
||||
/// preferredSize: const Size(400, 300),
|
||||
/// parent: WindowScope.of(context),
|
||||
/// title: 'Example Dialog'
|
||||
/// ),
|
||||
/// child: const Text('Hello, World!')
|
||||
/// )
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
class DialogWindow extends StatelessWidget {
|
||||
/// Creates a dialog window widget.
|
||||
///
|
||||
/// The [controller] creates the native backing window into which the
|
||||
/// [child] widget is rendered.
|
||||
///
|
||||
/// It is up to the caller to destroy the window by calling
|
||||
/// [DialogWindowController.destroy] when the window is no longer needed.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
DialogWindow({super.key, required this.controller, required this.child}) {
|
||||
if (!isWindowingEnabled) {
|
||||
throw UnsupportedError(_kWindowingDisabledErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// Controller for this widget.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
final DialogWindowController controller;
|
||||
|
||||
/// The content rendered into this window.
|
||||
///
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
final Widget child;
|
||||
|
||||
/// {@macro flutter.widgets.windowing.experimental}
|
||||
@internal
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(
|
||||
listenable: controller,
|
||||
builder: (BuildContext context, Widget? widget) => WindowScope(
|
||||
controller: controller,
|
||||
child: View(view: controller.rootView, child: child),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum _WindowControllerAspect { contentSize, title, activated, maximized, minimized, fullscreen }
|
||||
|
||||
/// Provides descendants with access to the [BaseWindowController] associated with
|
||||
@ -537,6 +914,7 @@ enum _WindowControllerAspect { contentSize, title, activated, maximized, minimiz
|
||||
/// See also:
|
||||
///
|
||||
/// * [RegularWindow], the widget to create a regular window.
|
||||
/// * [DialogWindow], the widget to create a dialog window.
|
||||
@internal
|
||||
class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
/// Creates a new [WindowScope].
|
||||
@ -565,8 +943,8 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
|
||||
/// Returns the [BaseWindowController] for the window that hosts the given context.
|
||||
///
|
||||
/// {@template flutter.widgets.windowing.windowControllerScope.of}
|
||||
/// If there is no [WindowControllerScope] in scope, this method
|
||||
/// {@template flutter.widgets.windowing.WindowScope.of}
|
||||
/// If there is no [WindowScope] in scope, this method
|
||||
/// will throw a [TypeError] exception in release builds, and throws
|
||||
/// a descriptive [FlutterError] in debug builds.
|
||||
///
|
||||
@ -580,7 +958,9 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
/// See also:
|
||||
///
|
||||
/// * [RegularWindowController], the controller for regular top-level windows.
|
||||
/// * [DialogWindowController], the controller for dialog windows.
|
||||
/// * [RegularWindow], the widget for a regular window.
|
||||
/// * [DialogWindow], the widget for a dialog window.
|
||||
/// * [maybeOf], which doesn't throw or assert if it doesn't find a
|
||||
/// [WindowScope] ancestor. It returns null instead.
|
||||
@internal
|
||||
@ -595,7 +975,9 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
/// See also:
|
||||
///
|
||||
/// * [RegularWindowController], the controller for regular top-level windows.
|
||||
/// * [DialogWindowController], the controller for dialog windows.
|
||||
/// * [RegularWindow], the widget for a regular window.
|
||||
/// * [DialogWindow], the widget for a dialog window.
|
||||
/// * [of], which will throw if it doesn't find a [WindowScope] ancestor,
|
||||
/// instead of returning null.
|
||||
@internal
|
||||
@ -648,6 +1030,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
final BaseWindowController controller = _of(context, _WindowControllerAspect.title);
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.title,
|
||||
DialogWindowController() => controller.title,
|
||||
};
|
||||
}
|
||||
|
||||
@ -668,6 +1051,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.title,
|
||||
DialogWindowController() => controller.title,
|
||||
};
|
||||
}
|
||||
|
||||
@ -689,6 +1073,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
final BaseWindowController controller = _of(context, _WindowControllerAspect.activated);
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.isActivated,
|
||||
DialogWindowController() => controller.isActivated,
|
||||
};
|
||||
}
|
||||
|
||||
@ -710,6 +1095,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.isActivated,
|
||||
DialogWindowController() => controller.isActivated,
|
||||
};
|
||||
}
|
||||
|
||||
@ -731,6 +1117,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
final BaseWindowController controller = _of(context, _WindowControllerAspect.minimized);
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.isMinimized,
|
||||
DialogWindowController() => controller.isMinimized,
|
||||
};
|
||||
}
|
||||
|
||||
@ -752,6 +1139,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.isMinimized,
|
||||
DialogWindowController() => controller.isMinimized,
|
||||
};
|
||||
}
|
||||
|
||||
@ -773,6 +1161,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
final BaseWindowController controller = _of(context, _WindowControllerAspect.maximized);
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.isMaximized,
|
||||
DialogWindowController() => false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -794,6 +1183,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.isMaximized,
|
||||
DialogWindowController() => false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -816,6 +1206,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.isFullscreen,
|
||||
DialogWindowController() => false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -837,6 +1228,7 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
|
||||
return switch (controller) {
|
||||
RegularWindowController() => controller.isFullscreen,
|
||||
DialogWindowController() => false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -898,26 +1290,34 @@ class WindowScope extends InheritedModel<_WindowControllerAspect> {
|
||||
_WindowControllerAspect.title => switch (controller) {
|
||||
final RegularWindowController regular =>
|
||||
regular.title != (oldWidget.controller as RegularWindowController).title,
|
||||
final DialogWindowController dialog =>
|
||||
dialog.title != (oldWidget.controller as DialogWindowController).title,
|
||||
},
|
||||
_WindowControllerAspect.activated => switch (controller) {
|
||||
final RegularWindowController regular =>
|
||||
regular.isActivated !=
|
||||
(oldWidget.controller as RegularWindowController).isActivated,
|
||||
final DialogWindowController dialog =>
|
||||
dialog.isActivated != (oldWidget.controller as DialogWindowController).isActivated,
|
||||
},
|
||||
_WindowControllerAspect.maximized => switch (controller) {
|
||||
final RegularWindowController regular =>
|
||||
regular.isMaximized !=
|
||||
(oldWidget.controller as RegularWindowController).isMaximized,
|
||||
DialogWindowController() => false,
|
||||
},
|
||||
_WindowControllerAspect.minimized => switch (controller) {
|
||||
final RegularWindowController regular =>
|
||||
regular.isMinimized !=
|
||||
(oldWidget.controller as RegularWindowController).isMinimized,
|
||||
final DialogWindowController dialog =>
|
||||
dialog.isMinimized != (oldWidget.controller as DialogWindowController).isMinimized,
|
||||
},
|
||||
_WindowControllerAspect.fullscreen => switch (controller) {
|
||||
final RegularWindowController regular =>
|
||||
regular.isFullscreen !=
|
||||
(oldWidget.controller as RegularWindowController).isFullscreen,
|
||||
DialogWindowController() => false,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@ -148,6 +148,18 @@ class WindowingOwnerWin32 extends WindowingOwner {
|
||||
);
|
||||
}
|
||||
|
||||
@internal
|
||||
@override
|
||||
DialogWindowController createDialogWindowController({
|
||||
required DialogWindowControllerDelegate delegate,
|
||||
Size? preferredSize,
|
||||
BoxConstraints? preferredConstraints,
|
||||
BaseWindowController? parent,
|
||||
String? title,
|
||||
}) {
|
||||
throw UnimplementedError('Dialog windows are not yet implemented on Windows.');
|
||||
}
|
||||
|
||||
/// Register a new [WindowsMessageHandler].
|
||||
///
|
||||
/// The handler will be triggered for unhandled messages for all top level
|
||||
|
||||
@ -7,6 +7,9 @@ import 'package:flutter/src/foundation/_features.dart' show isWindowingEnabled;
|
||||
import 'package:flutter/src/widgets/_window.dart'
|
||||
show
|
||||
BaseWindowController,
|
||||
DialogWindow,
|
||||
DialogWindowController,
|
||||
DialogWindowControllerDelegate,
|
||||
RegularWindow,
|
||||
RegularWindowController,
|
||||
RegularWindowControllerDelegate,
|
||||
@ -18,8 +21,8 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'multi_view_testing.dart';
|
||||
|
||||
class _StubWindowController extends RegularWindowController {
|
||||
_StubWindowController(WidgetTester tester) : super.empty() {
|
||||
class _StubRegularWindowController extends RegularWindowController {
|
||||
_StubRegularWindowController(WidgetTester tester) : super.empty() {
|
||||
rootView = FakeView(tester.view);
|
||||
}
|
||||
|
||||
@ -66,6 +69,45 @@ class _StubWindowController extends RegularWindowController {
|
||||
void destroy() {}
|
||||
}
|
||||
|
||||
class _StubDialogWindowController extends DialogWindowController {
|
||||
_StubDialogWindowController(WidgetTester tester) : super.empty() {
|
||||
rootView = FakeView(tester.view);
|
||||
}
|
||||
|
||||
@override
|
||||
BaseWindowController? get parent => null;
|
||||
|
||||
@override
|
||||
Size get contentSize => Size.zero;
|
||||
|
||||
@override
|
||||
String get title => 'Stub Window';
|
||||
|
||||
@override
|
||||
bool get isActivated => true;
|
||||
|
||||
@override
|
||||
bool get isMinimized => false;
|
||||
|
||||
@override
|
||||
void setSize(Size size) {}
|
||||
|
||||
@override
|
||||
void setConstraints(BoxConstraints constraints) {}
|
||||
|
||||
@override
|
||||
void setTitle(String title) {}
|
||||
|
||||
@override
|
||||
void activate() {}
|
||||
|
||||
@override
|
||||
void setMinimized(bool minimized) {}
|
||||
|
||||
@override
|
||||
void destroy() {}
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('Windowing', () {
|
||||
group('isWindowingEnabled is false', () {
|
||||
@ -86,6 +128,14 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test('default WindowingOwner throws when accessing createDialogWindowController', () {
|
||||
final WindowingOwner owner = createDefaultWindowingOwner();
|
||||
expect(
|
||||
() => owner.createDialogWindowController(delegate: DialogWindowControllerDelegate()),
|
||||
throwsUnsupportedError,
|
||||
);
|
||||
});
|
||||
|
||||
test('default WindowingOwner throws when accessing hasTopLevelWindows', () {
|
||||
final WindowingOwner owner = createDefaultWindowingOwner();
|
||||
expect(() => owner.hasTopLevelWindows(), throwsUnsupportedError);
|
||||
@ -93,7 +143,20 @@ void main() {
|
||||
|
||||
testWidgets('RegularWindow throws UnsupportedError', (WidgetTester tester) async {
|
||||
expect(
|
||||
() => RegularWindow(controller: _StubWindowController(tester), child: const Text('Test')),
|
||||
() => RegularWindow(
|
||||
controller: _StubRegularWindowController(tester),
|
||||
child: const Text('Test'),
|
||||
),
|
||||
throwsUnsupportedError,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('DialogWindow throws UnsupportedError', (WidgetTester tester) async {
|
||||
expect(
|
||||
() => DialogWindow(
|
||||
controller: _StubDialogWindowController(tester),
|
||||
child: const Text('Test'),
|
||||
),
|
||||
throwsUnsupportedError,
|
||||
);
|
||||
});
|
||||
@ -112,7 +175,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('RegularWindow does not throw', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -120,8 +183,17 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.of', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Dialog does not throw', (WidgetTester tester) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(controller: controller, child: Container()),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.of for regular windows', (WidgetTester tester) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -138,8 +210,28 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.of for dialog windows', (WidgetTester tester) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final BaseWindowController scope = WindowScope.of(context);
|
||||
expect(scope, isA<DialogWindowController>());
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -156,8 +248,28 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.contentSizeOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.maybeOf for dialog windows', (WidgetTester tester) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final BaseWindowController? scope = WindowScope.maybeOf(context);
|
||||
expect(scope, isA<DialogWindowController>());
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.contentSizeOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -174,8 +286,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeContentSizeOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.contentSizeOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final Size size = WindowScope.contentSizeOf(context);
|
||||
expect(size, equals(Size.zero));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeContentSizeOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -192,8 +326,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.titleOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.maybeContentSizeOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final Size? size = WindowScope.maybeContentSizeOf(context);
|
||||
expect(size, equals(Size.zero));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.titleOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -210,8 +366,28 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeTitleOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.titleOf for dialog windows', (WidgetTester tester) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final String title = WindowScope.titleOf(context);
|
||||
expect(title, equals('Stub Window'));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeTitleOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -228,8 +404,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.isActivatedOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.maybeTitleOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final String? title = WindowScope.maybeTitleOf(context);
|
||||
expect(title, equals('Stub Window'));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.isActivatedOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -246,8 +444,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsActivatedOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.isActivatedOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final bool isActivated = WindowScope.isActivatedOf(context);
|
||||
expect(isActivated, equals(true));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsActivatedOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -264,8 +484,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.isMinimizedOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.maybeIsActivatedOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final bool? isActivated = WindowScope.maybeIsActivatedOf(context);
|
||||
expect(isActivated, equals(true));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.isMinimizedOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -282,8 +524,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsMinimizedOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.isMinimizedOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final bool isMinimized = WindowScope.isMinimizedOf(context);
|
||||
expect(isMinimized, equals(false));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsMinimizedOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -300,8 +564,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.isMaximizedOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.maybeIsMinimizedOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final bool? isMinimized = WindowScope.maybeIsMinimizedOf(context);
|
||||
expect(isMinimized, equals(false));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.isMaximizedOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -318,8 +604,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsMaximizedOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.isMaximizedOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final bool isMaximized = WindowScope.isMaximizedOf(context);
|
||||
expect(isMaximized, equals(false));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsMaximizedOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -336,8 +644,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.isFullscreenOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.maybeIsMaximizedOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final bool? isMaximized = WindowScope.maybeIsMaximizedOf(context);
|
||||
expect(isMaximized, equals(false));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.isFullscreenOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -354,8 +684,30 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsFullscreenOf', (WidgetTester tester) async {
|
||||
final _StubWindowController controller = _StubWindowController(tester);
|
||||
testWidgets('Can access WindowScope.isFullscreenOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final bool isFullscreen = WindowScope.isFullscreenOf(context);
|
||||
expect(isFullscreen, equals(false));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsFullscreenOf for regular windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubRegularWindowController controller = _StubRegularWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
@ -371,6 +723,26 @@ void main() {
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can access WindowScope.maybeIsFullscreenOf for dialog windows', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final _StubDialogWindowController controller = _StubDialogWindowController(tester);
|
||||
addTearDown(controller.dispose);
|
||||
await tester.pumpWidget(
|
||||
wrapWithView: false,
|
||||
DialogWindow(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final bool? isFullscreen = WindowScope.maybeIsFullscreenOf(context);
|
||||
expect(isFullscreen, equals(false));
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user