diff --git a/packages/flet/lib/src/controls/page.dart b/packages/flet/lib/src/controls/page.dart index 7edb16519f..7a3c7ec1ce 100644 --- a/packages/flet/lib/src/controls/page.dart +++ b/packages/flet/lib/src/controls/page.dart @@ -20,6 +20,7 @@ import '../models/page_design.dart'; import '../routing/route_parser.dart'; import '../routing/route_state.dart'; import '../routing/router_delegate.dart'; +import '../services/service_binding.dart'; import '../services/service_registry.dart'; import '../utils/device_info.dart'; import '../utils/locale.dart'; @@ -57,6 +58,9 @@ class _PageControlState extends State with WidgetsBindingObserver { late final AppLifecycleListener _appLifecycleListener; ServiceRegistry? _pageServices; ServiceRegistry? _userServices; + String? _userServicesUid; + ServiceBinding? _windowService; + Control? _windowControl; bool? _prevOnKeyboardEvent; bool _keyboardHandlerSubscribed = false; String? _prevViewRoutes; @@ -95,12 +99,15 @@ class _PageControlState extends State with WidgetsBindingObserver { _attachKeyboardListenerIfNeeded(); widget.control.addInvokeMethodListener(_invokeMethod); + widget.control.addListener(_onPageControlChanged); + _ensureServiceRegistries(); } @override void didChangeDependencies() { debugPrint("Page.didChangeDependencies: ${widget.control.id}"); super.didChangeDependencies(); + _ensureServiceRegistries(); _loadFontsIfNeeded(FletBackend.of(context)); } @@ -109,26 +116,7 @@ class _PageControlState extends State with WidgetsBindingObserver { debugPrint("Page.didUpdateWidget: ${widget.control.id}"); super.didUpdateWidget(oldWidget); _updateMultiViews(); - - // page services - _pageServices ??= ServiceRegistry( - control: widget.control, - propertyName: "_services", - backend: FletBackend.of(context)); - - // user services - var userServicesControl = widget.control.child("_user_services"); - if (userServicesControl != null) { - if (_userServices == null || - _userServices?.control.internals?["uid"] != - userServicesControl.internals?["uid"]) { - _userServices = ServiceRegistry( - control: userServicesControl, - propertyName: "_services", - backend: FletBackend.of(context)); - } - } - + _ensureServiceRegistries(); _attachKeyboardListenerIfNeeded(); _loadFontsIfNeeded(FletBackend.of(context)); } @@ -148,9 +136,60 @@ class _PageControlState extends State with WidgetsBindingObserver { HardwareKeyboard.instance.removeHandler(_handleKeyDown); } widget.control.removeInvokeMethodListener(_invokeMethod); + widget.control.removeListener(_onPageControlChanged); + _pageServices?.dispose(); + _userServices?.dispose(); + _windowService?.dispose(); super.dispose(); } + void _onPageControlChanged() { + _ensureServiceRegistries(); + } + + void _ensureServiceRegistries() { + if (!mounted) { + return; + } + var backend = FletBackend.of(context); + + _pageServices ??= ServiceRegistry( + control: widget.control, + propertyName: "_services", + backend: backend); + + var userServicesControl = widget.control.child("_user_services"); + if (userServicesControl != null) { + var uid = userServicesControl.internals?["uid"]; + if (_userServices == null || _userServicesUid != uid) { + _userServices?.dispose(); + _userServices = ServiceRegistry( + control: userServicesControl, + propertyName: "_services", + backend: backend); + _userServicesUid = uid; + } + } else if (_userServices != null) { + _userServices?.dispose(); + _userServices = null; + _userServicesUid = null; + } + + var windowControl = widget.control.child("window", visibleOnly: false); + if (windowControl != null) { + if (!identical(windowControl, _windowControl)) { + _windowService?.dispose(); + _windowService = + ServiceBinding(control: windowControl, backend: backend); + _windowControl = windowControl; + } + } else if (_windowService != null) { + _windowService?.dispose(); + _windowService = null; + _windowControl = null; + } + } + Future _invokeMethod(String name, dynamic args) async { debugPrint("Page.$name($args)"); diff --git a/packages/flet/lib/src/controls/view.dart b/packages/flet/lib/src/controls/view.dart index 41ec0d01f9..10e215d6d7 100644 --- a/packages/flet/lib/src/controls/view.dart +++ b/packages/flet/lib/src/controls/view.dart @@ -168,10 +168,6 @@ class _ViewControlState extends State { overlayWidgets.add(PageMedia(view: widget.control.parent)); } - var windowControl = control.parent?.get("window"); - if (windowControl != null && isRootView && isDesktopPlatform()) { - overlayWidgets.add(ControlWidget(control: windowControl)); - } } Widget body = Stack(children: [ diff --git a/packages/flet/lib/src/flet_backend.dart b/packages/flet/lib/src/flet_backend.dart index a8c74faf27..088ffcc273 100644 --- a/packages/flet/lib/src/flet_backend.dart +++ b/packages/flet/lib/src/flet_backend.dart @@ -192,6 +192,7 @@ class FletBackend extends ChangeNotifier { } _registerClient() { + debugPrint("Registering web client: $page"); _send( Message( action: MessageAction.registerClient, @@ -211,7 +212,7 @@ class FletBackend extends ChangeNotifier { "width": page.get("width"), "height": page.get("height"), "platform": page.get("platform"), - "window": page.child("window")!.toMap(), + "window": page.child("window", visibleOnly: false)!.toMap(), "media": page.get("media"), }).toMap()), unbuffered: true); @@ -333,7 +334,7 @@ class FletBackend extends ChangeNotifier { if (isDesktopPlatform()) { var windowState = await getWindowState(); debugPrint("Window state updated: $windowState"); - var window = page.child("window")!; + var window = page.child("window", visibleOnly: false)!; updateControl(window.id, windowState.toMap()); triggerControlEvent(window, "event", {"type": "resized"}); } @@ -470,8 +471,7 @@ class FletBackend extends ChangeNotifier { var template = appErrorMessage ?? defaultAppErrorMessageTemplate; final lines = const LineSplitter().convert(rawError); final message = lines.isNotEmpty ? lines.first : ""; - final details = - lines.length > 1 ? lines.sublist(1).join("\n") : ""; + final details = lines.length > 1 ? lines.sublist(1).join("\n") : ""; template = template.replaceAll("{message}", message); if (details.isEmpty) { template = template.replaceAll(RegExp(r'(\r?\n)*\{details\}'), ""); diff --git a/packages/flet/lib/src/flet_core_extension.dart b/packages/flet/lib/src/flet_core_extension.dart index 17e0868ff5..5903641677 100644 --- a/packages/flet/lib/src/flet_core_extension.dart +++ b/packages/flet/lib/src/flet_core_extension.dart @@ -101,7 +101,6 @@ import 'controls/time_picker.dart'; import 'controls/transparent_pointer.dart'; import 'controls/vertical_divider.dart'; import 'controls/view.dart'; -import 'controls/window.dart'; import 'controls/window_drag_area.dart'; import 'flet_extension.dart'; import 'flet_service.dart'; @@ -116,6 +115,7 @@ import 'services/shared_preferences.dart'; import 'services/storage_paths.dart'; import 'services/tester.dart'; import 'services/url_launcher.dart'; +import 'services/window.dart'; import 'utils/cupertino_icons.dart'; import 'utils/material_icons.dart'; @@ -355,8 +355,6 @@ class FletCoreExtension extends FletExtension { return VerticalDividerControl(key: key, control: control); case "View": return ViewControl(key: key, control: control); - case "Window": - return WindowControl(key: key, control: control); case "WindowDragArea": return WindowDragAreaControl(key: key, control: control); default: @@ -383,6 +381,8 @@ class FletCoreExtension extends FletExtension { return SemanticsServiceControl(control: control); case "StoragePaths": return StoragePaths(control: control); + case "Window": + return WindowService(control: control); case "Tester": return TesterService(control: control); case "UrlLauncher": diff --git a/packages/flet/lib/src/controls/window.dart b/packages/flet/lib/src/services/window.dart similarity index 60% rename from packages/flet/lib/src/controls/window.dart rename to packages/flet/lib/src/services/window.dart index df68368d62..9ba9731ed4 100644 --- a/packages/flet/lib/src/controls/window.dart +++ b/packages/flet/lib/src/services/window.dart @@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:window_manager/window_manager.dart'; import '../flet_backend.dart'; -import '../models/control.dart'; +import '../flet_service.dart'; import '../utils/alignment.dart'; import '../utils/colors.dart'; import '../utils/desktop.dart'; @@ -13,17 +13,8 @@ import '../utils/platform.dart'; import '../utils/theme.dart'; import '../utils/window.dart'; -class WindowControl extends StatefulWidget { - final Control control; - - WindowControl({Key? key, required this.control}) - : super(key: key ?? ValueKey("control_${control.id}")); - - @override - State createState() => _WindowControlState(); -} - -class _WindowControlState extends State with WindowListener { +class WindowService extends FletService with WindowListener { + final Completer _initWindowStateCompleter = Completer(); String? _title; Color? _bgColor; double? _width; @@ -58,128 +49,129 @@ class _WindowControlState extends State with WindowListener { bool? _skipTaskBar; double? _progressBar; bool? _ignoreMouseEvents; - final Completer _initWindowStateCompleter = Completer(); + bool _listenersAttached = false; + + WindowService({required super.control}); @override - void initState() { - debugPrint("Window.initState()"); - super.initState(); + void init() { + super.init(); + if (!isDesktopPlatform()) { + return; + } + debugPrint("WindowService(${control.id}).init"); _initWindowState(); } Future _initWindowState() async { - final windowState = await getWindowState(); - _width = windowState.width; - _height = windowState.height; - _top = windowState.top; - _left = windowState.left; - _opacity = windowState.opacity; - _minimizable = windowState.minimizable; - _maximizable = windowState.maximizable; - _fullScreen = windowState.fullScreen; - _resizable = windowState.resizable; - _alwaysOnTop = windowState.alwaysOnTop; - _preventClose = windowState.preventClose; - _minimized = windowState.minimized; - _maximized = windowState.maximized; - _visible = windowState.visible; - _focused = windowState.focused; - _skipTaskBar = windowState.skipTaskBar; - - // bind listeners - windowManager.addListener(this); - widget.control.addInvokeMethodListener(_invokeMethod); - - if (!_initWindowStateCompleter.isCompleted) { - _initWindowStateCompleter.complete(); - } - } + try { + final windowState = await getWindowState(); + _width = windowState.width; + _height = windowState.height; + _top = windowState.top; + _left = windowState.left; + _opacity = windowState.opacity; + _minimizable = windowState.minimizable; + _maximizable = windowState.maximizable; + _fullScreen = windowState.fullScreen; + _resizable = windowState.resizable; + _alwaysOnTop = windowState.alwaysOnTop; + _preventClose = windowState.preventClose; + _minimized = windowState.minimized; + _maximized = windowState.maximized; + _visible = windowState.visible; + _focused = windowState.focused; + _skipTaskBar = windowState.skipTaskBar; + + if (!_listenersAttached) { + windowManager.addListener(this); + control.addInvokeMethodListener(_invokeMethod); + _listenersAttached = true; + } - @override - void didChangeDependencies() { - debugPrint("Window.didChangeDependencies: ${widget.control.id}"); - super.didChangeDependencies(); - _updateWindowAfterInit(); - } + if (!_initWindowStateCompleter.isCompleted) { + _initWindowStateCompleter.complete(); + } - @override - void dispose() { - debugPrint("Window.dispose()"); - windowManager.removeListener(this); - widget.control.addInvokeMethodListener(_invokeMethod); - super.dispose(); + _scheduleWindowUpdate(); + } catch (e) { + debugPrint("Error initializing window state: $e"); + } } @override - void didUpdateWidget(covariant WindowControl oldWidget) { - debugPrint("Window.didUpdateWidget: ${widget.control.id}"); - super.didUpdateWidget(oldWidget); - _updateWindowAfterInit(); + void update() { + if (!isDesktopPlatform()) { + return; + } + _scheduleWindowUpdate(); } - void _updateWindowAfterInit() { - var backend = FletBackend.of(context); + void _scheduleWindowUpdate() { if (_initWindowStateCompleter.isCompleted) { - _updateWindow(backend); + unawaited(_updateWindow(control.backend)); } else { - _initWindowStateCompleter.future.then((_) { - _updateWindow(backend); - }); + _initWindowStateCompleter.future + .then((_) => _updateWindow(control.backend)); } } - void _updateWindow(FletBackend backend) async { + Future _updateWindow(FletBackend backend) async { + if (!isDesktopPlatform()) { + return; + } try { - var title = widget.control.parent!.getString("title"); - var bgColor = widget.control.getColor("bgcolor", context); - var width = widget.control.getDouble("width"); - var height = widget.control.getDouble("height"); - var minWidth = widget.control.getDouble("min_width"); - var minHeight = widget.control.getDouble("min_height"); - var maxWidth = widget.control.getDouble("max_width"); - var maxHeight = widget.control.getDouble("max_height"); - var top = widget.control.getDouble("top"); - var left = widget.control.getDouble("left"); - var fullScreen = widget.control.getBool("full_screen"); - var minimized = widget.control.getBool("minimized"); - var maximized = widget.control.getBool("maximized"); - var alignment = widget.control.getAlignment("alignment"); - var badgeLabel = widget.control.getString("badge_label"); - var icon = widget.control.getString("icon"); - var hasShadow = widget.control.getBool("shadow"); - var opacity = widget.control.getDouble("opacity"); - var aspectRatio = widget.control.getDouble("aspect_ratio"); - var brightness = widget.control.getBrightness("brightness"); - var minimizable = widget.control.getBool("minimizable"); - var maximizable = widget.control.getBool("maximizable"); - var alwaysOnTop = widget.control.getBool("always_on_top"); - var alwaysOnBottom = widget.control.getBool("always_on_bottom"); - var resizable = widget.control.getBool("resizable"); - var movable = widget.control.getBool("movable"); - var preventClose = widget.control.getBool("prevent_close"); - var titleBarHidden = widget.control.getBool("title_bar_hidden"); + var parent = control.parent; + if (parent == null) { + return; + } + var title = parent.getString("title"); + var bgColor = control.getColor("bgcolor", null); + var width = control.getDouble("width"); + var height = control.getDouble("height"); + var minWidth = control.getDouble("min_width"); + var minHeight = control.getDouble("min_height"); + var maxWidth = control.getDouble("max_width"); + var maxHeight = control.getDouble("max_height"); + var top = control.getDouble("top"); + var left = control.getDouble("left"); + var fullScreen = control.getBool("full_screen"); + var minimized = control.getBool("minimized"); + var maximized = control.getBool("maximized"); + var alignment = control.getAlignment("alignment"); + var badgeLabel = control.getString("badge_label"); + var icon = control.getString("icon"); + var hasShadow = control.getBool("shadow"); + var opacity = control.getDouble("opacity"); + var aspectRatio = control.getDouble("aspect_ratio"); + var brightness = control.getBrightness("brightness"); + var minimizable = control.getBool("minimizable"); + var maximizable = control.getBool("maximizable"); + var alwaysOnTop = control.getBool("always_on_top"); + var alwaysOnBottom = control.getBool("always_on_bottom"); + var resizable = control.getBool("resizable"); + var movable = control.getBool("movable"); + var preventClose = control.getBool("prevent_close"); + var titleBarHidden = control.getBool("title_bar_hidden"); var titleBarButtonsHidden = - widget.control.getBool("title_bar_buttons_hidden", false)!; - var visible = widget.control.getBool("visible"); - var focused = widget.control.getBool("focused"); - var skipTaskBar = widget.control.getBool("skip_task_bar"); - var frameless = widget.control.getBool("frameless"); - var progressBar = widget.control.getDouble("progress_bar"); - var ignoreMouseEvents = widget.control.getBool("ignore_mouse_events"); - - // title + control.getBool("title_bar_buttons_hidden", false)!; + var visible = control.getBool("visible"); + var focused = control.getBool("focused"); + var skipTaskBar = control.getBool("skip_task_bar"); + var frameless = control.getBool("frameless"); + var progressBar = control.getDouble("progress_bar"); + var ignoreMouseEvents = control.getBool("ignore_mouse_events"); + if (title != null && title != _title) { - setWindowTitle(title); + await setWindowTitle(title); _title = title; } - // bgColor if (bgColor != null && bgColor != _bgColor) { - setWindowBackgroundColor(bgColor); + await setWindowBackgroundColor(bgColor); _bgColor = bgColor; } - // size if ((width != null || height != null) && (width != _width || height != _height) && fullScreen != true && @@ -190,7 +182,6 @@ class _WindowControlState extends State with WindowListener { _height = height; } - // min size if ((minWidth != null || minHeight != null) && (minWidth != _minWidth || minHeight != _minHeight)) { await setWindowMinSize(minWidth, minHeight); @@ -198,7 +189,6 @@ class _WindowControlState extends State with WindowListener { _minHeight = minHeight; } - // max size if ((maxWidth != null || maxHeight != null) && (maxWidth != _maxWidth || maxHeight != _maxHeight)) { await setWindowMaxSize(maxWidth, maxHeight); @@ -206,7 +196,6 @@ class _WindowControlState extends State with WindowListener { _maxHeight = maxHeight; } - // position if ((top != null || left != null) && (top != _top || left != _left) && fullScreen != true && @@ -217,31 +206,26 @@ class _WindowControlState extends State with WindowListener { _left = left; } - // opacity if (opacity != null && opacity != _opacity) { await setWindowOpacity(opacity); _opacity = opacity; } - // aspectRatio if (aspectRatio != null && aspectRatio != _aspectRatio) { await setWindowAspectRatio(aspectRatio); _aspectRatio = aspectRatio; } - // brightness if (brightness != null && brightness != _brightness) { await setWindowBrightness(brightness); _brightness = brightness; } - // minimizable if (minimizable != null && minimizable != _minimizable) { await setWindowMinimizability(minimizable); _minimizable = minimizable; } - // minimized if (minimized != _minimized) { if (minimized == true) { await minimizeWindow(); @@ -251,13 +235,11 @@ class _WindowControlState extends State with WindowListener { _minimized = minimized; } - // maximizable if (maximizable != null && maximizable != _maximizable) { await setWindowMaximizability(maximizable); _maximizable = maximizable; } - // maximized if (maximized != _maximized) { if (maximized == true) { await maximizeWindow(); @@ -267,76 +249,64 @@ class _WindowControlState extends State with WindowListener { _maximized = maximized; } - // alignment if (alignment != null && alignment != _alignment) { await setWindowAlignment(alignment); _alignment = alignment; } - // badge label if (badgeLabel != null && badgeLabel != _badgeLabel) { await setWindowBadgeLabel(badgeLabel); _badgeLabel = badgeLabel; } - // icon if (icon != null && icon != _icon) { var iconAssetSrc = backend.getAssetSource(icon); await setWindowIcon(iconAssetSrc.path); _icon = icon; } - // has shadow if (hasShadow != null && hasShadow != _hasShadow) { await setWindowShadow(hasShadow); _hasShadow = hasShadow; } - // resizable if (resizable != null && resizable != _resizable) { await setWindowResizability(resizable); _resizable = resizable; } - // movable if (movable != null && movable != _movable) { await setWindowMovability(movable); _movable = movable; } - // full screen if (fullScreen != null && fullScreen != _fullScreen) { await setWindowFullScreen(fullScreen); _fullScreen = fullScreen; } - // always on top if (alwaysOnTop != null && alwaysOnTop != _alwaysOnTop) { await setWindowAlwaysOnTop(alwaysOnTop); _alwaysOnTop = alwaysOnTop; } - // always on bottom if (alwaysOnBottom != null && alwaysOnBottom != _alwaysOnBottom) { await setWindowAlwaysOnBottom(alwaysOnBottom); _alwaysOnBottom = alwaysOnBottom; } - // prevent close if (preventClose != null && preventClose != _preventClose) { await setWindowPreventClose(preventClose); _preventClose = preventClose; } - // title bar hidden if (titleBarHidden != null && titleBarHidden != _titleBarHidden) { await setWindowTitleBarVisibility( titleBarHidden, titleBarButtonsHidden); _titleBarHidden = titleBarHidden; } - // visible - if (visible != _visible) { + if (visible != null && visible != _visible) { if (visible == true) { await showWindow(); } else { @@ -345,8 +315,7 @@ class _WindowControlState extends State with WindowListener { _visible = visible; } - // focused - if (focused != _focused) { + if (focused != null && focused != _focused) { if (focused == true) { await focusWindow(); } else { @@ -355,25 +324,21 @@ class _WindowControlState extends State with WindowListener { _focused = focused; } - // frameless if (frameless != null && frameless != _frameless && frameless == true) { await setWindowFrameless(); _frameless = frameless; } - // progress bar if (progressBar != null && progressBar != _progressBar) { await setWindowProgressBar(progressBar); _progressBar = progressBar; } - // skip task bar if (skipTaskBar != null && skipTaskBar != _skipTaskBar) { await setWindowSkipTaskBar(skipTaskBar); _skipTaskBar = skipTaskBar; } - // ignore mouse events if (ignoreMouseEvents != null && ignoreMouseEvents != _ignoreMouseEvents) { await setIgnoreMouseEvents(ignoreMouseEvents); @@ -411,18 +376,28 @@ class _WindowControlState extends State with WindowListener { } break; default: - throw Exception("Unknown method ${widget.control.type}.$name"); + throw Exception("Unknown method Window.$name"); } } @override - Widget build(BuildContext context) { - return const SizedBox.shrink(); + void dispose() { + if (_listenersAttached) { + windowManager.removeListener(this); + control.removeInvokeMethodListener(_invokeMethod); + _listenersAttached = false; + } + super.dispose(); } @override void onWindowEvent(String eventName) { - if (["resize", "resized", "move"].contains(eventName)) return; + if (!isDesktopPlatform()) { + return; + } + if (["resize", "resized", "move"].contains(eventName)) { + return; + } getWindowState().then((state) { _width = state.width; _height = state.height; @@ -441,8 +416,7 @@ class _WindowControlState extends State with WindowListener { _focused = state.focused; _skipTaskBar = state.skipTaskBar; - // notify - widget.control.backend.onWindowEvent(eventName, state); + control.backend.onWindowEvent(eventName, state); }); } } diff --git a/sdk/python/examples/controls/page/window_hidden_on_start.py b/sdk/python/examples/controls/page/window_hidden_on_start.py index 5c85a796ae..0ce72c4198 100644 --- a/sdk/python/examples/controls/page/window_hidden_on_start.py +++ b/sdk/python/examples/controls/page/window_hidden_on_start.py @@ -1,9 +1,15 @@ +# +# Use -n (--hidden) option to run this example with `flet run` command: +# +# flet run -n examples/controls/page/window_hidden_on_start.py +# import asyncio import flet as ft async def main(page: ft.Page): + print("Window is hidden on start. Will show after 3 seconds...") page.add(ft.Text("Hello!")) await asyncio.sleep(3) page.window.visible = True diff --git a/sdk/python/examples/controls/page/window_resize.py b/sdk/python/examples/controls/page/window_resize.py new file mode 100644 index 0000000000..d54f7ba3d2 --- /dev/null +++ b/sdk/python/examples/controls/page/window_resize.py @@ -0,0 +1,19 @@ +import flet as ft + + +def main(page: ft.Page): + if page.window.width is None or page.window.height is None: + page.add(ft.Text("Window size can be changed only in desktop apps.")) + return + + width = 400 + height = 300 + + chrome_width = page.window.width - page.width + chrome_height = page.window.height - page.height + page.window.width = width + chrome_width + page.window.height = height + chrome_height + page.window.update() + + +ft.run(main) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_time_picker.py b/sdk/python/packages/flet/integration_tests/controls/material/test_time_picker.py index efacbda781..a85c807ae0 100644 --- a/sdk/python/packages/flet/integration_tests/controls/material/test_time_picker.py +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_time_picker.py @@ -17,18 +17,20 @@ def flet_app(flet_app_function): async def test_basic(flet_app: ftt.FletTestApp, request): flet_app.page.enable_screenshots = True flet_app.resize_page(600, 450) - - time_picker = ft.TimePicker( - confirm_text="Confirm", - error_invalid_text="Time out of range", - help_text="Pick your time slot", - value=datetime.time(hour=19, minute=30), - hour_format=ft.TimePickerHourFormat.H24, - ) - flet_app.page.show_dialog(time_picker) flet_app.page.update() await flet_app.tester.pump_and_settle() + flet_app.page.show_dialog( + ft.TimePicker( + confirm_text="Confirm", + error_invalid_text="Time out of range", + help_text="Pick your time slot", + value=datetime.time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H24, + ) + ) + + await flet_app.tester.pump_and_settle() flet_app.assert_screenshot( request.node.name, await flet_app.page.take_screenshot( @@ -41,13 +43,16 @@ async def test_basic(flet_app: ftt.FletTestApp, request): async def test_hour_format_12(flet_app: ftt.FletTestApp, request): flet_app.page.enable_screenshots = True flet_app.resize_page(600, 450) + flet_app.page.update() + await flet_app.tester.pump_and_settle() - time_picker = ft.TimePicker( - value=datetime.time(hour=19, minute=30), - hour_format=ft.TimePickerHourFormat.H12, + flet_app.page.show_dialog( + ft.TimePicker( + value=datetime.time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H12, + ) ) - flet_app.page.show_dialog(time_picker) - flet_app.page.update() + await flet_app.tester.pump_and_settle() flet_app.assert_screenshot( request.node.name, @@ -61,13 +66,16 @@ async def test_hour_format_12(flet_app: ftt.FletTestApp, request): async def test_hour_format_24(flet_app: ftt.FletTestApp, request): flet_app.page.enable_screenshots = True flet_app.resize_page(600, 450) + flet_app.page.update() + await flet_app.tester.pump_and_settle() - time_picker = ft.TimePicker( - value=datetime.time(hour=19, minute=30), - hour_format=ft.TimePickerHourFormat.H24, + flet_app.page.show_dialog( + ft.TimePicker( + value=datetime.time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H24, + ) ) - flet_app.page.show_dialog(time_picker) - flet_app.page.update() + await flet_app.tester.pump_and_settle() flet_app.assert_screenshot( request.node.name, diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_shader_mask.py b/sdk/python/packages/flet/integration_tests/examples/core/test_shader_mask.py index 2a70d53aa7..e8905a8b0b 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_shader_mask.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_shader_mask.py @@ -28,9 +28,12 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): ) flet_app_function.page.enable_screenshots = True flet_app_function.resize_page(300, 320) - flet_app_function.page.add(sm) flet_app_function.page.update() - await flet_app_function.tester.pump_and_settle(duration=ft.Duration(seconds=1)) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.page.add(sm) + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.pump(1000) flet_app_function.assert_screenshot( "test_image_for_docs", await flet_app_function.page.take_screenshot( diff --git a/sdk/python/packages/flet/integration_tests/examples/cupertino/test_cupertino_action_sheet.py b/sdk/python/packages/flet/integration_tests/examples/cupertino/test_cupertino_action_sheet.py index c7aea65ff2..e26374bbd4 100644 --- a/sdk/python/packages/flet/integration_tests/examples/cupertino/test_cupertino_action_sheet.py +++ b/sdk/python/packages/flet/integration_tests/examples/cupertino/test_cupertino_action_sheet.py @@ -10,6 +10,9 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): page.theme_mode = ft.ThemeMode.LIGHT page.enable_screenshots = True flet_app_function.resize_page(400, 400) + page.update() + await flet_app_function.tester.pump_and_settle() + sheet = ft.CupertinoActionSheet( title=ft.Text("Choose an option"), message=ft.Text("Select what you would like to do."), @@ -20,12 +23,10 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): cancel=ft.CupertinoActionSheetAction(content=ft.Text("Cancel")), ) page.add(sheet) - page.update() await flet_app_function.tester.pump_and_settle() flet_app_function.assert_screenshot( - "test_image_for_docs", + request.node.name, await flet_app_function.page.take_screenshot( pixel_ratio=flet_app_function.screenshots_pixel_ratio ), ) - page.update() diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/context_menu/programmatic_open.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/context_menu/programmatic_open.png index 1f516099d4..c8e2c77ec6 100644 Binary files a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/context_menu/programmatic_open.png and b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/context_menu/programmatic_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_context_menu.py b/sdk/python/packages/flet/integration_tests/examples/material/test_context_menu.py index 78399787fe..89f32ab44c 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_context_menu.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_context_menu.py @@ -42,6 +42,7 @@ async def test_programmatic_open(flet_app_function: ftt.FletTestApp): flet_app_function.page.enable_screenshots = True flet_app_function.resize_page(300, 300) flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() # click button to open menu await flet_app_function.tester.tap( diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_time_picker.py b/sdk/python/packages/flet/integration_tests/examples/material/test_time_picker.py index e95a846388..de7cae659d 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_time_picker.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_time_picker.py @@ -14,17 +14,19 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT flet_app_function.page.enable_screenshots = True flet_app_function.resize_page(600, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() - time_picker = ft.TimePicker( - value=time(hour=19, minute=30), - hour_format=ft.TimePickerHourFormat.H12, + flet_app_function.page.show_dialog( + ft.TimePicker( + value=time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H12, + ) ) - flet_app_function.page.show_dialog(time_picker) - flet_app_function.page.update() await flet_app_function.tester.pump_and_settle() flet_app_function.assert_screenshot( - "test_image_for_docs", + request.node.name, await flet_app_function.page.take_screenshot( pixel_ratio=flet_app_function.screenshots_pixel_ratio ), @@ -40,12 +42,13 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): async def test_basic(flet_app_function: ftt.FletTestApp): flet_app_function.page.enable_screenshots = True flet_app_function.resize_page(600, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() # open picker await flet_app_function.tester.tap( await flet_app_function.tester.find_by_icon(ft.Icons.TIME_TO_LEAVE) ) - flet_app_function.page.update() await flet_app_function.tester.pump_and_settle() flet_app_function.assert_screenshot(