From 78e6096fe878487b5cfd3b78d90c8ab397f89cf3 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 27 Oct 2025 13:59:05 +0100 Subject: [PATCH 1/8] initial commit --- packages/flet/lib/src/controls/page.dart | 7 +++++++ packages/flet/pubspec.yaml | 1 + .../packages/flet/src/flet/controls/page.py | 16 ++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/packages/flet/lib/src/controls/page.dart b/packages/flet/lib/src/controls/page.dart index 19a5126304..d37ebcb443 100644 --- a/packages/flet/lib/src/controls/page.dart +++ b/packages/flet/lib/src/controls/page.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:fullscreen_window/fullscreen_window.dart'; import 'package:provider/provider.dart'; import '../extensions/control.dart'; @@ -197,6 +198,12 @@ class _PageControlState extends State with WidgetsBindingObserver { await SystemChrome.setPreferredOrientations(orientations); } break; + case "set_fullscreen": + final value = parseBool(args["value"]); + if (value != null) { + await FullScreenWindow.setFullScreen(value); + } + break; default: throw Exception("Unknown Page method: $name"); diff --git a/packages/flet/pubspec.yaml b/packages/flet/pubspec.yaml index c18d34bcad..e721bf00df 100644 --- a/packages/flet/pubspec.yaml +++ b/packages/flet/pubspec.yaml @@ -28,6 +28,7 @@ dependencies: flutter_highlight: 0.7.0 flutter_markdown: 0.7.6+2 flutter_svg: 2.2.1 + fullscreen_window: ^1.2.0 highlight: ^0.7.0 http: 1.5.0 markdown: 7.3.0 diff --git a/sdk/python/packages/flet/src/flet/controls/page.py b/sdk/python/packages/flet/src/flet/controls/page.py index 6c358a1974..6691ba072c 100644 --- a/sdk/python/packages/flet/src/flet/controls/page.py +++ b/sdk/python/packages/flet/src/flet/controls/page.py @@ -330,6 +330,22 @@ class Page(BasePage): The operating system the application is running on. """ + @property + def fullscreen(self) -> bool: + """ + Requests fullscreen mode for the host window or browser. + + Set to `True` to hide the host system chrome; set to `False` to restore it. + """ + return getattr(self, "_fullscreen", False) + + @fullscreen.setter + def fullscreen(self, value: bool) -> None: + self._fullscreen = value + asyncio.create_task( + self._invoke_method("set_fullscreen", arguments={"value": value}) + ) + fonts: Optional[dict[str, str]] = None """ Defines the custom fonts to be used in the application. From e061ab1cbff026fc3cc636a1249334ea6169321a Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 27 Oct 2025 13:59:38 +0100 Subject: [PATCH 2/8] platform config --- client/ios/Flutter/AppFrameworkInfo.plist | 2 +- client/ios/Podfile | 2 +- client/ios/Podfile.lock | 12 ++++++------ client/ios/Runner.xcodeproj/project.pbxproj | 6 +++--- client/linux/flutter/generated_plugin_registrant.cc | 4 ++++ client/linux/flutter/generated_plugins.cmake | 1 + client/pubspec.lock | 8 ++++++++ .../windows/flutter/generated_plugin_registrant.cc | 3 +++ client/windows/flutter/generated_plugins.cmake | 1 + 9 files changed, 28 insertions(+), 11 deletions(-) diff --git a/client/ios/Flutter/AppFrameworkInfo.plist b/client/ios/Flutter/AppFrameworkInfo.plist index 7c56964006..1dc6cf7652 100644 --- a/client/ios/Flutter/AppFrameworkInfo.plist +++ b/client/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 12.0 + 13.0 diff --git a/client/ios/Podfile b/client/ios/Podfile index 412ab380b1..1685edd78a 100644 --- a/client/ios/Podfile +++ b/client/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '12.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/client/ios/Podfile.lock b/client/ios/Podfile.lock index 68492f8268..c584552fd7 100644 --- a/client/ios/Podfile.lock +++ b/client/ios/Podfile.lock @@ -62,7 +62,7 @@ PODS: - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - - record_ios (1.0.0): + - record_ios (1.1.0): - Flutter - rive_common (0.0.1): - Flutter @@ -169,7 +169,7 @@ SPEC CHECKSUMS: DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e Google-Mobile-Ads-SDK: 1dfb0c3cb46c7e2b00b0f4de74a1e06d9ea25d67 google_mobile_ads: 535223588a6791b7a3cc3513a1bc7b89d12f3e62 @@ -180,7 +180,7 @@ SPEC CHECKSUMS: package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b + record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374 rive_common: dd421daaf9ae69f0125aa761dd96abd278399952 SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b @@ -190,8 +190,8 @@ SPEC CHECKSUMS: url_launcher_ios: 694010445543906933d732453a59da0a173ae33d volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 - webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2 + webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d -PODFILE CHECKSUM: 6e0773c9c44c19ccfa69850451666ad1d1af99d1 +PODFILE CHECKSUM: 462a5b249f9f1900cbd87af7b6af48272dc2df5a -COCOAPODS: 1.14.3 +COCOAPODS: 1.16.2 diff --git a/client/ios/Runner.xcodeproj/project.pbxproj b/client/ios/Runner.xcodeproj/project.pbxproj index 979c654f03..00bb254787 100644 --- a/client/ios/Runner.xcodeproj/project.pbxproj +++ b/client/ios/Runner.xcodeproj/project.pbxproj @@ -360,7 +360,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -441,7 +441,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -490,7 +490,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/client/linux/flutter/generated_plugin_registrant.cc b/client/linux/flutter/generated_plugin_registrant.cc index 64afe36fe3..f656ce8b1d 100644 --- a/client/linux/flutter/generated_plugin_registrant.cc +++ b/client/linux/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -21,6 +22,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); + g_autoptr(FlPluginRegistrar) fullscreen_window_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FullscreenWindowPlugin"); + fullscreen_window_plugin_register_with_registrar(fullscreen_window_registrar); g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); diff --git a/client/linux/flutter/generated_plugins.cmake b/client/linux/flutter/generated_plugins.cmake index 71b63382d5..6a9ff42869 100644 --- a/client/linux/flutter/generated_plugins.cmake +++ b/client/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux + fullscreen_window media_kit_libs_linux media_kit_video record_linux diff --git a/client/pubspec.lock b/client/pubspec.lock index 6f8197566b..fe4658cbc7 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -449,6 +449,14 @@ packages: description: flutter source: sdk version: "0.0.0" + fullscreen_window: + dependency: transitive + description: + name: fullscreen_window + sha256: "74247cb56006e5d00fa9ed7eaef9df90caa2be1cec4d5b1aeb7391fec7d19f66" + url: "https://pub.dev" + source: hosted + version: "1.2.0" geoclue: dependency: transitive description: diff --git a/client/windows/flutter/generated_plugin_registrant.cc b/client/windows/flutter/generated_plugin_registrant.cc index 754c15c2ff..8006f9ab35 100644 --- a/client/windows/flutter/generated_plugin_registrant.cc +++ b/client/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -22,6 +23,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { AudioplayersWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); + FullscreenWindowPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FullscreenWindowPluginCApi")); GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( diff --git a/client/windows/flutter/generated_plugins.cmake b/client/windows/flutter/generated_plugins.cmake index 72a5864a6b..de13849365 100644 --- a/client/windows/flutter/generated_plugins.cmake +++ b/client/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows + fullscreen_window geolocator_windows media_kit_libs_windows_video media_kit_video From 3276cceb64842900da5ca483483149920323d8e7 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 27 Oct 2025 15:31:57 +0100 Subject: [PATCH 3/8] feat: Implement platform-specific fullscreen handling and refactor font interface imports --- packages/flet/lib/src/controls/page.dart | 15 +++++++- .../{user_fonts_io.dart => io_interface.dart} | 8 +++- packages/flet/lib/src/utils/user_fonts.dart | 2 +- .../flet/lib/src/utils/user_fonts_web.dart | 5 --- .../flet/lib/src/utils/web_interface.dart | 15 ++++++++ .../packages/flet/src/flet/controls/page.py | 38 +++++++++++-------- 6 files changed, 58 insertions(+), 25 deletions(-) rename packages/flet/lib/src/utils/{user_fonts_io.dart => io_interface.dart} (56%) delete mode 100644 packages/flet/lib/src/utils/user_fonts_web.dart create mode 100644 packages/flet/lib/src/utils/web_interface.dart diff --git a/packages/flet/lib/src/controls/page.dart b/packages/flet/lib/src/controls/page.dart index d37ebcb443..30f64641c6 100644 --- a/packages/flet/lib/src/controls/page.dart +++ b/packages/flet/lib/src/controls/page.dart @@ -9,7 +9,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:fullscreen_window/fullscreen_window.dart'; import 'package:provider/provider.dart'; import '../extensions/control.dart'; @@ -33,6 +32,8 @@ import '../utils/session_store_web.dart' import '../utils/theme.dart'; import '../utils/time.dart'; import '../utils/user_fonts.dart'; +import '../utils/web_interface.dart' + if (dart.library.io) "../utils/io_interface.dart"; import '../widgets/animated_transition_page.dart'; import '../widgets/loading_page.dart'; import '../widgets/page_context.dart'; @@ -201,7 +202,17 @@ class _PageControlState extends State with WidgetsBindingObserver { case "set_fullscreen": final value = parseBool(args["value"]); if (value != null) { - await FullScreenWindow.setFullScreen(value); + if (isDesktopPlatform() || isWebPlatform()) { + await setWindowFullScreen(value); + } else if (isMobilePlatform()) { + if (value) { + await SystemChrome.setEnabledSystemUIMode( + SystemUiMode.immersiveSticky); + } else { + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, + overlays: SystemUiOverlay.values); + } + } } break; diff --git a/packages/flet/lib/src/utils/user_fonts_io.dart b/packages/flet/lib/src/utils/io_interface.dart similarity index 56% rename from packages/flet/lib/src/utils/user_fonts_io.dart rename to packages/flet/lib/src/utils/io_interface.dart index fd592a2cf8..e9667eaaaa 100644 --- a/packages/flet/lib/src/utils/user_fonts_io.dart +++ b/packages/flet/lib/src/utils/io_interface.dart @@ -1,8 +1,14 @@ -import 'dart:typed_data'; import 'dart:io'; +import 'dart:typed_data'; + +import 'desktop.dart' as desktop show setWindowFullScreen; Future fetchFontFromFile(String path) async { File file = File(path); Uint8List bytes = await file.readAsBytes(); return ByteData.view(bytes.buffer); } + +Future setWindowFullScreen(bool fullScreen) async { + await desktop.setWindowFullScreen(fullScreen); +} diff --git a/packages/flet/lib/src/utils/user_fonts.dart b/packages/flet/lib/src/utils/user_fonts.dart index ec4c5bb3f4..51746d4fc0 100644 --- a/packages/flet/lib/src/utils/user_fonts.dart +++ b/packages/flet/lib/src/utils/user_fonts.dart @@ -3,7 +3,7 @@ import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import '../models/control.dart'; -import 'user_fonts_web.dart' if (dart.library.io) "user_fonts_io.dart"; +import 'web_interface.dart' if (dart.library.io) "io_interface.dart"; class UserFonts { static Map fontLoaders = {}; diff --git a/packages/flet/lib/src/utils/user_fonts_web.dart b/packages/flet/lib/src/utils/user_fonts_web.dart deleted file mode 100644 index 2ff3ba68b7..0000000000 --- a/packages/flet/lib/src/utils/user_fonts_web.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'dart:typed_data'; - -Future fetchFontFromFile(String path) async { - throw UnimplementedError(); -} diff --git a/packages/flet/lib/src/utils/web_interface.dart b/packages/flet/lib/src/utils/web_interface.dart new file mode 100644 index 0000000000..ea2f3d6740 --- /dev/null +++ b/packages/flet/lib/src/utils/web_interface.dart @@ -0,0 +1,15 @@ +import 'dart:typed_data'; + +import 'package:web/web.dart' as web show window; + +Future fetchFontFromFile(String path) async { + throw UnimplementedError(); +} + +Future setWindowFullScreen(bool fullScreen) async { + if (fullScreen) { + web.window.document.documentElement?.requestFullscreen(); + } else { + web.window.document.exitFullscreen(); + } +} diff --git a/sdk/python/packages/flet/src/flet/controls/page.py b/sdk/python/packages/flet/src/flet/controls/page.py index 6691ba072c..bce2ab6193 100644 --- a/sdk/python/packages/flet/src/flet/controls/page.py +++ b/sdk/python/packages/flet/src/flet/controls/page.py @@ -330,22 +330,6 @@ class Page(BasePage): The operating system the application is running on. """ - @property - def fullscreen(self) -> bool: - """ - Requests fullscreen mode for the host window or browser. - - Set to `True` to hide the host system chrome; set to `False` to restore it. - """ - return getattr(self, "_fullscreen", False) - - @fullscreen.setter - def fullscreen(self, value: bool) -> None: - self._fullscreen = value - asyncio.create_task( - self._invoke_method("set_fullscreen", arguments={"value": value}) - ) - fonts: Optional[dict[str, str]] = None """ Defines the custom fonts to be used in the application. @@ -360,6 +344,28 @@ def fullscreen(self, value: bool) -> None: Usage example [here](https://flet.dev/docs/cookbook/fonts#importing-fonts). """ + @property + def full_screen(self) -> bool: + """ + Requests fullscreen mode for the host window or browser. + + Set to `True` to hide the host system chrome; set to `False` to restore it. + """ + return getattr( + self, + "__full_screen", + self.page.window.full_screen if self.page.platform.is_desktop() else False, + ) + + @full_screen.setter + def full_screen(self, value: bool) -> None: + self.__full_screen = value + if self.page.platform.is_desktop() and not self.page.web: + self.page.window.full_screen = value + asyncio.create_task( + self._invoke_method("set_fullscreen", arguments={"value": value}) + ) + on_platform_brightness_change: Optional[ EventHandler[PlatformBrightnessChangeEvent] ] = None From f73d5142d6ef2ff01f19cb11a684815094934e31 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 27 Oct 2025 15:32:44 +0100 Subject: [PATCH 4/8] Revert "platform config" This reverts commit e061ab1cbff026fc3cc636a1249334ea6169321a. --- client/ios/Flutter/AppFrameworkInfo.plist | 2 +- client/ios/Podfile | 2 +- client/ios/Podfile.lock | 12 ++++++------ client/ios/Runner.xcodeproj/project.pbxproj | 6 +++--- client/linux/flutter/generated_plugin_registrant.cc | 4 ---- client/linux/flutter/generated_plugins.cmake | 1 - client/pubspec.lock | 8 -------- .../windows/flutter/generated_plugin_registrant.cc | 3 --- client/windows/flutter/generated_plugins.cmake | 1 - 9 files changed, 11 insertions(+), 28 deletions(-) diff --git a/client/ios/Flutter/AppFrameworkInfo.plist b/client/ios/Flutter/AppFrameworkInfo.plist index 1dc6cf7652..7c56964006 100644 --- a/client/ios/Flutter/AppFrameworkInfo.plist +++ b/client/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 13.0 + 12.0 diff --git a/client/ios/Podfile b/client/ios/Podfile index 1685edd78a..412ab380b1 100644 --- a/client/ios/Podfile +++ b/client/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '13.0' +# platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/client/ios/Podfile.lock b/client/ios/Podfile.lock index c584552fd7..68492f8268 100644 --- a/client/ios/Podfile.lock +++ b/client/ios/Podfile.lock @@ -62,7 +62,7 @@ PODS: - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - - record_ios (1.1.0): + - record_ios (1.0.0): - Flutter - rive_common (0.0.1): - Flutter @@ -169,7 +169,7 @@ SPEC CHECKSUMS: DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be - Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e Google-Mobile-Ads-SDK: 1dfb0c3cb46c7e2b00b0f4de74a1e06d9ea25d67 google_mobile_ads: 535223588a6791b7a3cc3513a1bc7b89d12f3e62 @@ -180,7 +180,7 @@ SPEC CHECKSUMS: package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374 + record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b rive_common: dd421daaf9ae69f0125aa761dd96abd278399952 SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b @@ -190,8 +190,8 @@ SPEC CHECKSUMS: url_launcher_ios: 694010445543906933d732453a59da0a173ae33d volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 - webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d + webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2 -PODFILE CHECKSUM: 462a5b249f9f1900cbd87af7b6af48272dc2df5a +PODFILE CHECKSUM: 6e0773c9c44c19ccfa69850451666ad1d1af99d1 -COCOAPODS: 1.16.2 +COCOAPODS: 1.14.3 diff --git a/client/ios/Runner.xcodeproj/project.pbxproj b/client/ios/Runner.xcodeproj/project.pbxproj index 00bb254787..979c654f03 100644 --- a/client/ios/Runner.xcodeproj/project.pbxproj +++ b/client/ios/Runner.xcodeproj/project.pbxproj @@ -360,7 +360,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -441,7 +441,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -490,7 +490,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/client/linux/flutter/generated_plugin_registrant.cc b/client/linux/flutter/generated_plugin_registrant.cc index f656ce8b1d..64afe36fe3 100644 --- a/client/linux/flutter/generated_plugin_registrant.cc +++ b/client/linux/flutter/generated_plugin_registrant.cc @@ -7,7 +7,6 @@ #include "generated_plugin_registrant.h" #include -#include #include #include #include @@ -22,9 +21,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); - g_autoptr(FlPluginRegistrar) fullscreen_window_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FullscreenWindowPlugin"); - fullscreen_window_plugin_register_with_registrar(fullscreen_window_registrar); g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); diff --git a/client/linux/flutter/generated_plugins.cmake b/client/linux/flutter/generated_plugins.cmake index 6a9ff42869..71b63382d5 100644 --- a/client/linux/flutter/generated_plugins.cmake +++ b/client/linux/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux - fullscreen_window media_kit_libs_linux media_kit_video record_linux diff --git a/client/pubspec.lock b/client/pubspec.lock index fe4658cbc7..6f8197566b 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -449,14 +449,6 @@ packages: description: flutter source: sdk version: "0.0.0" - fullscreen_window: - dependency: transitive - description: - name: fullscreen_window - sha256: "74247cb56006e5d00fa9ed7eaef9df90caa2be1cec4d5b1aeb7391fec7d19f66" - url: "https://pub.dev" - source: hosted - version: "1.2.0" geoclue: dependency: transitive description: diff --git a/client/windows/flutter/generated_plugin_registrant.cc b/client/windows/flutter/generated_plugin_registrant.cc index 8006f9ab35..754c15c2ff 100644 --- a/client/windows/flutter/generated_plugin_registrant.cc +++ b/client/windows/flutter/generated_plugin_registrant.cc @@ -7,7 +7,6 @@ #include "generated_plugin_registrant.h" #include -#include #include #include #include @@ -23,8 +22,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { AudioplayersWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); - FullscreenWindowPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FullscreenWindowPluginCApi")); GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( diff --git a/client/windows/flutter/generated_plugins.cmake b/client/windows/flutter/generated_plugins.cmake index de13849365..72a5864a6b 100644 --- a/client/windows/flutter/generated_plugins.cmake +++ b/client/windows/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows - fullscreen_window geolocator_windows media_kit_libs_windows_video media_kit_video From 8e66f5b05b62de68cc7fc5ad29c43b759976cc4a Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 27 Oct 2025 16:04:34 +0100 Subject: [PATCH 5/8] example + docs --- client/lib/main.dart | 3 +-- packages/flet/pubspec.yaml | 1 - .../examples/controls/page/fullscreen.py | 22 +++++++++++++++++++ .../packages/flet/docs/controls/page.md | 15 +++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 sdk/python/examples/controls/page/fullscreen.py diff --git a/client/lib/main.dart b/client/lib/main.dart index dbb2ff65ad..37828804fe 100644 --- a/client/lib/main.dart +++ b/client/lib/main.dart @@ -87,8 +87,7 @@ void main([List? args]) async { assetsDir = args[2]; debugPrint("Args contain a path assets directory: $assetsDir}"); } - } else if (!kDebugMode && - (Platform.isWindows || Platform.isMacOS || Platform.isLinux)) { + } else if (!kDebugMode && isDesktopPlatform()) { throw Exception( 'In desktop mode Flet app URL must be provided as a first argument.'); } diff --git a/packages/flet/pubspec.yaml b/packages/flet/pubspec.yaml index e721bf00df..c18d34bcad 100644 --- a/packages/flet/pubspec.yaml +++ b/packages/flet/pubspec.yaml @@ -28,7 +28,6 @@ dependencies: flutter_highlight: 0.7.0 flutter_markdown: 0.7.6+2 flutter_svg: 2.2.1 - fullscreen_window: ^1.2.0 highlight: ^0.7.0 http: 1.5.0 markdown: 7.3.0 diff --git a/sdk/python/examples/controls/page/fullscreen.py b/sdk/python/examples/controls/page/fullscreen.py new file mode 100644 index 0000000000..dbba36565a --- /dev/null +++ b/sdk/python/examples/controls/page/fullscreen.py @@ -0,0 +1,22 @@ +import flet as ft + + +def main(page: ft.Page) -> None: + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def handle_fullscreen_change(e: ft.Event[ft.Switch]): + page.full_screen = e.control.value + + page.add( + ft.SafeArea( + ft.Switch( + value=page.full_screen, + label="Toggle Fullscreen", + on_change=handle_fullscreen_change, + ), + ) + ) + + +ft.run(main) diff --git a/sdk/python/packages/flet/docs/controls/page.md b/sdk/python/packages/flet/docs/controls/page.md index 7b7f628a59..68f7d699c1 100644 --- a/sdk/python/packages/flet/docs/controls/page.md +++ b/sdk/python/packages/flet/docs/controls/page.md @@ -29,6 +29,21 @@ Shows how to lock your app to specific device orientations --8<-- "{{ examples }}/app_exit_confirm_dialog.py" ``` +### Toggle Fullscreen + +This example demonstrates how to toggle fullscreen mode in a Flet application. + +/// admonition + type: note +[`Page.full_screen`][flet.] is cross-platform (mobile, desktop and web), whereas +[`Page.window.full_screen`][flet.Window.full_screen] is desktop only. +/// + + +```python +--8<-- "{{ examples }}/fullscreen.py" +``` + ### Hidden app window on startup ```python From 8868e6e8073444f8ca7d828c520aeddea300782e Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Tue, 28 Oct 2025 20:19:07 +0100 Subject: [PATCH 6/8] refactor API --- packages/flet/lib/src/controls/page.dart | 47 ++++++++++--------- .../packages/flet/src/flet/controls/page.py | 25 ++-------- 2 files changed, 29 insertions(+), 43 deletions(-) diff --git a/packages/flet/lib/src/controls/page.dart b/packages/flet/lib/src/controls/page.dart index 30f64641c6..1e1176716a 100644 --- a/packages/flet/lib/src/controls/page.dart +++ b/packages/flet/lib/src/controls/page.dart @@ -61,6 +61,7 @@ class _PageControlState extends State with WidgetsBindingObserver { ServiceRegistry? _userServices; bool? _prevOnKeyboardEvent; bool _keyboardHandlerSubscribed = false; + bool? _prevFullScreen; String? _prevViewRoutes; final Map _multiViews = {}; @@ -97,6 +98,7 @@ class _PageControlState extends State with WidgetsBindingObserver { _attachKeyboardListenerIfNeeded(); widget.control.addInvokeMethodListener(_invokeMethod); + _applyFullScreenFromControl(widget.control); } @override @@ -133,6 +135,7 @@ class _PageControlState extends State with WidgetsBindingObserver { _attachKeyboardListenerIfNeeded(); _loadFontsIfNeeded(FletBackend.of(context)); + _applyFullScreenFromControl(widget.control); } @override @@ -153,6 +156,24 @@ class _PageControlState extends State with WidgetsBindingObserver { super.dispose(); } + Future _applyFullScreenFromControl(Control control) async { + final fullScreen = control.getBool("full_screen", false)!; + if (_prevFullScreen != fullScreen) { + _prevFullScreen = fullScreen; + if (isDesktopPlatform() || isWebPlatform()) { + await setWindowFullScreen(fullScreen); + } else if (isMobilePlatform()) { + if (fullScreen) { + await SystemChrome.setEnabledSystemUIMode( + SystemUiMode.immersiveSticky); + } else { + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, + overlays: SystemUiOverlay.values); + } + } + } + } + Future _invokeMethod(String name, dynamic args) async { debugPrint("Page.$name($args)"); @@ -199,23 +220,6 @@ class _PageControlState extends State with WidgetsBindingObserver { await SystemChrome.setPreferredOrientations(orientations); } break; - case "set_fullscreen": - final value = parseBool(args["value"]); - if (value != null) { - if (isDesktopPlatform() || isWebPlatform()) { - await setWindowFullScreen(value); - } else if (isMobilePlatform()) { - if (value) { - await SystemChrome.setEnabledSystemUIMode( - SystemUiMode.immersiveSticky); - } else { - await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, - overlays: SystemUiOverlay.values); - } - } - } - break; - default: throw Exception("Unknown Page method: $name"); } @@ -393,11 +397,10 @@ class _PageControlState extends State with WidgetsBindingObserver { } Widget _buildApp(Control control, Widget? home) { - var platform = TargetPlatform.values.firstWhere( - (a) => - a.name.toLowerCase() == - control.getString("platform", "")!.toLowerCase(), - orElse: () => defaultTargetPlatform); + _applyFullScreenFromControl(control); + + var platform = + control.getTargetPlatform("platform", defaultTargetPlatform)!; var widgetsDesign = control.adaptive == true && (platform == TargetPlatform.iOS || platform == TargetPlatform.macOS) diff --git a/sdk/python/packages/flet/src/flet/controls/page.py b/sdk/python/packages/flet/src/flet/controls/page.py index bce2ab6193..076ca1387c 100644 --- a/sdk/python/packages/flet/src/flet/controls/page.py +++ b/sdk/python/packages/flet/src/flet/controls/page.py @@ -344,27 +344,10 @@ class Page(BasePage): Usage example [here](https://flet.dev/docs/cookbook/fonts#importing-fonts). """ - @property - def full_screen(self) -> bool: - """ - Requests fullscreen mode for the host window or browser. - - Set to `True` to hide the host system chrome; set to `False` to restore it. - """ - return getattr( - self, - "__full_screen", - self.page.window.full_screen if self.page.platform.is_desktop() else False, - ) - - @full_screen.setter - def full_screen(self, value: bool) -> None: - self.__full_screen = value - if self.page.platform.is_desktop() and not self.page.web: - self.page.window.full_screen = value - asyncio.create_task( - self._invoke_method("set_fullscreen", arguments={"value": value}) - ) + full_screen: bool = False + """ + Whether the app should run in full screen mode. + """ on_platform_brightness_change: Optional[ EventHandler[PlatformBrightnessChangeEvent] From 967f1fe19f8b0fce60dfb9b11795e20d032b53be Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Tue, 28 Oct 2025 20:27:52 +0100 Subject: [PATCH 7/8] improve docs --- packages/flet/lib/src/controls/page.dart | 1 + sdk/python/packages/flet/src/flet/controls/page.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/packages/flet/lib/src/controls/page.dart b/packages/flet/lib/src/controls/page.dart index 1e1176716a..80e1a1b3bf 100644 --- a/packages/flet/lib/src/controls/page.dart +++ b/packages/flet/lib/src/controls/page.dart @@ -156,6 +156,7 @@ class _PageControlState extends State with WidgetsBindingObserver { super.dispose(); } + /// Applies full screen mode to the app. Future _applyFullScreenFromControl(Control control) async { final fullScreen = control.getBool("full_screen", false)!; if (_prevFullScreen != fullScreen) { diff --git a/sdk/python/packages/flet/src/flet/controls/page.py b/sdk/python/packages/flet/src/flet/controls/page.py index 076ca1387c..7edbf99dd7 100644 --- a/sdk/python/packages/flet/src/flet/controls/page.py +++ b/sdk/python/packages/flet/src/flet/controls/page.py @@ -347,6 +347,11 @@ class Page(BasePage): full_screen: bool = False """ Whether the app should run in full screen mode. + + Difference to `Window.full_screen`: + This property is cross-platform, in contrast to [`full_screen`][flet.Window.] + property of [`Page.window`][flet.], which is only + available on desktop platforms (Windows, macOS and Linux). """ on_platform_brightness_change: Optional[ From 808d1e1d44e618e9c33c65371d13992559e2b25f Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Tue, 28 Oct 2025 21:06:08 +0100 Subject: [PATCH 8/8] Fix #5748 | Add docs for `KeyboardType` and `TextCapitalization` enums, refactor `parseTextInputType` --- packages/flet/lib/src/utils/form_field.dart | 44 ++---- .../src/flet/controls/material/textfield.py | 149 +++++++++++++++++- 2 files changed, 161 insertions(+), 32 deletions(-) diff --git a/packages/flet/lib/src/utils/form_field.dart b/packages/flet/lib/src/utils/form_field.dart index 4cbeda33f4..e5480c543d 100644 --- a/packages/flet/lib/src/utils/form_field.dart +++ b/packages/flet/lib/src/utils/form_field.dart @@ -24,32 +24,22 @@ FormFieldInputBorder? parseFormFieldInputBorder(String? value, TextInputType? parseTextInputType(String? value, [TextInputType? defaultValue]) { - switch (value?.toLowerCase()) { - case "datetime": - return TextInputType.datetime; - case "email": - return TextInputType.emailAddress; - case "multiline": - return TextInputType.multiline; - case "name": - return TextInputType.name; - case "none": - return TextInputType.none; - case "number": - return TextInputType.number; - case "phone": - return TextInputType.phone; - case "streetaddress": - return TextInputType.streetAddress; - case "text": - return TextInputType.text; - case "url": - return TextInputType.url; - case "visiblepassword": - return TextInputType.visiblePassword; - default: - return defaultValue; - } + const typeMap = { + "datetime": TextInputType.datetime, + "email": TextInputType.emailAddress, + "multiline": TextInputType.multiline, + "name": TextInputType.name, + "none": TextInputType.none, + "number": TextInputType.number, + "phone": TextInputType.phone, + "streetaddress": TextInputType.streetAddress, + "text": TextInputType.text, + "url": TextInputType.url, + "visiblepassword": TextInputType.visiblePassword, + "websearch": TextInputType.webSearch, + "twitter": TextInputType.twitter, + }; + return typeMap[value?.toLowerCase()] ?? defaultValue; } InputDecoration buildInputDecoration( @@ -86,7 +76,7 @@ InputDecoration buildInputDecoration( ?.replaceAll("{value_length}", valueLength.toString()) .replaceAll("{max_length}", maxLength?.toString() ?? "None") .replaceAll("{symbols_left}", - "${maxLength == null ? 'None' : (maxLength - (valueLength ?? 0))}"); + "${maxLength == null ? 'None' : (maxLength - (valueLength ?? 0))}"); } // error diff --git a/sdk/python/packages/flet/src/flet/controls/material/textfield.py b/sdk/python/packages/flet/src/flet/controls/material/textfield.py index 31326af67f..ed951e2f8d 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/textfield.py +++ b/sdk/python/packages/flet/src/flet/controls/material/textfield.py @@ -30,29 +30,168 @@ class KeyboardType(Enum): + """ + The type of information for which to optimize the text input control. + + On Android, behavior may vary across device and keyboard provider. + """ + NONE = "none" + """ + Prevents the OS from showing the on-screen virtual keyboard. + """ + TEXT = "text" + """ + Optimized for textual information. + + Requests the default platform keyboard. + """ + MULTILINE = "multiline" + """ + Optimized for multiline textual information. + + Requests the default platform keyboard, but accepts newlines when the + enter key is pressed. This is the input type used for all multiline text + fields. + """ + NUMBER = "number" + """ + Optimized for unsigned numerical information without a decimal point. + + Requests a default keyboard with ready access to the number keys. + """ + PHONE = "phone" + """ + Optimized for telephone numbers. + + Requests a keyboard with ready access to the number keys, `"*"`, and `"#"`. + """ + DATETIME = "datetime" + """ + Optimized for date and time information. + + - On iOS, requests the default keyboard. + - On Android, requests a keyboard with ready + access to the number keys, `":"`, and `"-"`. + """ + EMAIL = "email" + """ + Optimized for email addresses. + + Requests a keyboard with ready access to the `"@"` and `"."` keys. + """ + URL = "url" + """ + Optimized for URLs. + + Requests a keyboard with ready access to the `"/"` and `"."` keys. + """ + VISIBLE_PASSWORD = "visiblePassword" + """ + Optimized for passwords that are visible to the user. + + Requests a keyboard with ready access to both letters and numbers. + """ + NAME = "name" + """ + Optimized for a person's name. + + - On iOS, requests the [UIKeyboardType.namePhonePad](https://developer.apple.com/documentation/uikit/uikeyboardtype/namephonepad) + keyboard, a keyboard optimized for entering a person’s name or phone number. + Does not support auto-capitalization. + - On Android, requests a keyboard optimized for + [TYPE_TEXT_VARIATION_PERSON_NAME](https://developer.android.com/reference/android/text/InputType#TYPE_TEXT_VARIATION_PERSON_NAME). + """ # noqa: E501 + STREET_ADDRESS = "streetAddress" + """ + Optimized for postal mailing addresses. + + - On iOS, requests the default keyboard. + - On Android, requests a keyboard optimized for + [TYPE_TEXT_VARIATION_POSTAL_ADDRESS](https://developer.android.com/reference/android/text/InputType#TYPE_TEXT_VARIATION_POSTAL_ADDRESS). + """ # noqa: E501 + + WEB_SEARCH = "webSearch" + """ + Optimized for web searches. + + Requests a keyboard that includes keys useful for web searches as well as URLs. + + - On iOS, requests a default keyboard with ready access to the `"."` key. + In contrast to [`URL`][(c).], a space bar is available. + - On Android this is remapped to the [`URL`][(c).] keyboard type as it always + shows a space bar. + """ + + TWITTER = "twitter" + """ + Optimized for social media. + + Requests a keyboard that includes keys useful for handles and tags. + + - On iOS, requests a default keyboard with ready access to the `"@"` and `"#"` keys. + - On Android this is remapped to the [`EMAIL`][(c).] keyboard type as it + always shows the `"@"` key. + """ class TextCapitalization(Enum): + """ + Configures how the platform keyboard will select an uppercase or + lowercase keyboard. + + Only supports text keyboards, other keyboard types will ignore this + configuration. Capitalization is locale-aware. + """ + CHARACTERS = "characters" + """ + Uppercase keyboard for each character. + + Info: + Corresponds to `InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS` on Android, and + `UITextAutocapitalizationTypeAllCharacters` on iOS. + """ + WORDS = "words" + """ + Uppercase keyboard for the first letter of each word. + + Info: + Corresponds to `InputType.TYPE_TEXT_FLAG_CAP_WORDS` on Android, and + `UITextAutocapitalizationTypeWords` on iOS. + """ + SENTENCES = "sentences" + """ + Uppercase keyboard for the first letter of each sentence. + + Info: + Corresponds to `InputType.TYPE_TEXT_FLAG_CAP_SENTENCES` on Android, and + `UITextAutocapitalizationTypeSentences` on iOS. + """ + + NONE = "none" + """ + Lowercase keyboard. + """ @dataclass class InputFilter: """ - `InputFilter` class. + An input filter that uses a regular expression to allow or deny/block certain + patterns in the input. """ regex_string: str @@ -79,7 +218,7 @@ class InputFilter: """ Whether this regular expression matches multiple lines. - If the regexp does match multiple lines, the "^" and "$" characters match the + If the regexp does match multiple lines, the `"^"` and `"$"` characters match the beginning and end of lines. If not, the characters match the beginning and end of the input. """ @@ -100,10 +239,10 @@ class InputFilter: dot_all: bool = False """ - Whether "." in this regular expression matches line terminators. + Whether `"."` in this regular expression matches line terminators. - When false, the "." character matches a single character, unless that character - terminates a line. When true, then the "." character will match any single + When false, the `"."` character matches a single character, unless that character + terminates a line. When true, then the `"."` character will match any single character including line terminators. This feature is distinct from `multiline`. They affect the behavior of different