From 7603b68981875d4ed2b57888bcb651a076c36b48 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 25 May 2026 00:56:36 +0200 Subject: [PATCH 1/7] initial commit --- CHANGELOG.md | 1 + packages/flet/lib/src/services/file_picker.dart | 11 +++++++---- packages/flet/pubspec.yaml | 2 +- .../flet/src/flet/controls/services/file_picker.py | 5 +++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2140e0b417..a763dcd5b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Bug fixes +* Fix `FilePicker.pick_files()` on web for slow network shares or slow machines: pass `cancel_upload_on_window_blur=False` to prevent valid file selections from being reported as cancelled when the browser window loses focus during file picking ([#771](https://github.com/flet-dev/flet/issues/771)) by @ndonkoHenri. * Fix cross-tab session contamination on Flet web: opening the same app URL in a duplicated browser tab no longer steals the original tab's output connection via `sessionStorage`-cloned `_flet_session_id`. `REGISTER_CLIENT` now rejects session reuse when the existing session still has a live `connection`, allocating a fresh session for the second tab while preserving legitimate single-tab reconnect after refresh or network blip (where `connection` is already `None`) ([#6512](https://github.com/flet-dev/flet/issues/6512), [#6513](https://github.com/flet-dev/flet/pull/6513)) by @ihmily. ## 0.85.1 diff --git a/packages/flet/lib/src/services/file_picker.dart b/packages/flet/lib/src/services/file_picker.dart index 609ba20284..627e03fa31 100644 --- a/packages/flet/lib/src/services/file_picker.dart +++ b/packages/flet/lib/src/services/file_picker.dart @@ -36,6 +36,8 @@ class FilePickerService extends FletService { ?.map((e) => e.toString()) .toList(); var withData = parseBool(args["with_data"], false)!; + var cancelUploadOnWindowBlur = + parseBool(args["cancel_upload_on_window_blur"], true)!; var srcBytes = args["src_bytes"]; if (allowedExtensions != null && allowedExtensions.isNotEmpty) { @@ -48,7 +50,7 @@ class FilePickerService extends FletService { uploadFiles(files, control.backend.pageUri); } case "pick_files": - _files = (await FilePicker.platform.pickFiles( + _files = (await FilePicker.pickFiles( dialogTitle: dialogTitle, initialDirectory: initialDirectory, lockParentWindow: true, @@ -56,7 +58,8 @@ class FilePickerService extends FletService { allowedExtensions: allowedExtensions, allowMultiple: args["allow_multiple"], withData: withData, - withReadStream: !withData)) + withReadStream: !withData, + cancelUploadOnWindowBlur: cancelUploadOnWindowBlur)) ?.files; return _files != null ? _files!.asMap().entries.map((file) { @@ -79,7 +82,7 @@ class FilePickerService extends FletService { throw Exception( "\"file_name\" is required when saving a file on Web."); } - return await FilePicker.platform.saveFile( + return await FilePicker.saveFile( dialogTitle: dialogTitle, fileName: args["file_name"] != null || !isIOSMobile() ? args["file_name"] @@ -93,7 +96,7 @@ class FilePickerService extends FletService { if (kIsWeb) { throw Exception("Get Directory Path dialog is not supported on web."); } - return await FilePicker.platform.getDirectoryPath( + return await FilePicker.getDirectoryPath( dialogTitle: dialogTitle, initialDirectory: initialDirectory, lockParentWindow: true, diff --git a/packages/flet/pubspec.yaml b/packages/flet/pubspec.yaml index d1aa2ae337..d726a314e1 100644 --- a/packages/flet/pubspec.yaml +++ b/packages/flet/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: cupertino_icons: ^1.0.6 device_info_plus: ^12.3.0 equatable: ^2.0.3 - file_picker: ^10.3.10 + file_picker: ^11.0.2 flutter_highlight: ^0.7.0 flutter_markdown_plus: ^1.0.7 flutter_markdown_plus_latex: ^1.0.5 diff --git a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py index ba2e954603..0c2ee88113 100644 --- a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py @@ -308,6 +308,7 @@ async def pick_files( allowed_extensions: Optional[list[str]] = None, allow_multiple: bool = False, with_data: bool = False, + cancel_upload_on_window_blur: bool = True, ) -> list[FilePickerFile]: """ Opens a pick file dialog. @@ -323,6 +324,9 @@ async def pick_files( allow_multiple: Allow the selection of multiple files at once. with_data: Read selected file contents into :attr:`~flet.FilePickerFile.bytes`. + cancel_upload_on_window_blur: Web-only. Whether to treat browser + window blur as a cancelled selection. Set to `False` to avoid + losing valid selections on slow networks or slow machines. allowed_extensions: The allowed file extensions. Has effect only if `file_type` is :attr:`flet.FilePickerFileType.CUSTOM`. @@ -338,6 +342,7 @@ async def pick_files( "allowed_extensions": allowed_extensions, "allow_multiple": allow_multiple, "with_data": with_data, + "cancel_upload_on_window_blur": cancel_upload_on_window_blur, }, timeout=3600, ) From b5edc2a7d21d65f5afa7b80e271b0d0b3be59d2c Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 25 May 2026 01:28:14 +0200 Subject: [PATCH 2/7] Add `compression_quality` to `FilePicker.pick_files()` --- CHANGELOG.md | 1 + packages/flet/lib/src/services/file_picker.dart | 2 ++ .../packages/flet/src/flet/controls/services/file_picker.py | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a763dcd5b6..9572bec51f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Improvements +* Add `compression_quality` to `FilePicker.pick_files()` for selecting the image compression quality used by supported platforms by @ndonkoHenri. * `flet.Router`'s default `on_view_pop` now navigates to the matched chain's parent (`chain[-2].resolved_path`) instead of `views[-2].route`, which is robust against apps that share a `View.route` value between sibling tab roots to suppress switch transitions. Apps that install their own `page.on_view_pop` before `page.render_views()` still take precedence. Each sub-chain (base + modal) renders with its own `LocationInfo`, so `is_route_active(...)` inside a base view sees the base URL while a global modal is open over it ([#6516](https://github.com/flet-dev/flet/pull/6516)) by @FeodorFitsner. ### Bug fixes diff --git a/packages/flet/lib/src/services/file_picker.dart b/packages/flet/lib/src/services/file_picker.dart index 627e03fa31..1c7c0560e9 100644 --- a/packages/flet/lib/src/services/file_picker.dart +++ b/packages/flet/lib/src/services/file_picker.dart @@ -38,6 +38,7 @@ class FilePickerService extends FletService { var withData = parseBool(args["with_data"], false)!; var cancelUploadOnWindowBlur = parseBool(args["cancel_upload_on_window_blur"], true)!; + var compressionQuality = parseInt(args["compression_quality"], 0)!; var srcBytes = args["src_bytes"]; if (allowedExtensions != null && allowedExtensions.isNotEmpty) { @@ -56,6 +57,7 @@ class FilePickerService extends FletService { lockParentWindow: true, type: fileType, allowedExtensions: allowedExtensions, + compressionQuality: compressionQuality, allowMultiple: args["allow_multiple"], withData: withData, withReadStream: !withData, diff --git a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py index 0c2ee88113..a187a4c615 100644 --- a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py @@ -308,6 +308,7 @@ async def pick_files( allowed_extensions: Optional[list[str]] = None, allow_multiple: bool = False, with_data: bool = False, + compression_quality: int = 0, cancel_upload_on_window_blur: bool = True, ) -> list[FilePickerFile]: """ @@ -324,6 +325,8 @@ async def pick_files( allow_multiple: Allow the selection of multiple files at once. with_data: Read selected file contents into :attr:`~flet.FilePickerFile.bytes`. + compression_quality: Image compression quality from `0` to `100`. + `0` disables compression. cancel_upload_on_window_blur: Web-only. Whether to treat browser window blur as a cancelled selection. Set to `False` to avoid losing valid selections on slow networks or slow machines. @@ -342,6 +345,7 @@ async def pick_files( "allowed_extensions": allowed_extensions, "allow_multiple": allow_multiple, "with_data": with_data, + "compression_quality": compression_quality, "cancel_upload_on_window_blur": cancel_upload_on_window_blur, }, timeout=3600, From ecb074b77f9d53c4364429d0efb4f52cb8b0cc85 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 25 May 2026 01:29:37 +0200 Subject: [PATCH 3/7] Improve `FilePicker.save_file()` documentation --- CHANGELOG.md | 4 ++++ .../flet/src/flet/controls/services/file_picker.py | 9 ++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9572bec51f..2b118af171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ * Add `compression_quality` to `FilePicker.pick_files()` for selecting the image compression quality used by supported platforms by @ndonkoHenri. * `flet.Router`'s default `on_view_pop` now navigates to the matched chain's parent (`chain[-2].resolved_path`) instead of `views[-2].route`, which is robust against apps that share a `View.route` value between sibling tab roots to suppress switch transitions. Apps that install their own `page.on_view_pop` before `page.render_views()` still take precedence. Each sub-chain (base + modal) renders with its own `LocationInfo`, so `is_route_active(...)` inside a base view sees the base URL while a global modal is open over it ([#6516](https://github.com/flet-dev/flet/pull/6516)) by @FeodorFitsner. +### Documentation + +* Improve `FilePicker.save_file()` documentation: on desktop, passing `src_bytes` writes those bytes to the selected file by @ndonkoHenri. + ### Bug fixes * Fix `FilePicker.pick_files()` on web for slow network shares or slow machines: pass `cancel_upload_on_window_blur=False` to prevent valid file selections from being reported as cancelled when the browser window loses focus during file picking ([#771](https://github.com/flet-dev/flet/issues/771)) by @ndonkoHenri. diff --git a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py index a187a4c615..67691a7777 100644 --- a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py @@ -258,9 +258,9 @@ async def save_file( name to save a file. Note: - - On desktop this method only opens a dialog for the user to select - a location and file name, and returns the chosen path. The file - itself is not created or saved. + - On desktop, this method opens a dialog for the user to select a + location and file name. If `src_bytes` is provided, those bytes + are written to the selected file. Args: dialog_title: The title of the dialog window. @@ -270,8 +270,7 @@ async def save_file( src_bytes: The contents of a file. Must be provided in web, iOS or Android modes. allowed_extensions: The allowed file extensions. Has effect only if - `file_type` is - :attr:`flet.FilePickerFileType.CUSTOM`. + `file_type` is :attr:`flet.FilePickerFileType.CUSTOM`. Raises: ValueError: If `src_bytes` is not provided, when called in web mode, From 63828363204b33dff62c81491d22ebf5ead01003 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 25 May 2026 01:54:46 +0200 Subject: [PATCH 4/7] improve `FloatingActionButtonLocation` docs --- .../packages/flet/src/flet/controls/types.py | 137 +++++++++++++++++- 1 file changed, 134 insertions(+), 3 deletions(-) diff --git a/sdk/python/packages/flet/src/flet/controls/types.py b/sdk/python/packages/flet/src/flet/controls/types.py index 8a4fe9f186..a55da63fe6 100644 --- a/sdk/python/packages/flet/src/flet/controls/types.py +++ b/sdk/python/packages/flet/src/flet/controls/types.py @@ -675,30 +675,161 @@ class DeviceOrientation(Enum): class FloatingActionButtonLocation(Enum): """ Defines a position for the :class:`~flet.FloatingActionButton`. - - See [FloatingActionButtonLocation](https://api.flutter.dev/flutter/material/FloatingActionButtonLocation-class.html) - from Flutter documentation for placement location examples. """ # noqa: E501 CENTER_DOCKED = "centerDocked" + """ + Centered :class:`~flet.FloatingActionButton`, floating over a bottom navigation \ + control so the button's center lines up with the top of that control. + + Not typically useful for apps without a bottom navigation control. + """ + CENTER_FLOAT = "centerFloat" + """ + Centered :class:`~flet.FloatingActionButton`, floating at the bottom of the \ + screen. + + Use :attr:`MINI_CENTER_FLOAT` for mini buttons. + """ + CENTER_TOP = "centerTop" + """ + Centered :class:`~flet.FloatingActionButton`, floating over the transition \ + between the :class:`~flet.AppBar` and the page body. + + Not typically useful for apps without a top :class:`~flet.AppBar`. + """ + END_CONTAINED = "endContained" + """ + End-aligned :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button lines up with that control's center. + + Not typically useful for apps with a :class:`~flet.NavigationBar` or a \ + non-Material 3 :class:`~flet.BottomAppBar`. + """ + END_DOCKED = "endDocked" + """ + End-aligned :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Not typically useful for apps without a bottom navigation control. + """ + END_FLOAT = "endFloat" + """ + End-aligned :class:`~flet.FloatingActionButton`, floating at the bottom of the \ + screen. + + This is the default alignment in Material apps. Use :attr:`MINI_END_FLOAT` for \ + mini buttons. + """ + END_TOP = "endTop" + """ + End-aligned :class:`~flet.FloatingActionButton`, floating over the transition \ + between the :class:`~flet.AppBar` and the page body. + + Not typically useful for apps without a top :class:`~flet.AppBar`. + """ + MINI_CENTER_DOCKED = "miniCenterDocked" + """ + Centered mini :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Intended for use with mini buttons. + """ + MINI_CENTER_FLOAT = "miniCenterFloat" + """ + Centered mini :class:`~flet.FloatingActionButton`, floating at the bottom of the \ + screen. + + Intended for use with mini buttons. + """ + MINI_CENTER_TOP = "miniCenterTop" + """ + Centered mini :class:`~flet.FloatingActionButton`, floating over the transition \ + between the :class:`~flet.AppBar` and the page body. + + Intended for use with mini buttons. + """ + MINI_END_DOCKED = "miniEndDocked" + """ + End-aligned mini :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Intended for use with mini buttons. + """ + MINI_END_FLOAT = "miniEndFloat" + """ + End-aligned mini :class:`~flet.FloatingActionButton`, floating at the bottom of \ + the screen. + + Intended for use with mini buttons. + """ + MINI_END_TOP = "miniEndTop" + """ + End-aligned mini :class:`~flet.FloatingActionButton`, floating over the \ + transition between the :class:`~flet.AppBar` and the page body. + + Intended for use with mini buttons. + """ + MINI_START_DOCKED = "miniStartDocked" + """ + Start-aligned mini :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Intended for use with mini buttons. + """ + MINI_START_FLOAT = "miniStartFloat" + """ + Start-aligned mini :class:`~flet.FloatingActionButton`, floating at the bottom \ + of the screen. + + Intended for use with mini buttons. + """ + MINI_START_TOP = "miniStartTop" + """ + Start-aligned mini :class:`~flet.FloatingActionButton`, floating over the \ + transition between the :class:`~flet.AppBar` and the page body. + + Intended for use with mini buttons. + """ + START_DOCKED = "startDocked" + """ + Start-aligned :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Not typically useful for apps without a bottom navigation control. + """ + START_FLOAT = "startFloat" + """ + Start-aligned :class:`~flet.FloatingActionButton`, floating at the bottom of the \ + screen. + + Use :attr:`MINI_START_FLOAT` for mini buttons. + """ + START_TOP = "startTop" + """ + Start-aligned :class:`~flet.FloatingActionButton`, floating over the transition \ + between the :class:`~flet.AppBar` and the page body. + + Not typically useful for apps without a top :class:`~flet.AppBar`. + """ class AppLifecycleState(Enum): From 20685710240d7d4018cbc82662cbbfa77ad427f4 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Thu, 11 Jun 2026 14:12:33 +0200 Subject: [PATCH 5/7] update changelog to reference PR #6573 --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 141032925a..78de1305b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,15 @@ ### Improvements -* Add `compression_quality` to `FilePicker.pick_files()` for selecting the image compression quality used by supported platforms by @ndonkoHenri. +* Add `compression_quality` to `FilePicker.pick_files()` for selecting the image compression quality used by supported platforms ([#6573](https://github.com/flet-dev/flet/pull/6573)) by @ndonkoHenri. ### Documentation -* Improve `FilePicker.save_file()` documentation: on desktop, passing `src_bytes` writes those bytes to the selected file by @ndonkoHenri. +* Improve `FilePicker.save_file()` documentation: on desktop, passing `src_bytes` writes those bytes to the selected file ([#6573](https://github.com/flet-dev/flet/pull/6573)) by @ndonkoHenri. ### Bug fixes -* Fix `FilePicker.pick_files()` on web for slow network shares or slow machines: pass `cancel_upload_on_window_blur=False` to prevent valid file selections from being reported as cancelled when the browser window loses focus during file picking ([#771](https://github.com/flet-dev/flet/issues/771)) by @ndonkoHenri. +* Fix `FilePicker.pick_files()` on web for slow network shares or slow machines: pass `cancel_upload_on_window_blur=False` to prevent valid file selections from being reported as cancelled when the browser window loses focus during file picking ([#771](https://github.com/flet-dev/flet/issues/771), [#6573](https://github.com/flet-dev/flet/pull/6573)) by @ndonkoHenri. ## 0.85.3 From fe0cba362e7f48e940922e2f96407f24b00747dd Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Thu, 11 Jun 2026 14:25:30 +0200 Subject: [PATCH 6/7] validate `compression_quality` range in `FilePicker.pick_files()` --- .../flet/src/flet/controls/services/file_picker.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py index 67691a7777..7139298e29 100644 --- a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py @@ -334,7 +334,16 @@ async def pick_files( Returns: A list of selected files. + + Raises: + ValueError: If `compression_quality` is not between + `0` and `100` inclusive. """ + if not (0 <= compression_quality <= 100): + raise ValueError( + "compression_quality must be between 0 and 100 inclusive, " + f"got {compression_quality}." + ) files = await self._invoke_method( "pick_files", { From b1317b455120f09d8eff33f7726a4d60cdca8ab5 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Thu, 11 Jun 2026 23:34:26 +0200 Subject: [PATCH 7/7] changelog v0.86.0 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78de1305b4..3c07cc4dd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ -## 0.85.4 +## 0.86.0 -### Improvements +### New features * Add `compression_quality` to `FilePicker.pick_files()` for selecting the image compression quality used by supported platforms ([#6573](https://github.com/flet-dev/flet/pull/6573)) by @ndonkoHenri.