From 4b1bc44acf935142dc38f057d586ac5b2de39aaa Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Fri, 17 Jul 2026 18:24:17 +0200 Subject: [PATCH 1/9] Remove deprecated DragTargetEvent coordinates and Video playlist/controls APIs Removes APIs deprecated in 0.85.0 as part of the pre-v1 deprecation cleanup: - DragTargetEvent.x/.y/.offset -> use local_position / global_position - Video.show_controls -> set controls=None to hide controls - Video.playlist_add()/playlist_remove() -> mutate Video.playlist directly Also simplifies the flet_video Dart control (the show_controls gate is now dead code) and updates the root + flet-video changelogs and the 0.85.0 migration guides. --- CHANGELOG.md | 8 +++ sdk/python/packages/flet-video/CHANGELOG.md | 7 +++ .../flet-video/src/flet_video/video.py | 50 +------------------ .../src/flutter/flet_video/lib/src/video.dart | 4 +- .../src/flet/controls/core/drag_target.py | 49 ------------------ ...eprecated-drag-target-event-coordinates.md | 7 ++- .../v0-85-0/deprecated-video-apis.md | 7 ++- 7 files changed, 23 insertions(+), 109 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec1f39e280..a03d7a8883 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## Unreleased + +### Breaking changes + +* Remove `DragTargetEvent.x`, `DragTargetEvent.y`, and `DragTargetEvent.offset` (deprecated in `0.85.0`). Use `DragTargetEvent.local_position` for target-relative coordinates or `DragTargetEvent.global_position` for global coordinates ([#6401](https://github.com/flet-dev/flet/pull/6401)) by @ndonkoHenri. +* Remove `Video.show_controls` (deprecated in `0.85.0`). Set `Video.controls` to `None` to hide controls ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. +* Remove `Video.playlist_add()` and `Video.playlist_remove()` (deprecated in `0.85.0`). Mutate `Video.playlist` directly with list methods such as `append()` and `pop()` ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. + ## 0.86.1 ### Improvements diff --git a/sdk/python/packages/flet-video/CHANGELOG.md b/sdk/python/packages/flet-video/CHANGELOG.md index 63d23a9fb5..bac8bea77a 100644 --- a/sdk/python/packages/flet-video/CHANGELOG.md +++ b/sdk/python/packages/flet-video/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## Unreleased + +### Removed + +- `Video.show_controls` (deprecated in 0.85.0); set `Video.controls` to `None` to hide controls ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. +- `Video.playlist_add()` and `Video.playlist_remove()` (deprecated in 0.85.0); mutate `Video.playlist` directly with list methods such as `append()` and `pop()` ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. + ## 0.85.0 ### Added diff --git a/sdk/python/packages/flet-video/src/flet_video/video.py b/sdk/python/packages/flet-video/src/flet_video/video.py index ccdaa38919..986776244f 100644 --- a/sdk/python/packages/flet-video/src/flet_video/video.py +++ b/sdk/python/packages/flet-video/src/flet_video/video.py @@ -3,11 +3,9 @@ """ from dataclasses import field -from typing import Annotated, Optional, Union +from typing import Optional, Union import flet as ft -from flet.utils.deprecated import deprecated -from flet.utils.validation import V from flet_video.types import ( AdaptiveVideoControls, PlaylistMode, @@ -61,19 +59,6 @@ class Video(ft.LayoutControl): Whether the video should start playing automatically. """ - show_controls: Annotated[ - Optional[bool], - V.deprecated( - version="0.85.0", - delete_version="0.88.0", - reason="Use controls=None to hide controls.", - docs_reason="To hide controls, instead set :attr:`controls` to `None`.", - ), - ] = None - """ - Whether to show the video player :attr:`controls`. - """ - controls: Optional[ Union[ VideoControls, @@ -96,10 +81,6 @@ class Video(ft.LayoutControl): :attr:`VideoControlsMode.NORMAL` controls are reused before falling back to :attr:`VideoControlsMode.DEFAULT`. A mode value of `None` hides controls for that mode only. - - Note: - During the :attr:`show_controls` deprecation period, `show_controls=False` - hides controls even when this property is set. """ fullscreen: bool = False @@ -297,35 +278,6 @@ async def jump_to(self, media_index: int): arguments={"media_index": media_index}, ) - @deprecated( - reason="Use playlist.append(media) instead.", - docs_reason="Use :attr:`playlist` directly, for example `video.playlist.append(media)`.", # noqa: E501 - version="0.85.0", - delete_version="0.88.0", - show_parentheses=True, - ) - async def playlist_add(self, media: VideoMedia): - """Appends/Adds the provided `media` to the `playlist`.""" - if not media.resource: - raise ValueError("media has no resource") - self.playlist.append(media) - - @deprecated( - reason="Use playlist.pop(media_index) instead.", - docs_reason="Use :attr:`playlist` directly, for example `video.playlist.pop(media_index)`.", # noqa: E501 - version="0.85.0", - delete_version="0.88.0", - show_parentheses=True, - ) - async def playlist_remove(self, media_index: int): - """Removes the provided `media` from the `playlist`.""" - playlist_length = len(self.playlist) - if not (-playlist_length <= media_index < playlist_length): - raise IndexError("media_index is out of range") - if media_index < 0: - media_index = playlist_length + media_index - self.playlist.pop(media_index) - async def is_playing(self) -> bool: """ Returns: diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart index 03eceb7c45..4f31e50f2b 100644 --- a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart @@ -337,9 +337,7 @@ class _VideoControlState extends State with FletStoreMixin { var playbackRate = widget.control.getDouble("playback_rate"); var playlist = widget.control.get("playlist"); var shufflePlaylist = widget.control.getBool("shuffle_playlist"); - var controls = widget.control.getBool("show_controls", true)! - ? widget.control.get("controls") - : null; + var controls = widget.control.get("controls"); var playlistMode = parsePlaylistMode(widget.control.getString("playlist_mode")); var fullscreen = widget.control.getBool("fullscreen", false)!; diff --git a/sdk/python/packages/flet/src/flet/controls/core/drag_target.py b/sdk/python/packages/flet/src/flet/controls/core/drag_target.py index f5bce32bdc..69ec990afd 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/drag_target.py +++ b/sdk/python/packages/flet/src/flet/controls/core/drag_target.py @@ -6,7 +6,6 @@ from flet.controls.control_event import Event, EventHandler from flet.controls.core.draggable import Draggable from flet.controls.transform import Offset -from flet.utils.deprecated import deprecated from flet.utils.validation import V __all__ = [ @@ -73,54 +72,6 @@ def __post_init__(self): if self.src_id is not None: self.src = cast(Draggable, self.page.get_control(self.src_id)) - @property - @deprecated( - reason="Use `local_position.x` for target-relative coordinates or " - "`global_position.x` for global coordinates instead.", - docs_reason="Use [`local_position.x`][flet.DragTargetEvent.local_position] for target-relative coordinates or " # noqa: E501 - "[`global_position.x`][flet.DragTargetEvent.global_position] for global coordinates instead.", # noqa: E501 - version="0.85.0", - delete_version="0.88.0", - ) - def x(self) -> float: - """ - Horizontal pointer position in the global coordinate space. - """ - - return self.global_position.x - - @property - @deprecated( - reason="Use `local_position.y` for target-relative coordinates or " - "`global_position.y` for global coordinates instead.", - docs_reason="Use [`local_position.y`][flet.DragTargetEvent.local_position] for target-relative coordinates or " # noqa: E501 - "[`global_position.y`][flet.DragTargetEvent.global_position] for global coordinates instead.", # noqa: E501 - version="0.85.0", - delete_version="0.88.0", - ) - def y(self) -> float: - """ - Vertical pointer position in the global coordinate space. - """ - - return self.global_position.y - - @property - @deprecated( - reason="Use `local_position` for target-relative coordinates or " - "`global_position` for global coordinates instead.", - docs_reason="Use [`local_position`][flet.DragTargetEvent.local_position] for target-relative coordinates or " # noqa: E501 - "[`global_position`][flet.DragTargetEvent.global_position] for global coordinates instead.", # noqa: E501 - version="0.85.0", - delete_version="0.88.0", - ) - def offset(self) -> Offset: - """ - Pointer position in global coordinates. - """ - - return self.global_position - @dataclass class DragTargetLeaveEvent(Event["DragTarget"]): diff --git a/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md b/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md index 51a70b0207..a7865b6a8c 100644 --- a/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md +++ b/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md @@ -13,9 +13,8 @@ The [breaking changes and deprecations index](../index.md) lists the guides crea ## Summary -Flet 0.85.0 deprecated [`DragTargetEvent.x`][flet.DragTargetEvent.x], -[`DragTargetEvent.y`][flet.DragTargetEvent.y], and -[`DragTargetEvent.offset`][flet.DragTargetEvent.offset]. +Flet 0.85.0 deprecated `DragTargetEvent.x`, `DragTargetEvent.y`, and +`DragTargetEvent.offset`. Use [`DragTargetEvent.local_position`][flet.DragTargetEvent.local_position] for target-relative coordinates, or @@ -56,7 +55,7 @@ If your code needs page-level coordinates instead, use ## Timeline - Deprecated in: `0.85.0` -- Removal in: `0.88.0` +- Removed in: Unreleased ## References diff --git a/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md b/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md index 10580e1164..38b4c35f44 100644 --- a/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md +++ b/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md @@ -13,9 +13,8 @@ The [breaking changes and deprecations index](../index.md) lists the guides crea ## Summary -Flet 0.85.0 deprecated [`Video.show_controls`][flet_video.Video.show_controls], -[`Video.playlist_add()`][flet_video.Video.playlist_add], and -[`Video.playlist_remove()`][flet_video.Video.playlist_remove]. +Flet 0.85.0 deprecated `Video.show_controls`, `Video.playlist_add()`, and +`Video.playlist_remove()`. Use [`Video.controls`][flet_video.Video.controls] to configure or hide video controls. Mutate [`Video.playlist`][flet_video.Video.playlist] directly with @@ -75,7 +74,7 @@ been added to the page. ## Timeline - Deprecated in: `0.85.0` -- Removal in: `0.88.0` +- Removed in: Unreleased ## References From 6f260f3653a8ad4ca9e3a131a7068be6763303f2 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Fri, 17 Jul 2026 18:24:17 +0200 Subject: [PATCH 2/9] Remove deprecated FletApp startup-screen properties and --clear-cache flag Continues the pre-1.0 deprecation cleanup: - Remove FletApp.show_app_startup_screen and FletApp.app_startup_screen_message (deprecated in 0.86.0) -> use boot_screen_options - Remove the --clear-cache flag of flet build / flet debug (deprecated in 0.86.0) -> use the flet clean command; the flag's build/flutter deletion behavior is removed with it - Finalize the cleanup changelog version placeholder from 'Unreleased' to 1.0.0 (root + flet-video changelogs and the 0.85.0/0.86.0 migration-guide timelines) --- CHANGELOG.md | 4 +- .../src/flet_cli/commands/build_base.py | 35 ------------ sdk/python/packages/flet-video/CHANGELOG.md | 2 +- .../flet/src/flet/controls/core/flet_app.py | 57 ------------------- ...eprecated-drag-target-event-coordinates.md | 2 +- .../v0-85-0/deprecated-video-apis.md | 2 +- .../v0-86-0/deprecated-clear-cache-flag.md | 2 +- 7 files changed, 7 insertions(+), 97 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a03d7a8883..48e13943da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ -## Unreleased +## 1.0.0 ### Breaking changes * Remove `DragTargetEvent.x`, `DragTargetEvent.y`, and `DragTargetEvent.offset` (deprecated in `0.85.0`). Use `DragTargetEvent.local_position` for target-relative coordinates or `DragTargetEvent.global_position` for global coordinates ([#6401](https://github.com/flet-dev/flet/pull/6401)) by @ndonkoHenri. * Remove `Video.show_controls` (deprecated in `0.85.0`). Set `Video.controls` to `None` to hide controls ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. * Remove `Video.playlist_add()` and `Video.playlist_remove()` (deprecated in `0.85.0`). Mutate `Video.playlist` directly with list methods such as `append()` and `pop()` ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. +* Remove `FletApp.show_app_startup_screen` and `FletApp.app_startup_screen_message` (deprecated in `0.86.0`). Use `FletApp.boot_screen_options` instead, e.g. `boot_screen_options={'spinner_size': 30}` or `boot_screen_options={'startup_message': '...'}` by @ndonkoHenri. +* Remove the `--clear-cache` flag of `flet build` and `flet debug` (deprecated in `0.86.0`). Use the `flet clean` command instead ([#6233](https://github.com/flet-dev/flet/issues/6233)) by @ndonkoHenri. ## 0.86.1 diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py index 5eb5ef62cd..1305894051 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py @@ -17,7 +17,6 @@ import flet.version import flet_cli.utils.processes as processes from flet.utils import copy_tree, slugify -from flet.utils.deprecated import deprecated_warning from flet_cli.commands.flutter_base import ( BaseFlutterCommand, console, @@ -285,14 +284,6 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: help="Files and/or directories to exclude from the package" "; can be used multiple times", ) - parser.add_argument( - "--clear-cache", - dest="clear_cache", - action="store_true", - default=None, - help="Remove any existing build cache before starting the build process. " - "Deprecated: use the `flet clean` command instead", - ) parser.add_argument( "--project", dest="project_name", @@ -710,21 +701,6 @@ def handle(self, options: argparse.Namespace) -> None: super().handle(options) - if getattr(self.options, "clear_cache", None): - deprecated_warning( - name="--clear-cache", - reason="Use the `flet clean` command instead.", - version="0.86.0", - delete_version="0.89.0", - type="flag", - ) - console.print( - "Warning: the `--clear-cache` flag is deprecated since version " - "0.86.0 and will be removed in version 0.89.0. " - "Use the `flet clean` command instead.", - style=warning_style, - ) - if "target_platform" in self.options: self.target_platform = self.options.target_platform @@ -1517,17 +1493,6 @@ def create_flutter_project(self, second_pass=False): hash_changed = hash.has_changed() if hash_changed: - # if options.clear_cache is set, delete any existing Flutter bootstrap - # project directory - if ( - self.options.clear_cache - and self.flutter_dir.exists() - and not second_pass - ): - if self.verbose > 1: - console.log(f"Deleting {self.flutter_dir}", style=verbose2_style) - shutil.rmtree(self.flutter_dir, ignore_errors=True) - # create a new Flutter bootstrap project directory, if non-existent if not second_pass: self.flutter_dir.mkdir(parents=True, exist_ok=True) diff --git a/sdk/python/packages/flet-video/CHANGELOG.md b/sdk/python/packages/flet-video/CHANGELOG.md index bac8bea77a..c6a0107df3 100644 --- a/sdk/python/packages/flet-video/CHANGELOG.md +++ b/sdk/python/packages/flet-video/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## Unreleased +## 1.0.0 ### Removed diff --git a/sdk/python/packages/flet/src/flet/controls/core/flet_app.py b/sdk/python/packages/flet/src/flet/controls/core/flet_app.py index 5a38f74481..ccf18ccdf7 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/flet_app.py +++ b/sdk/python/packages/flet/src/flet/controls/core/flet_app.py @@ -4,7 +4,6 @@ from flet.controls.base_control import control from flet.controls.control_event import ControlEventHandler, Event, EventHandler from flet.controls.layout_control import LayoutControl -from flet.utils.deprecated import deprecated __all__ = ["FletApp", "FletAppOutputEvent"] @@ -98,59 +97,3 @@ class FletApp(LayoutControl): `force_pyodide=True`; root-level Pyodide pages have nowhere to bubble the event. """ - - @property - @deprecated( - reason="Use `boot_screen_options` instead, e.g. " - "boot_screen_options={'spinner_size': 30}.", - version="0.86.0", - delete_version="0.89.0", - ) - def show_app_startup_screen(self) -> bool: - """ - Whether to show the app startup screen. - """ - return bool((self.boot_screen_options or {}).get("spinner_size", 0)) - - @show_app_startup_screen.setter - @deprecated( - reason="Use `boot_screen_options` instead, e.g. " - "boot_screen_options={'spinner_size': 30}.", - version="0.86.0", - delete_version="0.89.0", - ) - def show_app_startup_screen(self, value: bool) -> None: - options = dict(self.boot_screen_options or {}) - if value: - options.setdefault("spinner_size", 30) - else: - options.pop("spinner_size", None) - self.boot_screen_options = options - - @property - @deprecated( - reason="Use `boot_screen_options` instead, e.g. " - "boot_screen_options={'startup_message': '...'}.", - version="0.86.0", - delete_version="0.89.0", - ) - def app_startup_screen_message(self) -> Optional[str]: - """ - Message to display on the app startup screen. - """ - return (self.boot_screen_options or {}).get("startup_message") - - @app_startup_screen_message.setter - @deprecated( - reason="Use `boot_screen_options` instead, e.g. " - "boot_screen_options={'startup_message': '...'}.", - version="0.86.0", - delete_version="0.89.0", - ) - def app_startup_screen_message(self, value: Optional[str]) -> None: - options = dict(self.boot_screen_options or {}) - if value is not None: - options["startup_message"] = value - else: - options.pop("startup_message", None) - self.boot_screen_options = options diff --git a/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md b/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md index a7865b6a8c..5e603dd62c 100644 --- a/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md +++ b/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md @@ -55,7 +55,7 @@ If your code needs page-level coordinates instead, use ## Timeline - Deprecated in: `0.85.0` -- Removed in: Unreleased +- Removed in: `1.0.0` ## References diff --git a/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md b/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md index 38b4c35f44..8ba5dcfc95 100644 --- a/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md +++ b/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md @@ -74,7 +74,7 @@ been added to the page. ## Timeline - Deprecated in: `0.85.0` -- Removed in: Unreleased +- Removed in: `1.0.0` ## References diff --git a/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md b/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md index a3aec1aef1..868350abd6 100644 --- a/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md +++ b/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md @@ -50,7 +50,7 @@ current directory), so you can target another project with `flet clean path/to/a ## Timeline - Deprecated in: `0.86.0` -- Removal in: `0.89.0` +- Removed in: `1.0.0` ## References From 3fb5ca5a08a5d221fa3b362eb9be68b781dafcbd Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Fri, 17 Jul 2026 18:39:40 +0200 Subject: [PATCH 3/9] Remove deprecated Page.go() and Page service accessors Continues the pre-1.0 deprecation cleanup: - Remove Page.go() (deprecated in 0.80.0) -> use Page.push_route() - Remove the Page.url_launcher, Page.browser_context_menu, Page.shared_preferences, Page.clipboard, and Page.storage_paths service accessors (deprecated in 0.80.0) -> instantiate the service classes directly: UrlLauncher(), BrowserContextMenu(), SharedPreferences(), Clipboard(), StoragePaths() - Migrate two examples off the removed accessors --- CHANGELOG.md | 2 + .../declarative/trolli/components/dialogs.py | 2 +- .../material/context_menu/triggers/main.py | 2 +- .../packages/flet/src/flet/controls/page.py | 90 ------------------- 4 files changed, 4 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48e13943da..9c2e874157 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * Remove `Video.playlist_add()` and `Video.playlist_remove()` (deprecated in `0.85.0`). Mutate `Video.playlist` directly with list methods such as `append()` and `pop()` ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. * Remove `FletApp.show_app_startup_screen` and `FletApp.app_startup_screen_message` (deprecated in `0.86.0`). Use `FletApp.boot_screen_options` instead, e.g. `boot_screen_options={'spinner_size': 30}` or `boot_screen_options={'startup_message': '...'}` by @ndonkoHenri. * Remove the `--clear-cache` flag of `flet build` and `flet debug` (deprecated in `0.86.0`). Use the `flet clean` command instead ([#6233](https://github.com/flet-dev/flet/issues/6233)) by @ndonkoHenri. +* Remove `Page.go()` (deprecated in `0.80.0`). Use `Page.push_route()` instead by @ndonkoHenri. +* Remove the `Page.url_launcher`, `Page.browser_context_menu`, `Page.shared_preferences`, `Page.clipboard`, and `Page.storage_paths` service accessors (deprecated in `0.80.0`). Instantiate the corresponding service classes directly: `UrlLauncher()`, `BrowserContextMenu()`, `SharedPreferences()`, `Clipboard()`, `StoragePaths()` by @ndonkoHenri. ## 0.86.1 diff --git a/sdk/python/examples/apps/declarative/trolli/components/dialogs.py b/sdk/python/examples/apps/declarative/trolli/components/dialogs.py index 9db842bb2c..4cf8cc3e19 100644 --- a/sdk/python/examples/apps/declarative/trolli/components/dialogs.py +++ b/sdk/python/examples/apps/declarative/trolli/components/dialogs.py @@ -45,7 +45,7 @@ async def do_login(_: ft.Event): error_text.value = "Please provide username and password" ft.context.page.update() return - await ft.context.page.shared_preferences.set("current_user", user) + await ft.SharedPreferences().set("current_user", user) app.user = user ft.context.page.pop_dialog() diff --git a/sdk/python/examples/controls/material/context_menu/triggers/main.py b/sdk/python/examples/controls/material/context_menu/triggers/main.py index f7e356c262..6b995dd630 100644 --- a/sdk/python/examples/controls/material/context_menu/triggers/main.py +++ b/sdk/python/examples/controls/material/context_menu/triggers/main.py @@ -4,7 +4,7 @@ async def main(page: ft.Page): # on web, disable default browser context menu if page.web: - await page.browser_context_menu.disable() + await ft.BrowserContextMenu().disable() def handle_item_click(e: ft.Event[ft.PopupMenuItem]): action = e.control.content diff --git a/sdk/python/packages/flet/src/flet/controls/page.py b/sdk/python/packages/flet/src/flet/controls/page.py index be0c3fb51e..db40cab504 100644 --- a/sdk/python/packages/flet/src/flet/controls/page.py +++ b/sdk/python/packages/flet/src/flet/controls/page.py @@ -853,23 +853,6 @@ def run_thread( partial(handler_with_context, *args, **kwargs), ) - @deprecated( - "Use push_route() instead.", - version="0.80.0", - delete_version="0.90.0", - show_parentheses=True, - ) - def go( - self, route: str, skip_route_change_event: bool = False, **kwargs: Any - ) -> None: - """ - A helper method that updates [`page.route`](#route), calls \ - [`page.on_route_change`](#on_route_change) event handler to update views and \ - finally calls `page.update()`. - """ - - asyncio.create_task(self.push_route(route, **kwargs)) - async def push_route(self, route: str, **kwargs: Any) -> None: """ Pushes a new navigation route to the browser history stack. @@ -1296,79 +1279,6 @@ def pubsub(self) -> "PubSubClient": """ return self.session.pubsub_client - @property - @deprecated( - reason="Use UrlLauncher() instead.", - docs_reason="Use :class:`~flet.UrlLauncher` instead.", - version="0.80.0", - delete_version="0.90.0", - ) - def url_launcher(self) -> UrlLauncher: - """ - The UrlLauncher service for the current page. - """ - return UrlLauncher() - - @property - @deprecated( - reason="Use BrowserContextMenu() instead.", - docs_reason="Use :class:`~flet.BrowserContextMenu` instead.", - version="0.80.0", - delete_version="0.90.0", - ) - def browser_context_menu(self): - """ - The BrowserContextMenu service for the current page. - """ - from flet.controls.services.browser_context_menu import BrowserContextMenu - - return BrowserContextMenu() - - @property - @deprecated( - reason="Use SharedPreferences() instead.", - docs_reason="Use :class:`~flet.SharedPreferences` instead.", - version="0.80.0", - delete_version="0.90.0", - ) - def shared_preferences(self): - """ - The SharedPreferences service for the current page. - """ - from flet.controls.services.shared_preferences import SharedPreferences - - return SharedPreferences() - - @property - @deprecated( - reason="Use Clipboard() instead.", - docs_reason="Use :class:`~flet.Clipboard` instead.", - version="0.80.0", - delete_version="0.90.0", - ) - def clipboard(self): - """ - The Clipboard service for the current page. - """ - from flet.controls.services.clipboard import Clipboard - - return Clipboard() - - @property - @deprecated( - reason="Use StoragePaths() instead.", - docs_reason="Use :class:`~flet.StoragePaths` instead.", - version="0.80.0", - delete_version="0.90.0", - ) - def storage_paths(self): - """ - The StoragePaths service for the current page. - """ - from flet.controls.services.storage_paths import StoragePaths - - return StoragePaths() - async def get_device_info(self) -> Optional[DeviceInfo]: """ Returns device information. From 76e33fa8e79ce5388ff9eff0ce431ed4364db6a3 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Fri, 17 Jul 2026 18:59:46 +0200 Subject: [PATCH 4/9] Remove ConstrainedControl, ElevatedButton, DropdownM2, and deprecated Colors aliases Completes the scheduled (1.0) deprecation removals: - Remove the ConstrainedControl base class (deprecated 0.80.0) -> inherit from LayoutControl - Remove ElevatedButton (deprecated 0.80.0) -> use Button - Remove DropdownM2 and the dropdownm2 module, incl. its Dart widget and control registration (deprecated 0.84.0) -> use Dropdown - Remove the 14 deprecated non-underscored Colors aliases (BLACK12..WHITE70) -> use the underscored names; revert Colors to a plain Enum - Clean up flet package exports, delete the DropdownM2 docs page and sidebar entry, and migrate one example type annotation to ft.Button --- CHANGELOG.md | 4 + .../flet/lib/src/controls/dropdownm2.dart | 180 -------------- .../flet/lib/src/flet_core_extension.dart | 3 - .../line_chart_with_custom_axes/main.py | 2 +- sdk/python/packages/flet/src/flet/__init__.py | 12 - .../packages/flet/src/flet/controls/colors.py | 28 +-- .../flet/src/flet/controls/layout_control.py | 12 +- .../src/flet/controls/material/dropdownm2.py | 226 ------------------ .../flet/controls/material/elevated_button.py | 13 - .../controls/material/form_field_control.py | 3 +- website/docs/controls/dropdownm2.md | 8 - website/sidebars.yml | 1 - 12 files changed, 8 insertions(+), 484 deletions(-) delete mode 100644 packages/flet/lib/src/controls/dropdownm2.dart delete mode 100644 sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py delete mode 100644 sdk/python/packages/flet/src/flet/controls/material/elevated_button.py delete mode 100644 website/docs/controls/dropdownm2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c2e874157..c909f57d66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ * Remove the `--clear-cache` flag of `flet build` and `flet debug` (deprecated in `0.86.0`). Use the `flet clean` command instead ([#6233](https://github.com/flet-dev/flet/issues/6233)) by @ndonkoHenri. * Remove `Page.go()` (deprecated in `0.80.0`). Use `Page.push_route()` instead by @ndonkoHenri. * Remove the `Page.url_launcher`, `Page.browser_context_menu`, `Page.shared_preferences`, `Page.clipboard`, and `Page.storage_paths` service accessors (deprecated in `0.80.0`). Instantiate the corresponding service classes directly: `UrlLauncher()`, `BrowserContextMenu()`, `SharedPreferences()`, `Clipboard()`, `StoragePaths()` by @ndonkoHenri. +* Remove the `ConstrainedControl` base class (deprecated in `0.80.0`). Inherit from `LayoutControl` instead by @ndonkoHenri. +* Remove `ElevatedButton` (deprecated in `0.80.0`). Use `Button` instead by @ndonkoHenri. +* Remove `DropdownM2` and its `dropdownm2` module (deprecated in `0.84.0`). Use `Dropdown` instead by @ndonkoHenri. +* Remove the deprecated non-underscored `Colors` aliases (`BLACK12`, `BLACK26`, `BLACK38`, `BLACK45`, `BLACK54`, `BLACK87`, `WHITE10`, `WHITE12`, `WHITE24`, `WHITE30`, `WHITE38`, `WHITE54`, `WHITE60`, `WHITE70`). Use the underscored names instead (e.g. `Colors.BLACK_12`) by @ndonkoHenri. ## 0.86.1 diff --git a/packages/flet/lib/src/controls/dropdownm2.dart b/packages/flet/lib/src/controls/dropdownm2.dart deleted file mode 100644 index b1437a9b3a..0000000000 --- a/packages/flet/lib/src/controls/dropdownm2.dart +++ /dev/null @@ -1,180 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../extensions/control.dart'; -import '../models/control.dart'; -import '../utils/alignment.dart'; -import '../utils/borders.dart'; -import '../utils/colors.dart'; -import '../utils/edge_insets.dart'; -import '../utils/form_field.dart'; -import '../utils/layout.dart'; -import '../utils/numbers.dart'; -import '../utils/text.dart'; -import 'base_controls.dart'; - -class DropdownM2Control extends StatefulWidget { - final Control control; - - DropdownM2Control({Key? key, required this.control}) - : super(key: key ?? ValueKey("control_${control.id}")); - - @override - State createState() => _DropdownM2ControlState(); -} - -class _DropdownM2ControlState extends State { - String? _value; - bool _focused = false; - late final FocusNode _focusNode; - - @override - void initState() { - super.initState(); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); - widget.control.addInvokeMethodListener(_invokeMethod); - } - - void _onFocusChange() { - setState(() { - _focused = _focusNode.hasFocus; - }); - widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); - } - - Future _invokeMethod(String name, dynamic args) async { - debugPrint("DropdownM2.$name($args)"); - switch (name) { - case "focus": - _focusNode.requestFocus(); - default: - throw Exception("Unknown DropdownM2 method: $name"); - } - } - - @override - void dispose() { - _focusNode.removeListener(_onFocusChange); - _focusNode.dispose(); - widget.control.removeInvokeMethodListener(_invokeMethod); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - debugPrint("DropdownM2 build: ${widget.control.id}"); - - var textSize = widget.control.getDouble("text_size"); - var color = widget.control.getColor("color", context); - var focusedColor = widget.control.getColor("focused_color", context); - - var textStyle = widget.control - .getTextStyle("text_style", Theme.of(context), const TextStyle())!; - - if (textSize != null) { - textStyle = textStyle.copyWith(fontSize: textSize); - } - - if (focusedColor != null) { - textStyle = textStyle.copyWith( - color: _focused ? focusedColor : (color ?? textStyle.color)); - } - - if (color != null) { - textStyle = textStyle.copyWith(color: color); - } - - if (textStyle.color == null) { - textStyle = - textStyle.copyWith(color: Theme.of(context).colorScheme.onSurface); - } - - var items = widget.control - .children("options") - .map>((Control item) { - item.notifyParent = true; - var textStyle = item.getTextStyle("text_style", Theme.of(context)); - if (item.disabled && textStyle != null) { - textStyle = textStyle.apply(color: Theme.of(context).disabledColor); - } - var value = - item.getString("key") ?? item.getString("text") ?? item.id.toString(); - var content = - item.buildWidget("content") ?? Text(value, style: textStyle); - var alignment = item.getAlignment("alignment"); - if (alignment != null) { - content = Container(alignment: alignment, child: content); - } - return DropdownMenuItem( - enabled: !item.disabled, - value: value, - alignment: alignment ?? AlignmentDirectional.centerStart, - onTap: !item.disabled ? () => item.triggerEvent("click") : null, - child: content); - }).toList(); - - String? value = widget.control.getString("value"); - if (_value != value) { - _value = value; - } - - if (items.where((item) => item.value == value).isEmpty) { - _value = null; - } - - Widget dropDown = DropdownButtonFormField( - style: textStyle, - autofocus: widget.control.getBool("autofocus", false)!, - focusNode: _focusNode, - initialValue: _value, - dropdownColor: widget.control.getColor("bgcolor", context), - enableFeedback: widget.control.getBool("enable_feedback"), - elevation: widget.control.getInt("elevation", 8)!, - padding: widget.control.getPadding("padding"), - itemHeight: widget.control.getDouble("item_height"), - menuMaxHeight: widget.control.getDouble("max_menu_height"), - iconEnabledColor: - widget.control.getColor("select_icon_enabled_color", context), - iconDisabledColor: - widget.control.getColor("select_icon_disabled_color", context), - iconSize: widget.control.getDouble("select_icon_size", 24.0)!, - borderRadius: widget.control.getBorderRadius("border_radius"), - alignment: widget.control.getAlignment("alignment") ?? - AlignmentDirectional.centerStart, - isExpanded: widget.control.getBool("options_fill_horizontally", true)!, - icon: widget.control.buildIconOrWidget("select_icon"), - hint: widget.control.buildWidget("hint"), - disabledHint: widget.control.buildWidget("disabled_hint"), - decoration: buildInputDecoration(context, widget.control, - customSuffix: null, focused: _focused), - onTap: !widget.control.disabled - ? () => widget.control.triggerEvent("click") - : null, - onChanged: widget.control.disabled - ? null - : (String? value) { - _value = value!; - widget.control.updateProperties({"value": value}); - widget.control.triggerEvent("change", value); - }, - items: items, - ); - - if (widget.control.getExpand("expand", 0)! > 0) { - return LayoutControl(control: widget.control, child: dropDown); - } else { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - if (constraints.maxWidth == double.infinity && - widget.control.getDouble("width") == null) { - dropDown = ConstrainedBox( - constraints: const BoxConstraints.tightFor(width: 300), - child: dropDown); - } - - return LayoutControl(control: widget.control, child: dropDown); - }, - ); - } - } -} diff --git a/packages/flet/lib/src/flet_core_extension.dart b/packages/flet/lib/src/flet_core_extension.dart index 9bb0d0232b..6f64f6ffbf 100644 --- a/packages/flet/lib/src/flet_core_extension.dart +++ b/packages/flet/lib/src/flet_core_extension.dart @@ -51,7 +51,6 @@ import 'controls/divider.dart'; import 'controls/drag_target.dart'; import 'controls/draggable.dart'; import 'controls/dropdown.dart'; -import 'controls/dropdownm2.dart'; import 'controls/expansion_panel.dart'; import 'controls/expansion_tile.dart'; import 'controls/flet_app_control.dart'; @@ -253,8 +252,6 @@ class FletCoreExtension extends FletExtension { return DraggableControl(key: key, control: control); case "Dropdown": return DropdownControl(key: key, control: control); - case "DropdownM2": - return DropdownM2Control(key: key, control: control); case "ExpansionPanelList": return ExpansionPanelListControl(key: key, control: control); case "ExpansionTile": diff --git a/sdk/python/examples/extensions/charts/line_chart/line_chart_with_custom_axes/main.py b/sdk/python/examples/extensions/charts/line_chart/line_chart_with_custom_axes/main.py index 839d384228..426227f275 100644 --- a/sdk/python/examples/extensions/charts/line_chart/line_chart_with_custom_axes/main.py +++ b/sdk/python/examples/extensions/charts/line_chart/line_chart_with_custom_axes/main.py @@ -123,7 +123,7 @@ def main(page: ft.Page): ), ) - def toggle_data(e: ft.Event[ft.ElevatedButton]): + def toggle_data(e: ft.Event[ft.Button]): if state.toggled: chart.data_series = data_2 chart.interactive = False diff --git a/sdk/python/packages/flet/src/flet/__init__.py b/sdk/python/packages/flet/src/flet/__init__.py index c534e26a23..d39e06b2f2 100644 --- a/sdk/python/packages/flet/src/flet/__init__.py +++ b/sdk/python/packages/flet/src/flet/__init__.py @@ -334,7 +334,6 @@ ValueKey, ) from flet.controls.layout_control import ( - ConstrainedControl, LayoutControl, LayoutSizeChangeEvent, ) @@ -344,7 +343,6 @@ ) from flet.controls.material import ( dropdown, - dropdownm2, icons, ) from flet.controls.material.alert_dialog import AlertDialog @@ -395,8 +393,6 @@ Dropdown, DropdownOption, ) - from flet.controls.material.dropdownm2 import DropdownM2 - from flet.controls.material.elevated_button import ElevatedButton from flet.controls.material.expansion_panel import ( ExpansionPanel, ExpansionPanelList, @@ -819,7 +815,6 @@ "Connectivity", "ConnectivityChangeEvent", "ConnectivityType", - "ConstrainedControl", "Container", "Context", "ContextMenu", @@ -900,12 +895,10 @@ "DragWillAcceptEvent", "Draggable", "Dropdown", - "DropdownM2", "DropdownOption", "DropdownTheme", "Duration", "DurationValue", - "ElevatedButton", "Event", "EventControlType", "EventHandler", @@ -1233,7 +1226,6 @@ "cupertino_colors", "cupertino_icons", "dropdown", - "dropdownm2", "icons", "is_route_active", "margin", @@ -1353,7 +1345,6 @@ "Connectivity": "flet.controls.services.connectivity", "ConnectivityChangeEvent": "flet.controls.services.connectivity", "ConnectivityType": "flet.controls.services.connectivity", - "ConstrainedControl": "flet.controls.layout_control", "Container": "flet.controls.material.container", "Context": "flet.controls.context", "ContextMenu": "flet.controls.material.context_menu", @@ -1434,12 +1425,10 @@ "DragWillAcceptEvent": "flet.controls.core.drag_target", "Draggable": "flet.controls.core.draggable", "Dropdown": "flet.controls.material.dropdown", - "DropdownM2": "flet.controls.material.dropdownm2", "DropdownOption": "flet.controls.material.dropdown", "DropdownTheme": "flet.controls.theme", "Duration": "flet.controls.duration", "DurationValue": "flet.controls.duration", - "ElevatedButton": "flet.controls.material.elevated_button", "Event": "flet.controls.control_event", "EventControlType": "flet.controls.control_event", "EventHandler": "flet.controls.control_event", @@ -1766,7 +1755,6 @@ "cupertino_colors": "flet.controls.cupertino", "cupertino_icons": "flet.controls.cupertino", "dropdown": "flet.controls.material", - "dropdownm2": "flet.controls.material", "icons": "flet.controls.material", "is_route_active": "flet.components.router", "margin": "flet.controls", diff --git a/sdk/python/packages/flet/src/flet/controls/colors.py b/sdk/python/packages/flet/src/flet/controls/colors.py index fbddce30ca..8e87f82c7e 100644 --- a/sdk/python/packages/flet/src/flet/controls/colors.py +++ b/sdk/python/packages/flet/src/flet/controls/colors.py @@ -55,15 +55,13 @@ from enum import Enum from typing import TYPE_CHECKING, Optional, Union -from flet.utils.deprecated_enum import DeprecatedEnumMeta - if TYPE_CHECKING: from flet.controls.types import ColorValue __all__ = ["Colors"] -class Colors(str, Enum, metaclass=DeprecatedEnumMeta): +class Colors(str, Enum): """ Named Material colors. """ @@ -493,27 +491,3 @@ def with_opacity(opacity: Union[int, float], color: "ColorValue") -> str: YELLOW_ACCENT_200 = "yellowaccent200" YELLOW_ACCENT_400 = "yellowaccent400" YELLOW_ACCENT_700 = "yellowaccent700" - - -# TODO - remove in Flet 1.0 -_DEPRECATED_COLOR_ALIASES = { - "BLACK12": ("BLACK_12", "Use Colors.BLACK_12 instead."), - "BLACK26": ("BLACK_26", "Use Colors.BLACK_26 instead."), - "BLACK38": ("BLACK_38", "Use Colors.BLACK_38 instead."), - "BLACK45": ("BLACK_45", "Use Colors.BLACK_45 instead."), - "BLACK54": ("BLACK_54", "Use Colors.BLACK_54 instead."), - "BLACK87": ("BLACK_87", "Use Colors.BLACK_87 instead."), - "WHITE10": ("WHITE_10", "Use Colors.WHITE_10 instead."), - "WHITE12": ("WHITE_12", "Use Colors.WHITE_12 instead."), - "WHITE24": ("WHITE_24", "Use Colors.WHITE_24 instead."), - "WHITE30": ("WHITE_30", "Use Colors.WHITE_30 instead."), - "WHITE38": ("WHITE_38", "Use Colors.WHITE_38 instead."), - "WHITE54": ("WHITE_54", "Use Colors.WHITE_54 instead."), - "WHITE60": ("WHITE_60", "Use Colors.WHITE_60 instead."), - "WHITE70": ("WHITE_70", "Use Colors.WHITE_70 instead."), -} - -Colors._deprecated_members_ = _DEPRECATED_COLOR_ALIASES - -for alias_name, (target_name, _) in _DEPRECATED_COLOR_ALIASES.items(): - Colors._member_map_[alias_name] = getattr(Colors, target_name) diff --git a/sdk/python/packages/flet/src/flet/controls/layout_control.py b/sdk/python/packages/flet/src/flet/controls/layout_control.py index 6af296eb1f..46174e52bc 100644 --- a/sdk/python/packages/flet/src/flet/controls/layout_control.py +++ b/sdk/python/packages/flet/src/flet/controls/layout_control.py @@ -20,9 +20,8 @@ Transform, ) from flet.controls.types import Number -from flet.utils import deprecated_class -__all__ = ["ConstrainedControl", "LayoutControl", "LayoutSizeChangeEvent"] +__all__ = ["LayoutControl", "LayoutSizeChangeEvent"] @dataclass @@ -319,12 +318,3 @@ def main(page: ft.Page): More information [here](https://flet.dev/docs/cookbook/animations). """ - - -@deprecated_class( - reason="Inherit from LayoutControl instead.", - version="0.80.0", - delete_version="1.0", -) -class ConstrainedControl(LayoutControl): - pass diff --git a/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py b/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py deleted file mode 100644 index 52da53640f..0000000000 --- a/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py +++ /dev/null @@ -1,226 +0,0 @@ -from typing import Optional - -from flet.controls.alignment import Alignment -from flet.controls.base_control import control -from flet.controls.control import Control -from flet.controls.control_event import ControlEventHandler -from flet.controls.material.form_field_control import FormFieldControl -from flet.controls.padding import PaddingValue -from flet.controls.text_style import TextStyle -from flet.controls.types import ( - ColorValue, - IconDataOrControl, - Number, -) -from flet.utils.deprecated import deprecated_class -from flet.utils.validation import V, ValidationRules - -__all__ = ["DropdownM2", "Option"] - - -@control("Option") -class Option(Control): - """ - Represents an item in a dropdown. - """ - - key: Optional[str] = None - """ - Option's key. - - If not specified :attr:`text` will be used as fallback. - - Raises: - ValueError: If neither `key` nor :attr:`text` is provided. - """ - - text: Optional[str] = None - """ - Option's display text. - - If not specified :attr:`key` will be used as fallback. - - Raises: - ValueError: If neither :attr:`key` nor `text` is provided. - """ - - content: Optional[Control] = None - """ - A `Control` to display in this option. If not specified, `text` will be used as \ - fallback, else `text` will be ignored. - """ - - alignment: Optional[Alignment] = None - """ - Defines the alignment of this option in it's container. - - Defaults to `Alignment.center_left()`. - """ - - text_style: Optional[TextStyle] = None - """ - Defines the style of the `text`. - """ - - on_click: Optional[ControlEventHandler["Option"]] = None - """ - Called when this option is clicked. - """ - - __validation_rules__: ValidationRules = ( - V.ensure( - lambda ctrl: ctrl.key is not None or ctrl.text is not None, - message="key or text must be specified", - ), - ) - - -@deprecated_class( - reason="Use Dropdown instead.", - docs_reason="Use [`Dropdown`][flet.Dropdown] instead.", - version="0.84.0", - delete_version="1.0", -) -@control("DropdownM2") -class DropdownM2(FormFieldControl): - """ - A dropdown lets the user select from a number of items. The dropdown shows the \ - currently selected item as well as an arrow that opens a menu for selecting \ - another item. - - Example: - ```python - ft.DropdownM2( - width=220, - value="Alice", - options=[ - ft.dropdownm2.Option(key="Alice", text="Alice"), - ft.dropdownm2.Option(key="Bob", text="Bob"), - ], - ) - ``` - """ - - value: Optional[str] = None - """ - `key` value of the selected option. - """ - - options: Optional[list[Option]] = None - """ - A list of `Option` controls representing items in this dropdown. - """ - - alignment: Optional[Alignment] = None - """ - Defines how the `hint` or the selected item is positioned within this dropdown. - """ - - autofocus: bool = False - """ - True if the control will be selected as the initial focus. If there is more than \ - one control on a page with autofocus set, then the first one added to the page \ - will get focus. - """ - - hint_content: Optional[Control] = None - """ - A placeholder `Control` for the dropdown's value that is displayed when `value` is \ - `None`. - """ - - select_icon: Optional[IconDataOrControl] = None - """ - The [name of the icon](https://flet.dev/docs/types/icons) or `Control` to use \ - for the drop-down select button's icon. - - Defaults to `Icon(ft.Icons.ARROW_DROP_DOWN)`. - """ - - elevation: Number = 8 - """ - The dropdown's elevation. - """ - - item_height: Optional[Number] = None - """ - The height of the items/options in the dropdown menu. - """ - - max_menu_height: Optional[Number] = None - """ - The maximum height of the dropdown menu. - """ - - select_icon_size: Number = 24.0 - """ - The size of the icon button which wraps `select_icon`. - """ - - enable_feedback: Optional[bool] = None - """ - Whether detected gestures should provide acoustic and/or haptic feedback. On \ - Android, for example, setting this to `True` produce a click sound and a \ - long-press will produce a short vibration. - """ - - padding: Optional[PaddingValue] = None - """ - The padding around the visible portion of this dropdown. - """ - - select_icon_enabled_color: Optional[ColorValue] = None - """ - The color of any `Icon` descendant of `select_icon` if this button is enabled. - """ - - select_icon_disabled_color: Optional[ColorValue] = None - """ - The color of any `Icon` descendant of `select_icon` if this button is disabled. - """ - - options_fill_horizontally: bool = True - """ - Whether the dropdown's inner contents to horizontally fill its parent. - By default this button's inner width is the minimum size of its content. - - If `True`, the inner width is expanded to fill its surrounding container. - """ - - disabled_hint_content: Optional[Control] = None - """ - A placeholder `Control` for the dropdown's value that is displayed when `value` is \ - `None` and the dropdown is disabled. - """ - - on_change: Optional[ControlEventHandler["DropdownM2"]] = None - """ - Called when the selected item of this dropdown has changed. - """ - - on_focus: Optional[ControlEventHandler["DropdownM2"]] = None - """ - Called when the control has received focus. - """ - - on_blur: Optional[ControlEventHandler["DropdownM2"]] = None - """ - Called when the control has lost focus. - """ - - on_click: Optional[ControlEventHandler["DropdownM2"]] = None - """ - Called when this dropdown is clicked. - """ - - def before_update(self): - super().before_update() - if ( - self.bgcolor is not None - or self.fill_color is not None - or self.focused_bgcolor is not None - ) and self.filled is None: - self.filled = True # required to display any of the above colors - - def __contains__(self, item): - return item in self.options diff --git a/sdk/python/packages/flet/src/flet/controls/material/elevated_button.py b/sdk/python/packages/flet/src/flet/controls/material/elevated_button.py deleted file mode 100644 index 18706db87d..0000000000 --- a/sdk/python/packages/flet/src/flet/controls/material/elevated_button.py +++ /dev/null @@ -1,13 +0,0 @@ -from flet.controls.material.button import Button -from flet.utils.deprecated import deprecated_class - -__all__ = ["ElevatedButton"] - - -@deprecated_class( - reason="Use Button instead.", - version="0.80.0", - delete_version="1.0", -) -class ElevatedButton(Button): - pass diff --git a/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py b/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py index d4a5271476..0005b217af 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py +++ b/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py @@ -46,8 +46,7 @@ class FormFieldControl(LayoutControl): Base class for Material form-field controls with a decorated input area. It provides the shared label, hint, helper, error, prefix, suffix, fill, and - border properties used by controls such as :class:`~flet.TextField` and - :class:`~flet.DropdownM2`. + border properties used by controls such as :class:`~flet.TextField`. """ text_size: Optional[Number] = None diff --git a/website/docs/controls/dropdownm2.md b/website/docs/controls/dropdownm2.md deleted file mode 100644 index e55db7ff94..0000000000 --- a/website/docs/controls/dropdownm2.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -class_name: "flet.DropdownM2" -title: "DropdownM2" ---- - -import {ClassAll} from '@site/src/components/crocodocs'; - - diff --git a/website/sidebars.yml b/website/sidebars.yml index 206c97b79d..a1bb7d67a5 100644 --- a/website/sidebars.yml +++ b/website/sidebars.yml @@ -195,7 +195,6 @@ docs: Dropdown: _index: controls/dropdown/index.md DropdownOption: controls/dropdownoption.md - DropdownM2: controls/dropdownm2.md ExpansionPanel: controls/expansionpanel.md ExpansionPanelList: controls/expansionpanellist.md ExpansionTile: controls/expansiontile.md From 2090c23da5c6ea99ac0bc4a934f415960a923056 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Fri, 17 Jul 2026 19:25:53 +0200 Subject: [PATCH 5/9] Remove remaining no-removal-version deprecations for a deprecation-free 1.0 Sweeps the deprecations that had no scheduled removal version: - Remove app() and app_async() (deprecated 0.80.0) -> use run()/run_async() - Remove the target= alias parameter of run()/run_async() -> pass main - Remove Page.launch_url()/can_launch_url()/close_in_app_web_view() (deprecated 0.90.0) -> use UrlLauncher() - Remove the legacy [tool.flet.app.boot_screen]/[tool.flet.app.startup_screen] build-config fallback -> use [tool.flet.boot_screen] - Remove the Dart empty-string widget-state key back-compat mapping -> 'default' - Migrate 8 examples + the authentication cookbook doc off page.launch_url() to ft.UrlLauncher().launch_url() (and fix a stale web_window_name kwarg) --- CHANGELOG.md | 5 ++ packages/flet/lib/src/utils/widget_state.dart | 5 -- .../markdown/code_syntax_highlight/main.py | 2 +- .../controls/core/markdown/listviews/main.py | 2 +- .../controls/core/markdown/markdown/main.py | 2 +- .../audio_recorder/audio_recorder/main.py | 2 +- .../extensions/map/camera_controls/main.py | 2 +- .../extensions/map/idle_camera/main.py | 2 +- .../extensions/map/interaction_flags/main.py | 2 +- .../extensions/map/multi_layers/main.py | 2 +- .../src/flet_cli/commands/build_base.py | 21 ----- sdk/python/packages/flet/src/flet/__init__.py | 6 -- sdk/python/packages/flet/src/flet/app.py | 45 ++--------- .../packages/flet/src/flet/controls/page.py | 81 ------------------- website/docs/cookbook/authentication.md | 4 +- 15 files changed, 22 insertions(+), 161 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c909f57d66..96fa3d05ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,11 @@ * Remove `ElevatedButton` (deprecated in `0.80.0`). Use `Button` instead by @ndonkoHenri. * Remove `DropdownM2` and its `dropdownm2` module (deprecated in `0.84.0`). Use `Dropdown` instead by @ndonkoHenri. * Remove the deprecated non-underscored `Colors` aliases (`BLACK12`, `BLACK26`, `BLACK38`, `BLACK45`, `BLACK54`, `BLACK87`, `WHITE10`, `WHITE12`, `WHITE24`, `WHITE30`, `WHITE38`, `WHITE54`, `WHITE60`, `WHITE70`). Use the underscored names instead (e.g. `Colors.BLACK_12`) by @ndonkoHenri. +* Remove `app()` and `app_async()` (deprecated in `0.80.0`). Use `run()` and `run_async()` instead by @ndonkoHenri. +* Remove the `target` parameter of `run()` and `run_async()` (deprecated alias for `main`). Pass `main` instead by @ndonkoHenri. +* Remove `Page.launch_url()`, `Page.can_launch_url()`, and `Page.close_in_app_web_view()` (deprecated in `0.90.0`). Use `UrlLauncher().launch_url()` / `.can_launch_url()` / `.close_in_app_web_view()` instead by @ndonkoHenri. +* Remove the legacy `[tool.flet.app.boot_screen]` / `[tool.flet.app.startup_screen]` build-config fallback. Use `[tool.flet.boot_screen]` with a named screen instead by @ndonkoHenri. +* Remove the Dart empty-string (`""`) widget-state key back-compat mapping. Use `"default"` (or `ControlState.DEFAULT`) instead by @ndonkoHenri. ## 0.86.1 diff --git a/packages/flet/lib/src/utils/widget_state.dart b/packages/flet/lib/src/utils/widget_state.dart index 616ca81bed..c25307a79f 100644 --- a/packages/flet/lib/src/utils/widget_state.dart +++ b/packages/flet/lib/src/utils/widget_state.dart @@ -12,9 +12,6 @@ WidgetStateProperty? getWidgetStateProperty( if (j is! Map || j.isEmpty) { j = {"default": j}; } - if (j.containsKey("")) { - j["default"] = j.remove(""); - } if (!j.keys.every( (k) => k == "default" || WidgetState.values.any((v) => v.name == k))) { // wrap into another dict @@ -35,8 +32,6 @@ class WidgetStateFromJSON extends WidgetStateProperty { _states = LinkedHashMap.from( jsonDictValue?.map((k, v) { var key = k.trim().toLowerCase(); - // "" is deprecated and renamed to "default" - if (key == "") key = "default"; return MapEntry(key, converterFromJson(v)); }) ?? {}, diff --git a/sdk/python/examples/controls/core/markdown/code_syntax_highlight/main.py b/sdk/python/examples/controls/core/markdown/code_syntax_highlight/main.py index 7c836b9c83..9d0656d22d 100644 --- a/sdk/python/examples/controls/core/markdown/code_syntax_highlight/main.py +++ b/sdk/python/examples/controls/core/markdown/code_syntax_highlight/main.py @@ -159,7 +159,7 @@ def main(page: ft.Page): } async def navigate_md_link(e: ft.Event[ft.Markdown]): - await page.launch_url(e.data) + await ft.UrlLauncher().launch_url(e.data) page.add( ft.SafeArea( diff --git a/sdk/python/examples/controls/core/markdown/listviews/main.py b/sdk/python/examples/controls/core/markdown/listviews/main.py index 119a5905b4..d2e4da81fe 100644 --- a/sdk/python/examples/controls/core/markdown/listviews/main.py +++ b/sdk/python/examples/controls/core/markdown/listviews/main.py @@ -121,7 +121,7 @@ def main(page: ft.Page): async def navigate_md_link(e: ft.Event[ft.Markdown]): - await page.launch_url(e.data) + await ft.UrlLauncher().launch_url(e.data) page.add( ft.SafeArea( diff --git a/sdk/python/examples/controls/core/markdown/markdown/main.py b/sdk/python/examples/controls/core/markdown/markdown/main.py index 075fc15c35..1ceb6fcdc9 100644 --- a/sdk/python/examples/controls/core/markdown/markdown/main.py +++ b/sdk/python/examples/controls/core/markdown/markdown/main.py @@ -80,7 +80,7 @@ def main(page: ft.Page): page.scroll = ft.ScrollMode.AUTO async def handle_link_tap(e: ft.Event[ft.Markdown]): - await page.launch_url(e.data) + await ft.UrlLauncher().launch_url(e.data) page.add( ft.SafeArea( diff --git a/sdk/python/examples/extensions/audio_recorder/audio_recorder/main.py b/sdk/python/examples/extensions/audio_recorder/audio_recorder/main.py index c2d4b8b5bb..a0310c503f 100644 --- a/sdk/python/examples/extensions/audio_recorder/audio_recorder/main.py +++ b/sdk/python/examples/extensions/audio_recorder/audio_recorder/main.py @@ -19,7 +19,7 @@ async def handle_recording_stop(e: ft.Event[ft.Button]): output_path = await recorder.stop_recording() show_snackbar(f"Stopped recording. Output Path: {output_path}") if page.web and output_path is not None: - await page.launch_url(output_path) + await ft.UrlLauncher().launch_url(output_path) async def handle_list_devices(e: ft.Event[ft.Button]): o = await recorder.get_input_devices() diff --git a/sdk/python/examples/extensions/map/camera_controls/main.py b/sdk/python/examples/extensions/map/camera_controls/main.py index da1886e17f..e44875ced1 100644 --- a/sdk/python/examples/extensions/map/camera_controls/main.py +++ b/sdk/python/examples/extensions/map/camera_controls/main.py @@ -81,7 +81,7 @@ async def set_world_zoom(e: ft.Event[ft.Button]): ), ftm.SimpleAttribution( text="OpenStreetMap contributors", - on_click=lambda e: e.page.launch_url( + on_click=lambda e: ft.UrlLauncher().launch_url( "https://www.openstreetmap.org/copyright" ), ), diff --git a/sdk/python/examples/extensions/map/idle_camera/main.py b/sdk/python/examples/extensions/map/idle_camera/main.py index d2c383beb6..310bdbb4bb 100644 --- a/sdk/python/examples/extensions/map/idle_camera/main.py +++ b/sdk/python/examples/extensions/map/idle_camera/main.py @@ -68,7 +68,7 @@ async def handle_map_event(e: ftm.MapEvent): ), ftm.SimpleAttribution( text="OpenStreetMap contributors", - on_click=lambda e: e.page.launch_url( + on_click=lambda e: ft.UrlLauncher().launch_url( "https://www.openstreetmap.org/copyright" ), ), diff --git a/sdk/python/examples/extensions/map/interaction_flags/main.py b/sdk/python/examples/extensions/map/interaction_flags/main.py index 580b8914c5..a668c8a723 100644 --- a/sdk/python/examples/extensions/map/interaction_flags/main.py +++ b/sdk/python/examples/extensions/map/interaction_flags/main.py @@ -62,7 +62,7 @@ def handle_map_event(e: ftm.MapEvent): ), ftm.SimpleAttribution( text="OpenStreetMap contributors", - on_click=lambda e: e.page.launch_url( + on_click=lambda e: ft.UrlLauncher().launch_url( "https://www.openstreetmap.org/copyright" ), ), diff --git a/sdk/python/examples/extensions/map/multi_layers/main.py b/sdk/python/examples/extensions/map/multi_layers/main.py index e79263637b..2c84a67923 100644 --- a/sdk/python/examples/extensions/map/multi_layers/main.py +++ b/sdk/python/examples/extensions/map/multi_layers/main.py @@ -56,7 +56,7 @@ def handle_tap(e: ftm.MapTapEvent): ), ftm.SimpleAttribution( text="OpenStreetMap contributors", - on_click=lambda e: e.page.launch_url( + on_click=lambda e: ft.UrlLauncher().launch_url( "https://www.openstreetmap.org/copyright" ), ), diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py index 1305894051..f5434969c3 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py @@ -1393,29 +1393,8 @@ def merged(key): name = boot_screen.get("name", "flet") options = boot_screen.get(name) or {} else: - # backward compatibility with the legacy app.boot_screen / - # app.startup_screen settings name = "flet" options = {} - legacy_boot = merged("app.boot_screen") - legacy_startup = merged("app.startup_screen") - if legacy_boot or legacy_startup: - console.log( - "[tool.flet.app.boot_screen] and " - "[tool.flet.app.startup_screen] are deprecated; use " - "[tool.flet.boot_screen] with a named screen instead.", - style=warning_style, - ) - if legacy_boot.get("show"): - options["spinner_size"] = 30 - message = legacy_boot.get("message") - if message: - options["prepare_message"] = message - if legacy_startup.get("show"): - options["spinner_size"] = 30 - message = legacy_startup.get("message") - if message: - options["startup_message"] = message return { "name": name, diff --git a/sdk/python/packages/flet/src/flet/__init__.py b/sdk/python/packages/flet/src/flet/__init__.py index d39e06b2f2..f953080611 100644 --- a/sdk/python/packages/flet/src/flet/__init__.py +++ b/sdk/python/packages/flet/src/flet/__init__.py @@ -9,8 +9,6 @@ if TYPE_CHECKING: from flet.app import ( AppCallable, - app, - app_async, run, run_async, ) @@ -1215,8 +1213,6 @@ "WindowsDeviceInfo", "__version__", "alignment", - "app", - "app_async", "border", "border_radius", "component", @@ -1744,8 +1740,6 @@ "WindowResizeEdge": "flet.controls.core.window", "WindowsDeviceInfo": "flet.controls.device_info", "alignment": "flet.controls", - "app": "flet.app", - "app_async": "flet.app", "border": "flet.controls", "border_radius": "flet.controls", "component": "flet.components.component_decorator", diff --git a/sdk/python/packages/flet/src/flet/app.py b/sdk/python/packages/flet/src/flet/app.py index 1c6a82762b..8ec817aa87 100644 --- a/sdk/python/packages/flet/src/flet/app.py +++ b/sdk/python/packages/flet/src/flet/app.py @@ -23,7 +23,6 @@ is_pyodide, open_in_browser, ) -from flet.utils.deprecated import deprecated from flet.utils.pip import ( ensure_flet_desktop_package_installed, ensure_flet_web_package_installed, @@ -41,32 +40,6 @@ """ -@deprecated( - "Use run() instead.", - docs_reason="Use [`run()`][flet.run] instead.", - version="0.80.0", - show_parentheses=True, -) -def app(*args, **kwargs): - new_args = list(args) - if "target" in kwargs: - new_args.insert(0, kwargs["target"]) - return run(*new_args, **kwargs) - - -@deprecated( - "Use run_async() instead.", - docs_reason="Use [`run_async()`][flet.run_async] instead.", - version="0.80.0", - show_parentheses=True, -) -def app_async(*args, **kwargs): - new_args = list(args) - if "target" in kwargs: - new_args.insert(0, kwargs["target"]) - return run_async(*new_args, **kwargs) - - def run( main: AppCallable, before_main: Optional[AppCallable] = None, @@ -80,7 +53,6 @@ def run( route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, no_cdn: Optional[bool] = False, export_asgi_app: Optional[bool] = False, - target=None, ): """ Runs the Flet app. @@ -101,14 +73,13 @@ def run( no_cdn: Whether not load CanvasKit, Pyodide, or fonts from CDN. export_asgi_app: If `True`, returns a configured ASGI app instead of running an event loop. - target: Deprecated alias for `main`. Returns: A FastAPI ASGI app when `export_asgi_app=True`. Otherwise, runs the app and returns `None`. """ if is_pyodide(): - __run_pyodide(main=main or target, before_main=before_main) + __run_pyodide(main=main, before_main=before_main) return if export_asgi_app: @@ -116,7 +87,7 @@ def run( from flet_web.fastapi.serve_fastapi_web_app import get_fastapi_web_app return get_fastapi_web_app( - main=main or target, + main=main, before_main=before_main, page_name=__get_page_name(name), assets_dir=__get_assets_dir_path(assets_dir, relative_to_cwd=True), @@ -134,7 +105,7 @@ def run( return asyncio.run( run_async( - main=main or target, + main=main, before_main=before_main, name=name, host=host, @@ -161,7 +132,6 @@ async def run_async( web_renderer: WebRenderer = WebRenderer.AUTO, route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, no_cdn: Optional[bool] = False, - target=None, ): """ Asynchronously run a Flet app using socket or web server transport. @@ -179,11 +149,10 @@ async def run_async( web_renderer: Web renderer type for web-hosted mode. route_url_strategy: Route URL strategy (`path` or `hash`). no_cdn: Whether to avoid loading CanvasKit, Pyodide, and fonts from CDN. - target: Deprecated alias for `main`. """ if is_pyodide(): - __run_pyodide(main=main or target, before_main=before_main) + __run_pyodide(main=main, before_main=before_main) return if isinstance(view, str): @@ -270,19 +239,19 @@ def exit_gracefully(signum, frame): if is_embedded() and bridge_port_env: conn = await __run_dart_bridge_server( port=int(bridge_port_env), - main=main or target, + main=main, before_main=before_main, ) elif is_socket_server: conn = await __run_socket_server( port=port, - main=main or target, + main=main, before_main=before_main, blocking=is_embedded(), ) else: conn = await __run_web_server( - main=main or target, + main=main, before_main=before_main, host=host, port=port, diff --git a/sdk/python/packages/flet/src/flet/controls/page.py b/sdk/python/packages/flet/src/flet/controls/page.py index db40cab504..52a5d2ecb5 100644 --- a/sdk/python/packages/flet/src/flet/controls/page.py +++ b/sdk/python/packages/flet/src/flet/controls/page.py @@ -15,7 +15,6 @@ Optional, ParamSpec, TypeVar, - Union, ) from urllib.parse import urlparse @@ -53,12 +52,9 @@ DeviceOrientation, Locale, PagePlatform, - Url, - UrlTarget, Wrapper, ) from flet.utils import is_pyodide -from flet.utils.deprecated import deprecated from flet.utils.from_dict import from_dict from flet.utils.strings import random_string @@ -1144,83 +1140,6 @@ def logout(self) -> None: if self.on_logout: asyncio.create_task(self._trigger_event("logout", event_data=None, e=e)) - @deprecated( - "Use UrlLauncher().launch_url() instead.", - version="0.90.0", - show_parentheses=True, - ) - async def launch_url( - self, - url: Union[str, Url], - *, - web_popup_window_name: Optional[Union[str, UrlTarget]] = None, - web_popup_window: bool = False, - web_popup_window_width: Optional[int] = None, - web_popup_window_height: Optional[int] = None, - ) -> None: - """ - Opens a web browser or popup window to a given `url`. - - Args: - url: The URL to open. - web_popup_window_name: Window tab/name to open URL in. Use - :attr:`flet.UrlTarget.SELF` for the same browser tab, - :attr:`flet.UrlTarget.BLANK` for a new browser tab (or in external - application on a mobile device), or a custom name for a named tab. - web_popup_window: Display the URL in a browser popup window. - web_popup_window_width: Popup window width. - web_popup_window_height: Popup window height. - """ - if web_popup_window: - await UrlLauncher().open_window( - url, - title=web_popup_window_name, - width=web_popup_window_width, - height=web_popup_window_height, - ) - else: - await UrlLauncher().launch_url(url) - - @deprecated( - "Use UrlLauncher().can_launch_url() instead.", - version="0.90.0", - show_parentheses=True, - ) - async def can_launch_url(self, url: str) -> bool: - """ - Checks whether the specified URL can be handled by some app installed on the \ - device. - - Args: - url: The URL to check. - - Returns: - `True` if it is possible to verify that there is a handler available. - `False` if there is no handler available, or the application does not - have permission to check. For example: - - - On recent versions of Android and iOS, this will always return `False` - unless the application has been configuration to allow querying the - system for launch support. - - In web mode, this will always return `False` except for a few specific - schemes that are always assumed to be supported (such as http(s)), - as web pages are never allowed to query installed applications. - """ - return await UrlLauncher().can_launch_url(url) - - @deprecated( - "Use UrlLauncher().close_in_app_web_view() instead.", - version="0.90.0", - show_parentheses=True, - ) - async def close_in_app_web_view(self) -> None: - """ - Closes in-app web view opened with `launch_url()`. - - 📱 Mobile only. - """ - await UrlLauncher().close_in_app_web_view() - @property def session(self) -> "Session": """ diff --git a/website/docs/cookbook/authentication.md b/website/docs/cookbook/authentication.md index 29e73dd5bd..cf3b704531 100644 --- a/website/docs/cookbook/authentication.md +++ b/website/docs/cookbook/authentication.md @@ -392,7 +392,7 @@ You can also change web app to open provider's authorization page in the same ta ```python page.login( provider, - on_open_authorization_url=lambda url: asyncio.create_task(page.launch_url(url, web_window_name="_self")), + on_open_authorization_url=lambda url: asyncio.create_task(ft.UrlLauncher().launch_url(url, web_only_window_name="_self")), redirect_to_page=True ) ``` @@ -402,7 +402,7 @@ To open flow in a new tab (notice `_self` replaced with `_blank`): ```python page.login( provider, - on_open_authorization_url=lambda url: asyncio.create_task(page.launch_url(url, web_window_name="_blank")) + on_open_authorization_url=lambda url: asyncio.create_task(ft.UrlLauncher().launch_url(url, web_only_window_name="_blank")) ) ``` From eaf1a7fe83d5075658a9a08dce7ef9d3d92ab927 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Sat, 18 Jul 2026 12:46:13 +0200 Subject: [PATCH 6/9] Restore DropdownM2 as a non-deprecated control Reverses the DropdownM2 removal from 76e33fa8e and drops its deprecation: - Restore the Python control, the Dart widget + its control registration, and the docs page - Strip the @deprecated_class decorator (and its import) so DropdownM2 is no longer deprecated - Re-add the flet package exports (class + module) and the sidebar entry DropdownM2 remains a supported control; its 0.84.0 deprecation in favor of Dropdown is reverted. --- CHANGELOG.md | 5 +- .../flet/lib/src/controls/dropdownm2.dart | 180 ++++++++++++++ .../flet/lib/src/flet_core_extension.dart | 3 + sdk/python/packages/flet/src/flet/__init__.py | 6 + .../src/flet/controls/material/dropdownm2.py | 219 ++++++++++++++++++ .../controls/material/form_field_control.py | 3 +- website/docs/controls/dropdownm2.md | 8 + website/sidebars.yml | 1 + 8 files changed, 423 insertions(+), 2 deletions(-) create mode 100644 packages/flet/lib/src/controls/dropdownm2.dart create mode 100644 sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py create mode 100644 website/docs/controls/dropdownm2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 96fa3d05ce..809d4aad56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,6 @@ * Remove the `Page.url_launcher`, `Page.browser_context_menu`, `Page.shared_preferences`, `Page.clipboard`, and `Page.storage_paths` service accessors (deprecated in `0.80.0`). Instantiate the corresponding service classes directly: `UrlLauncher()`, `BrowserContextMenu()`, `SharedPreferences()`, `Clipboard()`, `StoragePaths()` by @ndonkoHenri. * Remove the `ConstrainedControl` base class (deprecated in `0.80.0`). Inherit from `LayoutControl` instead by @ndonkoHenri. * Remove `ElevatedButton` (deprecated in `0.80.0`). Use `Button` instead by @ndonkoHenri. -* Remove `DropdownM2` and its `dropdownm2` module (deprecated in `0.84.0`). Use `Dropdown` instead by @ndonkoHenri. * Remove the deprecated non-underscored `Colors` aliases (`BLACK12`, `BLACK26`, `BLACK38`, `BLACK45`, `BLACK54`, `BLACK87`, `WHITE10`, `WHITE12`, `WHITE24`, `WHITE30`, `WHITE38`, `WHITE54`, `WHITE60`, `WHITE70`). Use the underscored names instead (e.g. `Colors.BLACK_12`) by @ndonkoHenri. * Remove `app()` and `app_async()` (deprecated in `0.80.0`). Use `run()` and `run_async()` instead by @ndonkoHenri. * Remove the `target` parameter of `run()` and `run_async()` (deprecated alias for `main`). Pass `main` instead by @ndonkoHenri. @@ -19,6 +18,10 @@ * Remove the legacy `[tool.flet.app.boot_screen]` / `[tool.flet.app.startup_screen]` build-config fallback. Use `[tool.flet.boot_screen]` with a named screen instead by @ndonkoHenri. * Remove the Dart empty-string (`""`) widget-state key back-compat mapping. Use `"default"` (or `ControlState.DEFAULT`) instead by @ndonkoHenri. +### Changed + +* `DropdownM2` is no longer deprecated and remains a supported control; its `0.84.0` deprecation in favor of `Dropdown` has been reverted by @ndonkoHenri. + ## 0.86.1 ### Improvements diff --git a/packages/flet/lib/src/controls/dropdownm2.dart b/packages/flet/lib/src/controls/dropdownm2.dart new file mode 100644 index 0000000000..b1437a9b3a --- /dev/null +++ b/packages/flet/lib/src/controls/dropdownm2.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/alignment.dart'; +import '../utils/borders.dart'; +import '../utils/colors.dart'; +import '../utils/edge_insets.dart'; +import '../utils/form_field.dart'; +import '../utils/layout.dart'; +import '../utils/numbers.dart'; +import '../utils/text.dart'; +import 'base_controls.dart'; + +class DropdownM2Control extends StatefulWidget { + final Control control; + + DropdownM2Control({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); + + @override + State createState() => _DropdownM2ControlState(); +} + +class _DropdownM2ControlState extends State { + String? _value; + bool _focused = false; + late final FocusNode _focusNode; + + @override + void initState() { + super.initState(); + _focusNode = FocusNode(); + _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + void _onFocusChange() { + setState(() { + _focused = _focusNode.hasFocus; + }); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("DropdownM2.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown DropdownM2 method: $name"); + } + } + + @override + void dispose() { + _focusNode.removeListener(_onFocusChange); + _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("DropdownM2 build: ${widget.control.id}"); + + var textSize = widget.control.getDouble("text_size"); + var color = widget.control.getColor("color", context); + var focusedColor = widget.control.getColor("focused_color", context); + + var textStyle = widget.control + .getTextStyle("text_style", Theme.of(context), const TextStyle())!; + + if (textSize != null) { + textStyle = textStyle.copyWith(fontSize: textSize); + } + + if (focusedColor != null) { + textStyle = textStyle.copyWith( + color: _focused ? focusedColor : (color ?? textStyle.color)); + } + + if (color != null) { + textStyle = textStyle.copyWith(color: color); + } + + if (textStyle.color == null) { + textStyle = + textStyle.copyWith(color: Theme.of(context).colorScheme.onSurface); + } + + var items = widget.control + .children("options") + .map>((Control item) { + item.notifyParent = true; + var textStyle = item.getTextStyle("text_style", Theme.of(context)); + if (item.disabled && textStyle != null) { + textStyle = textStyle.apply(color: Theme.of(context).disabledColor); + } + var value = + item.getString("key") ?? item.getString("text") ?? item.id.toString(); + var content = + item.buildWidget("content") ?? Text(value, style: textStyle); + var alignment = item.getAlignment("alignment"); + if (alignment != null) { + content = Container(alignment: alignment, child: content); + } + return DropdownMenuItem( + enabled: !item.disabled, + value: value, + alignment: alignment ?? AlignmentDirectional.centerStart, + onTap: !item.disabled ? () => item.triggerEvent("click") : null, + child: content); + }).toList(); + + String? value = widget.control.getString("value"); + if (_value != value) { + _value = value; + } + + if (items.where((item) => item.value == value).isEmpty) { + _value = null; + } + + Widget dropDown = DropdownButtonFormField( + style: textStyle, + autofocus: widget.control.getBool("autofocus", false)!, + focusNode: _focusNode, + initialValue: _value, + dropdownColor: widget.control.getColor("bgcolor", context), + enableFeedback: widget.control.getBool("enable_feedback"), + elevation: widget.control.getInt("elevation", 8)!, + padding: widget.control.getPadding("padding"), + itemHeight: widget.control.getDouble("item_height"), + menuMaxHeight: widget.control.getDouble("max_menu_height"), + iconEnabledColor: + widget.control.getColor("select_icon_enabled_color", context), + iconDisabledColor: + widget.control.getColor("select_icon_disabled_color", context), + iconSize: widget.control.getDouble("select_icon_size", 24.0)!, + borderRadius: widget.control.getBorderRadius("border_radius"), + alignment: widget.control.getAlignment("alignment") ?? + AlignmentDirectional.centerStart, + isExpanded: widget.control.getBool("options_fill_horizontally", true)!, + icon: widget.control.buildIconOrWidget("select_icon"), + hint: widget.control.buildWidget("hint"), + disabledHint: widget.control.buildWidget("disabled_hint"), + decoration: buildInputDecoration(context, widget.control, + customSuffix: null, focused: _focused), + onTap: !widget.control.disabled + ? () => widget.control.triggerEvent("click") + : null, + onChanged: widget.control.disabled + ? null + : (String? value) { + _value = value!; + widget.control.updateProperties({"value": value}); + widget.control.triggerEvent("change", value); + }, + items: items, + ); + + if (widget.control.getExpand("expand", 0)! > 0) { + return LayoutControl(control: widget.control, child: dropDown); + } else { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + if (constraints.maxWidth == double.infinity && + widget.control.getDouble("width") == null) { + dropDown = ConstrainedBox( + constraints: const BoxConstraints.tightFor(width: 300), + child: dropDown); + } + + return LayoutControl(control: widget.control, child: dropDown); + }, + ); + } + } +} diff --git a/packages/flet/lib/src/flet_core_extension.dart b/packages/flet/lib/src/flet_core_extension.dart index 6f64f6ffbf..9bb0d0232b 100644 --- a/packages/flet/lib/src/flet_core_extension.dart +++ b/packages/flet/lib/src/flet_core_extension.dart @@ -51,6 +51,7 @@ import 'controls/divider.dart'; import 'controls/drag_target.dart'; import 'controls/draggable.dart'; import 'controls/dropdown.dart'; +import 'controls/dropdownm2.dart'; import 'controls/expansion_panel.dart'; import 'controls/expansion_tile.dart'; import 'controls/flet_app_control.dart'; @@ -252,6 +253,8 @@ class FletCoreExtension extends FletExtension { return DraggableControl(key: key, control: control); case "Dropdown": return DropdownControl(key: key, control: control); + case "DropdownM2": + return DropdownM2Control(key: key, control: control); case "ExpansionPanelList": return ExpansionPanelListControl(key: key, control: control); case "ExpansionTile": diff --git a/sdk/python/packages/flet/src/flet/__init__.py b/sdk/python/packages/flet/src/flet/__init__.py index f953080611..ada04ca522 100644 --- a/sdk/python/packages/flet/src/flet/__init__.py +++ b/sdk/python/packages/flet/src/flet/__init__.py @@ -341,6 +341,7 @@ ) from flet.controls.material import ( dropdown, + dropdownm2, icons, ) from flet.controls.material.alert_dialog import AlertDialog @@ -391,6 +392,7 @@ Dropdown, DropdownOption, ) + from flet.controls.material.dropdownm2 import DropdownM2 from flet.controls.material.expansion_panel import ( ExpansionPanel, ExpansionPanelList, @@ -893,6 +895,7 @@ "DragWillAcceptEvent", "Draggable", "Dropdown", + "DropdownM2", "DropdownOption", "DropdownTheme", "Duration", @@ -1222,6 +1225,7 @@ "cupertino_colors", "cupertino_icons", "dropdown", + "dropdownm2", "icons", "is_route_active", "margin", @@ -1421,6 +1425,7 @@ "DragWillAcceptEvent": "flet.controls.core.drag_target", "Draggable": "flet.controls.core.draggable", "Dropdown": "flet.controls.material.dropdown", + "DropdownM2": "flet.controls.material.dropdownm2", "DropdownOption": "flet.controls.material.dropdown", "DropdownTheme": "flet.controls.theme", "Duration": "flet.controls.duration", @@ -1749,6 +1754,7 @@ "cupertino_colors": "flet.controls.cupertino", "cupertino_icons": "flet.controls.cupertino", "dropdown": "flet.controls.material", + "dropdownm2": "flet.controls.material", "icons": "flet.controls.material", "is_route_active": "flet.components.router", "margin": "flet.controls", diff --git a/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py b/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py new file mode 100644 index 0000000000..cd376226f3 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py @@ -0,0 +1,219 @@ +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.material.form_field_control import FormFieldControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["DropdownM2", "Option"] + + +@control("Option") +class Option(Control): + """ + Represents an item in a dropdown. + """ + + key: Optional[str] = None + """ + Option's key. + + If not specified :attr:`text` will be used as fallback. + + Raises: + ValueError: If neither `key` nor :attr:`text` is provided. + """ + + text: Optional[str] = None + """ + Option's display text. + + If not specified :attr:`key` will be used as fallback. + + Raises: + ValueError: If neither :attr:`key` nor `text` is provided. + """ + + content: Optional[Control] = None + """ + A `Control` to display in this option. If not specified, `text` will be used as \ + fallback, else `text` will be ignored. + """ + + alignment: Optional[Alignment] = None + """ + Defines the alignment of this option in it's container. + + Defaults to `Alignment.center_left()`. + """ + + text_style: Optional[TextStyle] = None + """ + Defines the style of the `text`. + """ + + on_click: Optional[ControlEventHandler["Option"]] = None + """ + Called when this option is clicked. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ctrl.key is not None or ctrl.text is not None, + message="key or text must be specified", + ), + ) + + +@control("DropdownM2") +class DropdownM2(FormFieldControl): + """ + A dropdown lets the user select from a number of items. The dropdown shows the \ + currently selected item as well as an arrow that opens a menu for selecting \ + another item. + + Example: + ```python + ft.DropdownM2( + width=220, + value="Alice", + options=[ + ft.dropdownm2.Option(key="Alice", text="Alice"), + ft.dropdownm2.Option(key="Bob", text="Bob"), + ], + ) + ``` + """ + + value: Optional[str] = None + """ + `key` value of the selected option. + """ + + options: Optional[list[Option]] = None + """ + A list of `Option` controls representing items in this dropdown. + """ + + alignment: Optional[Alignment] = None + """ + Defines how the `hint` or the selected item is positioned within this dropdown. + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + hint_content: Optional[Control] = None + """ + A placeholder `Control` for the dropdown's value that is displayed when `value` is \ + `None`. + """ + + select_icon: Optional[IconDataOrControl] = None + """ + The [name of the icon](https://flet.dev/docs/types/icons) or `Control` to use \ + for the drop-down select button's icon. + + Defaults to `Icon(ft.Icons.ARROW_DROP_DOWN)`. + """ + + elevation: Number = 8 + """ + The dropdown's elevation. + """ + + item_height: Optional[Number] = None + """ + The height of the items/options in the dropdown menu. + """ + + max_menu_height: Optional[Number] = None + """ + The maximum height of the dropdown menu. + """ + + select_icon_size: Number = 24.0 + """ + The size of the icon button which wraps `select_icon`. + """ + + enable_feedback: Optional[bool] = None + """ + Whether detected gestures should provide acoustic and/or haptic feedback. On \ + Android, for example, setting this to `True` produce a click sound and a \ + long-press will produce a short vibration. + """ + + padding: Optional[PaddingValue] = None + """ + The padding around the visible portion of this dropdown. + """ + + select_icon_enabled_color: Optional[ColorValue] = None + """ + The color of any `Icon` descendant of `select_icon` if this button is enabled. + """ + + select_icon_disabled_color: Optional[ColorValue] = None + """ + The color of any `Icon` descendant of `select_icon` if this button is disabled. + """ + + options_fill_horizontally: bool = True + """ + Whether the dropdown's inner contents to horizontally fill its parent. + By default this button's inner width is the minimum size of its content. + + If `True`, the inner width is expanded to fill its surrounding container. + """ + + disabled_hint_content: Optional[Control] = None + """ + A placeholder `Control` for the dropdown's value that is displayed when `value` is \ + `None` and the dropdown is disabled. + """ + + on_change: Optional[ControlEventHandler["DropdownM2"]] = None + """ + Called when the selected item of this dropdown has changed. + """ + + on_focus: Optional[ControlEventHandler["DropdownM2"]] = None + """ + Called when the control has received focus. + """ + + on_blur: Optional[ControlEventHandler["DropdownM2"]] = None + """ + Called when the control has lost focus. + """ + + on_click: Optional[ControlEventHandler["DropdownM2"]] = None + """ + Called when this dropdown is clicked. + """ + + def before_update(self): + super().before_update() + if ( + self.bgcolor is not None + or self.fill_color is not None + or self.focused_bgcolor is not None + ) and self.filled is None: + self.filled = True # required to display any of the above colors + + def __contains__(self, item): + return item in self.options diff --git a/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py b/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py index 0005b217af..d4a5271476 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py +++ b/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py @@ -46,7 +46,8 @@ class FormFieldControl(LayoutControl): Base class for Material form-field controls with a decorated input area. It provides the shared label, hint, helper, error, prefix, suffix, fill, and - border properties used by controls such as :class:`~flet.TextField`. + border properties used by controls such as :class:`~flet.TextField` and + :class:`~flet.DropdownM2`. """ text_size: Optional[Number] = None diff --git a/website/docs/controls/dropdownm2.md b/website/docs/controls/dropdownm2.md new file mode 100644 index 0000000000..e55db7ff94 --- /dev/null +++ b/website/docs/controls/dropdownm2.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.DropdownM2" +title: "DropdownM2" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/sidebars.yml b/website/sidebars.yml index a1bb7d67a5..206c97b79d 100644 --- a/website/sidebars.yml +++ b/website/sidebars.yml @@ -195,6 +195,7 @@ docs: Dropdown: _index: controls/dropdown/index.md DropdownOption: controls/dropdownoption.md + DropdownM2: controls/dropdownm2.md ExpansionPanel: controls/expansionpanel.md ExpansionPanelList: controls/expansionpanellist.md ExpansionTile: controls/expansiontile.md From fdb2ae96704b818c6f1bb39c679e32dc747a8bca Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Sat, 18 Jul 2026 13:09:22 +0200 Subject: [PATCH 7/9] Fix map examples launching URLs from a sync lambda (coroutine never awaited) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SimpleAttribution.on_click used `lambda e: ft.UrlLauncher().launch_url(...)`, but launch_url is async — Flet's sync-handler dispatch calls the lambda and discards the returned coroutine, so it was never awaited and the click did nothing. Replace with a proper `async def` handler that Flet awaits. This was a pre-existing bug (the prior `page.launch_url()` form was also async). --- sdk/python/examples/extensions/map/camera_controls/main.py | 7 ++++--- sdk/python/examples/extensions/map/idle_camera/main.py | 7 ++++--- .../examples/extensions/map/interaction_flags/main.py | 7 ++++--- sdk/python/examples/extensions/map/multi_layers/main.py | 7 ++++--- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/sdk/python/examples/extensions/map/camera_controls/main.py b/sdk/python/examples/extensions/map/camera_controls/main.py index e44875ced1..f43c4e440d 100644 --- a/sdk/python/examples/extensions/map/camera_controls/main.py +++ b/sdk/python/examples/extensions/map/camera_controls/main.py @@ -5,6 +5,9 @@ def main(page: ft.Page): page.padding = 16 + async def open_attribution(e: ft.Event[ftm.SimpleAttribution]): + await ft.UrlLauncher().launch_url("https://www.openstreetmap.org/copyright") + async def update_camera_status(trigger: str): camera = await my_map.get_camera() camera_status.value = ( @@ -81,9 +84,7 @@ async def set_world_zoom(e: ft.Event[ft.Button]): ), ftm.SimpleAttribution( text="OpenStreetMap contributors", - on_click=lambda e: ft.UrlLauncher().launch_url( - "https://www.openstreetmap.org/copyright" - ), + on_click=open_attribution, ), ftm.MarkerLayer( markers=[ diff --git a/sdk/python/examples/extensions/map/idle_camera/main.py b/sdk/python/examples/extensions/map/idle_camera/main.py index 310bdbb4bb..1109fc97cc 100644 --- a/sdk/python/examples/extensions/map/idle_camera/main.py +++ b/sdk/python/examples/extensions/map/idle_camera/main.py @@ -13,6 +13,9 @@ def main(page: ft.Page): page.padding = 16 + async def open_attribution(e: ft.Event[ftm.SimpleAttribution]): + await ft.UrlLauncher().launch_url("https://www.openstreetmap.org/copyright") + async def handle_map_event(e: ftm.MapEvent): last_event.value = ( "Last event: " @@ -68,9 +71,7 @@ async def handle_map_event(e: ftm.MapEvent): ), ftm.SimpleAttribution( text="OpenStreetMap contributors", - on_click=lambda e: ft.UrlLauncher().launch_url( - "https://www.openstreetmap.org/copyright" - ), + on_click=open_attribution, ), ], ), diff --git a/sdk/python/examples/extensions/map/interaction_flags/main.py b/sdk/python/examples/extensions/map/interaction_flags/main.py index a668c8a723..6b7db88d7d 100644 --- a/sdk/python/examples/extensions/map/interaction_flags/main.py +++ b/sdk/python/examples/extensions/map/interaction_flags/main.py @@ -16,6 +16,9 @@ def main(page: ft.Page): page.padding = 16 + async def open_attribution(e: ft.Event[ftm.SimpleAttribution]): + await ft.UrlLauncher().launch_url("https://www.openstreetmap.org/copyright") + def get_selected_flags() -> ftm.InteractionFlag: flags = ftm.InteractionFlag.NONE for checkbox in checkboxes: @@ -62,9 +65,7 @@ def handle_map_event(e: ftm.MapEvent): ), ftm.SimpleAttribution( text="OpenStreetMap contributors", - on_click=lambda e: ft.UrlLauncher().launch_url( - "https://www.openstreetmap.org/copyright" - ), + on_click=open_attribution, ), ], ) diff --git a/sdk/python/examples/extensions/map/multi_layers/main.py b/sdk/python/examples/extensions/map/multi_layers/main.py index 2c84a67923..7ae7e95f58 100644 --- a/sdk/python/examples/extensions/map/multi_layers/main.py +++ b/sdk/python/examples/extensions/map/multi_layers/main.py @@ -5,6 +5,9 @@ def main(page: ft.Page): + async def open_attribution(e: ft.Event[ftm.SimpleAttribution]): + await ft.UrlLauncher().launch_url("https://www.openstreetmap.org/copyright") + def handle_tap(e: ftm.MapTapEvent): if e.name == "tap": marker_layer.markers.append( @@ -56,9 +59,7 @@ def handle_tap(e: ftm.MapTapEvent): ), ftm.SimpleAttribution( text="OpenStreetMap contributors", - on_click=lambda e: ft.UrlLauncher().launch_url( - "https://www.openstreetmap.org/copyright" - ), + on_click=open_attribution, ), marker_layer := ftm.MarkerLayer( markers=[ From 568a64642b2c62dedef55503b6789e123fe7613a Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Sat, 18 Jul 2026 13:31:16 +0200 Subject: [PATCH 8/9] Reference removal PR #6693 in the 1.0.0 changelog and migration guides Point the 1.0.0 CHANGELOG entries (root + flet-video) at the removal PR #6693 instead of the original deprecation PRs, and add #6693 to the References of the drag-target/video/clear-cache migration guides. --- CHANGELOG.md | 32 +++++++++---------- sdk/python/packages/flet-video/CHANGELOG.md | 4 +-- ...eprecated-drag-target-event-coordinates.md | 2 +- .../v0-85-0/deprecated-video-apis.md | 2 +- .../v0-86-0/deprecated-clear-cache-flag.md | 2 +- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 809d4aad56..ba67d75b91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,25 +2,25 @@ ### Breaking changes -* Remove `DragTargetEvent.x`, `DragTargetEvent.y`, and `DragTargetEvent.offset` (deprecated in `0.85.0`). Use `DragTargetEvent.local_position` for target-relative coordinates or `DragTargetEvent.global_position` for global coordinates ([#6401](https://github.com/flet-dev/flet/pull/6401)) by @ndonkoHenri. -* Remove `Video.show_controls` (deprecated in `0.85.0`). Set `Video.controls` to `None` to hide controls ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. -* Remove `Video.playlist_add()` and `Video.playlist_remove()` (deprecated in `0.85.0`). Mutate `Video.playlist` directly with list methods such as `append()` and `pop()` ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. -* Remove `FletApp.show_app_startup_screen` and `FletApp.app_startup_screen_message` (deprecated in `0.86.0`). Use `FletApp.boot_screen_options` instead, e.g. `boot_screen_options={'spinner_size': 30}` or `boot_screen_options={'startup_message': '...'}` by @ndonkoHenri. -* Remove the `--clear-cache` flag of `flet build` and `flet debug` (deprecated in `0.86.0`). Use the `flet clean` command instead ([#6233](https://github.com/flet-dev/flet/issues/6233)) by @ndonkoHenri. -* Remove `Page.go()` (deprecated in `0.80.0`). Use `Page.push_route()` instead by @ndonkoHenri. -* Remove the `Page.url_launcher`, `Page.browser_context_menu`, `Page.shared_preferences`, `Page.clipboard`, and `Page.storage_paths` service accessors (deprecated in `0.80.0`). Instantiate the corresponding service classes directly: `UrlLauncher()`, `BrowserContextMenu()`, `SharedPreferences()`, `Clipboard()`, `StoragePaths()` by @ndonkoHenri. -* Remove the `ConstrainedControl` base class (deprecated in `0.80.0`). Inherit from `LayoutControl` instead by @ndonkoHenri. -* Remove `ElevatedButton` (deprecated in `0.80.0`). Use `Button` instead by @ndonkoHenri. -* Remove the deprecated non-underscored `Colors` aliases (`BLACK12`, `BLACK26`, `BLACK38`, `BLACK45`, `BLACK54`, `BLACK87`, `WHITE10`, `WHITE12`, `WHITE24`, `WHITE30`, `WHITE38`, `WHITE54`, `WHITE60`, `WHITE70`). Use the underscored names instead (e.g. `Colors.BLACK_12`) by @ndonkoHenri. -* Remove `app()` and `app_async()` (deprecated in `0.80.0`). Use `run()` and `run_async()` instead by @ndonkoHenri. -* Remove the `target` parameter of `run()` and `run_async()` (deprecated alias for `main`). Pass `main` instead by @ndonkoHenri. -* Remove `Page.launch_url()`, `Page.can_launch_url()`, and `Page.close_in_app_web_view()` (deprecated in `0.90.0`). Use `UrlLauncher().launch_url()` / `.can_launch_url()` / `.close_in_app_web_view()` instead by @ndonkoHenri. -* Remove the legacy `[tool.flet.app.boot_screen]` / `[tool.flet.app.startup_screen]` build-config fallback. Use `[tool.flet.boot_screen]` with a named screen instead by @ndonkoHenri. -* Remove the Dart empty-string (`""`) widget-state key back-compat mapping. Use `"default"` (or `ControlState.DEFAULT`) instead by @ndonkoHenri. +* Remove `DragTargetEvent.x`, `DragTargetEvent.y`, and `DragTargetEvent.offset` (deprecated in `0.85.0`). Use `DragTargetEvent.local_position` for target-relative coordinates or `DragTargetEvent.global_position` for global coordinates ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove `Video.show_controls` (deprecated in `0.85.0`). Set `Video.controls` to `None` to hide controls ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove `Video.playlist_add()` and `Video.playlist_remove()` (deprecated in `0.85.0`). Mutate `Video.playlist` directly with list methods such as `append()` and `pop()` ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove `FletApp.show_app_startup_screen` and `FletApp.app_startup_screen_message` (deprecated in `0.86.0`). Use `FletApp.boot_screen_options` instead, e.g. `boot_screen_options={'spinner_size': 30}` or `boot_screen_options={'startup_message': '...'}` ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove the `--clear-cache` flag of `flet build` and `flet debug` (deprecated in `0.86.0`). Use the `flet clean` command instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove `Page.go()` (deprecated in `0.80.0`). Use `Page.push_route()` instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove the `Page.url_launcher`, `Page.browser_context_menu`, `Page.shared_preferences`, `Page.clipboard`, and `Page.storage_paths` service accessors (deprecated in `0.80.0`). Instantiate the corresponding service classes directly: `UrlLauncher()`, `BrowserContextMenu()`, `SharedPreferences()`, `Clipboard()`, `StoragePaths()` ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove the `ConstrainedControl` base class (deprecated in `0.80.0`). Inherit from `LayoutControl` instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove `ElevatedButton` (deprecated in `0.80.0`). Use `Button` instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove the deprecated non-underscored `Colors` aliases (`BLACK12`, `BLACK26`, `BLACK38`, `BLACK45`, `BLACK54`, `BLACK87`, `WHITE10`, `WHITE12`, `WHITE24`, `WHITE30`, `WHITE38`, `WHITE54`, `WHITE60`, `WHITE70`). Use the underscored names instead (e.g. `Colors.BLACK_12`) ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove `app()` and `app_async()` (deprecated in `0.80.0`). Use `run()` and `run_async()` instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove the `target` parameter of `run()` and `run_async()` (deprecated alias for `main`). Pass `main` instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove `Page.launch_url()`, `Page.can_launch_url()`, and `Page.close_in_app_web_view()` (deprecated in `0.90.0`). Use `UrlLauncher().launch_url()` / `.can_launch_url()` / `.close_in_app_web_view()` instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove the legacy `[tool.flet.app.boot_screen]` / `[tool.flet.app.startup_screen]` build-config fallback. Use `[tool.flet.boot_screen]` with a named screen instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +* Remove the Dart empty-string (`""`) widget-state key back-compat mapping. Use `"default"` (or `ControlState.DEFAULT`) instead ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. ### Changed -* `DropdownM2` is no longer deprecated and remains a supported control; its `0.84.0` deprecation in favor of `Dropdown` has been reverted by @ndonkoHenri. +* `DropdownM2` is no longer deprecated and remains a supported control; its `0.84.0` deprecation in favor of `Dropdown` has been reverted ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. ## 0.86.1 diff --git a/sdk/python/packages/flet-video/CHANGELOG.md b/sdk/python/packages/flet-video/CHANGELOG.md index c6a0107df3..915ee1c960 100644 --- a/sdk/python/packages/flet-video/CHANGELOG.md +++ b/sdk/python/packages/flet-video/CHANGELOG.md @@ -9,8 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Removed -- `Video.show_controls` (deprecated in 0.85.0); set `Video.controls` to `None` to hide controls ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. -- `Video.playlist_add()` and `Video.playlist_remove()` (deprecated in 0.85.0); mutate `Video.playlist` directly with list methods such as `append()` and `pop()` ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. +- `Video.show_controls` (deprecated in 0.85.0); set `Video.controls` to `None` to hide controls ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. +- `Video.playlist_add()` and `Video.playlist_remove()` (deprecated in 0.85.0); mutate `Video.playlist` directly with list methods such as `append()` and `pop()` ([#6693](https://github.com/flet-dev/flet/pull/6693)) by @ndonkoHenri. ## 0.85.0 diff --git a/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md b/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md index 5e603dd62c..f55a9179c9 100644 --- a/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md +++ b/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md @@ -60,5 +60,5 @@ If your code needs page-level coordinates instead, use ## References - API documentation: [`DragTargetEvent`][flet.DragTargetEvent] -- Issues and PRs: [#6387](https://github.com/flet-dev/flet/issues/6387), [#6401](https://github.com/flet-dev/flet/pull/6401) +- Issues and PRs: [#6387](https://github.com/flet-dev/flet/issues/6387), [#6401](https://github.com/flet-dev/flet/pull/6401), [#6693](https://github.com/flet-dev/flet/pull/6693) (removal) - Release notes: [Flet 0.85.0](../../release-notes.md#085x) diff --git a/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md b/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md index 8ba5dcfc95..0cbf44f2d8 100644 --- a/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md +++ b/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md @@ -79,5 +79,5 @@ been added to the page. ## References - API documentation: [`Video`][flet_video.Video] -- Issues and PRs: [PR #6463](https://github.com/flet-dev/flet/pull/6463) +- Issues and PRs: [PR #6463](https://github.com/flet-dev/flet/pull/6463), [PR #6693](https://github.com/flet-dev/flet/pull/6693) (removal) - Release notes: [Flet 0.85.0](../../release-notes.md#085x) diff --git a/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md b/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md index 868350abd6..3cf9922d67 100644 --- a/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md +++ b/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md @@ -55,5 +55,5 @@ current directory), so you can target another project with `flet clean path/to/a ## References - CLI documentation: [`flet clean`](../../../cli/flet-clean.md), [`flet build`](../../../cli/flet-build.md) -- Issues and PRs: [#6233](https://github.com/flet-dev/flet/issues/6233) +- Issues and PRs: [#6233](https://github.com/flet-dev/flet/issues/6233), [#6693](https://github.com/flet-dev/flet/pull/6693) (removal) - Release notes: [Flet 0.86.0](../../release-notes.md) From 218947c341f73e89b26af2a948f500865641c3c4 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Sat, 18 Jul 2026 13:47:09 +0200 Subject: [PATCH 9/9] Fix docs build: ContextMenu docstring referenced removed Page.browser_context_menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ContextMenu docstring linked `:attr:`flet.Page.browser_context_menu``, which this PR removes — leaving an unresolved reST xref that failed the docs build's cross-reference check (`docs/controls/contextmenu`). Point it at the `BrowserContextMenu` service directly. Verified locally with the full `yarn build` + `check_docs` sequence — all checks pass. --- .../flet/src/flet/controls/material/context_menu.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/python/packages/flet/src/flet/controls/material/context_menu.py b/sdk/python/packages/flet/src/flet/controls/material/context_menu.py index b426df9e69..36a8a3d99c 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/context_menu.py +++ b/sdk/python/packages/flet/src/flet/controls/material/context_menu.py @@ -97,9 +97,9 @@ class ContextMenu(LayoutControl): Wraps its :attr:`content` and displays contextual menus for specific mouse events. Tip: - On web, call :meth:`flet.BrowserContextMenu.disable` method of - :attr:`flet.Page.browser_context_menu` to suppress the default browser - context menu before relying on custom menus. + On web, call [`BrowserContextMenu.disable()`][flet.BrowserContextMenu.disable] + method to suppress the default browser context menu before relying + on custom menus. """ content: Annotated[