From 70bde22ec4dd691580513ff8e4474e14d7f0033f Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 12:34:29 -0700 Subject: [PATCH 01/96] Move chip examples into package dirs and update docs Refactor chip examples into package folders (assist_chips, filter_chips): add main.py and __init__.py, add pyproject.toml metadata for each example, and wrap UI in SafeArea/Column where appropriate. Remove the old top-level assist_chips.py and filter_chips.py scripts. Update docs to reference the new example paths (assist_chips/main.py and filter_chips/main.py). Also minor code tweaks: simplified click handlers (removed explicit page.update and adjusted handler implementations) and a placeholder pass for amenity selection handler. --- .../examples/controls/chip/assist_chips.py | 38 ------------------ .../controls/chip/assist_chips/__init__.py | 1 + .../controls/chip/assist_chips/main.py | 38 ++++++++++++++++++ .../controls/chip/assist_chips/pyproject.toml | 26 +++++++++++++ .../examples/controls/chip/filter_chips.py | 33 ---------------- .../controls/chip/filter_chips/__init__.py | 1 + .../controls/chip/filter_chips/main.py | 39 +++++++++++++++++++ .../controls/chip/filter_chips/pyproject.toml | 26 +++++++++++++ .../packages/flet/docs/controls/chip.md | 4 +- 9 files changed, 133 insertions(+), 73 deletions(-) delete mode 100644 sdk/python/examples/controls/chip/assist_chips.py create mode 100644 sdk/python/examples/controls/chip/assist_chips/__init__.py create mode 100644 sdk/python/examples/controls/chip/assist_chips/main.py create mode 100644 sdk/python/examples/controls/chip/assist_chips/pyproject.toml delete mode 100644 sdk/python/examples/controls/chip/filter_chips.py create mode 100644 sdk/python/examples/controls/chip/filter_chips/__init__.py create mode 100644 sdk/python/examples/controls/chip/filter_chips/main.py create mode 100644 sdk/python/examples/controls/chip/filter_chips/pyproject.toml diff --git a/sdk/python/examples/controls/chip/assist_chips.py b/sdk/python/examples/controls/chip/assist_chips.py deleted file mode 100644 index 188709c0cb..0000000000 --- a/sdk/python/examples/controls/chip/assist_chips.py +++ /dev/null @@ -1,38 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_chip1_click(e: ft.Event[ft.Chip]): - e.control.label.value = "Saved to favorites" - e.control.leading = ft.Icon(ft.Icons.FAVORITE_OUTLINED) - e.control.disabled = True - page.update() - - async def handle_chip2_click(e: ft.Event[ft.Chip]): - await page.launch_url("https://maps.google.com") - page.update() - - page.add( - ft.Row( - controls=[ - ft.Chip( - label=ft.Text("Save to favourites"), - leading=ft.Icon(ft.Icons.FAVORITE_BORDER_OUTLINED), - bgcolor=ft.Colors.GREEN_200, - disabled_color=ft.Colors.GREEN_100, - autofocus=True, - on_click=handle_chip1_click, - ), - ft.Chip( - label=ft.Text("9 min walk"), - leading=ft.Icon(ft.Icons.MAP_SHARP), - bgcolor=ft.Colors.GREEN_200, - on_click=handle_chip2_click, - ), - ] - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/chip/assist_chips/__init__.py b/sdk/python/examples/controls/chip/assist_chips/__init__.py new file mode 100644 index 0000000000..45afd30165 --- /dev/null +++ b/sdk/python/examples/controls/chip/assist_chips/__init__.py @@ -0,0 +1 @@ +from .main import main as main diff --git a/sdk/python/examples/controls/chip/assist_chips/main.py b/sdk/python/examples/controls/chip/assist_chips/main.py new file mode 100644 index 0000000000..48fc91e6d6 --- /dev/null +++ b/sdk/python/examples/controls/chip/assist_chips/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_chip1_click(e: ft.Event[ft.Chip]): + e.control.label.value = "Saved to favorites" + e.control.leading = ft.Icon(ft.Icons.FAVORITE_OUTLINED) + e.control.disabled = True + + async def handle_chip2_click(e: ft.Event[ft.Chip]): + await page.launch_url("https://maps.google.com") + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Chip( + label=ft.Text("Save to favourites"), + leading=ft.Icon(ft.Icons.FAVORITE_BORDER_OUTLINED), + bgcolor=ft.Colors.GREEN_200, + disabled_color=ft.Colors.GREEN_100, + autofocus=True, + on_click=handle_chip1_click, + ), + ft.Chip( + label=ft.Text("9 min walk"), + leading=ft.Icon(ft.Icons.MAP_SHARP), + bgcolor=ft.Colors.GREEN_200, + on_click=handle_chip2_click, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/chip/assist_chips/pyproject.toml b/sdk/python/examples/controls/chip/assist_chips/pyproject.toml new file mode 100644 index 0000000000..fe88e9c36b --- /dev/null +++ b/sdk/python/examples/controls/chip/assist_chips/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "chip-assist-chips" +version = "1.0.0" +description = "Assist chips with click actions and dynamic state updates." +requires-python = ">=3.10" +keywords = ["chip", "assist chip", "material", "input", "actions", "async", "url launch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Chip", "Apps/Basic controls"] + +[tool.flet.metadata] +title = "Assist chips" +controls = ["SafeArea", "Row", "Chip", "Icon", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["click handling", "async url launch", "dynamic chip state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/chip/filter_chips.py b/sdk/python/examples/controls/chip/filter_chips.py deleted file mode 100644 index aaf1d71a3c..0000000000 --- a/sdk/python/examples/controls/chip/filter_chips.py +++ /dev/null @@ -1,33 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_amenity_selection(e: ft.Event[ft.Chip]): - page.update() - - amenities = ["Washer / Dryer", "Ramp access", "Dogs OK", "Cats OK", "Smoke-free"] - - page.add( - ft.Row( - controls=[ - ft.Icon(ft.Icons.HOTEL_CLASS), - ft.Text("Amenities"), - ] - ), - ft.Row( - controls=[ - ft.Chip( - label=ft.Text(amenity), - bgcolor=ft.Colors.GREEN_200, - disabled_color=ft.Colors.GREEN_100, - autofocus=True, - on_select=handle_amenity_selection, - ) - for amenity in amenities - ] - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/chip/filter_chips/__init__.py b/sdk/python/examples/controls/chip/filter_chips/__init__.py new file mode 100644 index 0000000000..45afd30165 --- /dev/null +++ b/sdk/python/examples/controls/chip/filter_chips/__init__.py @@ -0,0 +1 @@ +from .main import main as main diff --git a/sdk/python/examples/controls/chip/filter_chips/main.py b/sdk/python/examples/controls/chip/filter_chips/main.py new file mode 100644 index 0000000000..75fe21c4ef --- /dev/null +++ b/sdk/python/examples/controls/chip/filter_chips/main.py @@ -0,0 +1,39 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_amenity_selection(e: ft.Event[ft.Chip]): + pass + + amenities = ["Washer / Dryer", "Ramp access", "Dogs OK", "Cats OK", "Smoke-free"] + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Icon(ft.Icons.HOTEL_CLASS), + ft.Text("Amenities"), + ] + ), + ft.Row( + controls=[ + ft.Chip( + label=ft.Text(amenity), + bgcolor=ft.Colors.GREEN_200, + disabled_color=ft.Colors.GREEN_100, + autofocus=True, + on_select=handle_amenity_selection, + ) + for amenity in amenities + ] + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/chip/filter_chips/pyproject.toml b/sdk/python/examples/controls/chip/filter_chips/pyproject.toml new file mode 100644 index 0000000000..8732c3aca3 --- /dev/null +++ b/sdk/python/examples/controls/chip/filter_chips/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "chip-filter-chips" +version = "1.0.0" +description = "Filter chips for amenity selection with on_select events." +requires-python = ">=3.10" +keywords = ["chip", "filter chip", "material", "input", "selection", "filters"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Chip", "Apps/Basic controls"] + +[tool.flet.metadata] +title = "Filter chips" +controls = ["SafeArea", "Column", "Row", "Chip", "Icon", "Text"] +layout_pattern = "filter-bar" +complexity = "basic" +features = ["selection handling", "chip toggles", "event-driven filtering UI"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/chip.md b/sdk/python/packages/flet/docs/controls/chip.md index a353f33e68..6a3f0eabf3 100644 --- a/sdk/python/packages/flet/docs/controls/chip.md +++ b/sdk/python/packages/flet/docs/controls/chip.md @@ -21,7 +21,7 @@ They represent smart or automated actions that appear dynamically and contextual An alternative to assist chips are buttons, which should appear persistently and consistently. ```python ---8<-- "{{ examples }}/assist_chips.py" +--8<-- "{{ examples }}/assist_chips/main.py" ``` {{ image(example_media + "/assist_chips.png", alt="assist-chips", width="80%") }} @@ -35,7 +35,7 @@ They use tags or descriptive words provided in the [`label`][flet.Chip.label] to They can be a good alternative to switches or checkboxes. ```python ---8<-- "{{ examples }}/filter_chips.py" +--8<-- "{{ examples }}/filter_chips/main.py" ``` {{ image(example_media + "/filter_chips.png", alt="filter-chips", width="80%") }} From f63da9becb0ece82db85a0856cfdfe90e3dc7023 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 12:42:43 -0700 Subject: [PATCH 02/96] Add create-flet-example-projects skill doc Introduce a new .codex skill describing how to convert flat Flet example .py files into standalone example projects. The guide defines required project layout (main.py, pyproject.toml, assets/, __init__.py), metadata inference rules, dependency inference, mobile-safety recommendations, docs/tests update steps, and validation/checklist commands to ensure correct migration and indexing for Gallery/MCP. --- .../create-flet-example-projects/SKILL.md | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 .codex/skills/create-flet-example-projects/SKILL.md diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md new file mode 100644 index 0000000000..d4bb31cc21 --- /dev/null +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -0,0 +1,80 @@ +--- +name: create-flet-example-projects +description: Use when asked to create Flet example projects from flat .py files with main.py and pyproject.toml metadata for Gallery/MCP indexing. +--- + +## When to use + +Use this skill when a user asks to create one control/example folder (for example `examples/controls/chip`) in the project-per-example format. + +## Goal + +Turn each runnable example file into a standalone project containing: + +- `main.py` +- `pyproject.toml` with Gallery/MCP metadata +- `assets/` (if the example uses local assets) +- `__init__.py` when needed for imports/tests + +## Workflow + +1. Inspect source folder. +- Find example modules: `*.py` in the target folder, excluding `__init__.py`. +- Keep existing `media/` unless an example needs local assets copied into its own `assets/`. + +2. Create one folder per example. +- For `foo.py`, create `foo/` and move file to `foo/main.py`. +- Add `foo/__init__.py` with `from .main import main` if examples are imported from tests/docs. + +3. Add `pyproject.toml` for each example project. +- Infer from path and code. +- Required fields: + - `[project]`: `name`, `version`, `description`, `requires-python`, `keywords`, `authors`, `dependencies` + - `[dependency-groups].dev`: include `flet-cli`, `flet-desktop`, `flet-web` + - `[tool.flet.gallery].categories` + - `[tool.flet.metadata]`: `title`, `controls`, `layout_pattern`, `complexity`, `features` + - `[tool.flet]`: `org`, `company`, `copyright` +- Add `[tool.flet].platforms` only when the example is platform-limited. +- Add permissions blocks only when code actually needs them. + +4. Infer metadata. +- Title: readable version of file/folder intent. +- Short description: one line of what the example demonstrates. +- Categories: typically control-based, e.g. `Input/Chip`, plus optional `Apps/Basic controls`. +- Tags: from control/topic/behavior words. +- Controls used: list key controls from code. +- Layout pattern: choose closest practical value (e.g. `filter-bar`, `inline-actions`, `dashboard`, `list-detail`). +- Complexity: `basic` unless logic/state/architecture is non-trivial. +- Features: notable behaviors only (click handling, selection, async loading, drag-and-drop, etc.). + +5. Infer dependencies from imports. +- Always include `flet` for standard examples. +- Include extra packages if imported (for example extension packages). +- Do not add unused dependencies. + +6. Make examples mobile-safe. +- If `ft.context.disable_auto_update()` is not used, do not add explicit `page.update()` unless strictly necessary. +- Wrap app content in `ft.SafeArea` so example renders correctly on mobile. + +7. Update references. +- Docs code includes: change from `.../example.py` to `.../example/main.py`. +- Tests/imports: update module imports to new package paths if needed. + +8. Validate. +- Run `python -m compileall` on changed `main.py` files. +- Search for stale paths to old flat files. +- Check `git status` to confirm expected moves and edits. + +## Command checklist + +- Discover files: `rg --files ` +- Find docs links/imports: `rg -n "" packages examples` +- Syntax check: `python -m compileall ` + +## Output expectations + +Report: +- created example projects +- metadata added +- docs/tests updates +- validation results From 83fbe3b1dafa6e57ba1417a822b3ec23c539d12d Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 17:55:14 -0700 Subject: [PATCH 03/96] Drop example __init__.py and update imports Remove example package __init__.py files and switch tests/docs to import example modules directly. Updated SKILL.md to instruct creating example projects without __init__.py and adjusted test_checkbox imports to use module-level imports (e.g. import examples.controls.checkbox.basic as basic). Deleted: sdk/python/examples/controls/checkbox/__init__.py, sdk/python/examples/controls/chip/__init__.py, sdk/python/examples/controls/chip/assist_chips/__init__.py, sdk/python/examples/controls/chip/filter_chips/__init__.py; modified .codex/skills/create-flet-example-projects/SKILL.md and sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py to match the new import approach. --- .codex/skills/create-flet-example-projects/SKILL.md | 5 ++--- sdk/python/examples/controls/checkbox/__init__.py | 0 sdk/python/examples/controls/chip/__init__.py | 0 sdk/python/examples/controls/chip/assist_chips/__init__.py | 1 - sdk/python/examples/controls/chip/filter_chips/__init__.py | 1 - .../integration_tests/examples/material/test_checkbox.py | 4 +++- 6 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 sdk/python/examples/controls/checkbox/__init__.py delete mode 100644 sdk/python/examples/controls/chip/__init__.py delete mode 100644 sdk/python/examples/controls/chip/assist_chips/__init__.py delete mode 100644 sdk/python/examples/controls/chip/filter_chips/__init__.py diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index d4bb31cc21..ce97a60e28 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -14,7 +14,6 @@ Turn each runnable example file into a standalone project containing: - `main.py` - `pyproject.toml` with Gallery/MCP metadata - `assets/` (if the example uses local assets) -- `__init__.py` when needed for imports/tests ## Workflow @@ -24,7 +23,7 @@ Turn each runnable example file into a standalone project containing: 2. Create one folder per example. - For `foo.py`, create `foo/` and move file to `foo/main.py`. -- Add `foo/__init__.py` with `from .main import main` if examples are imported from tests/docs. +- Do not create `foo/__init__.py`; import example modules directly in tests/docs (for example `import examples.controls.foo.bar.main as bar` or `import examples.controls.foo.bar as bar` when using namespace-package imports). 3. Add `pyproject.toml` for each example project. - Infer from path and code. @@ -58,7 +57,7 @@ Turn each runnable example file into a standalone project containing: 7. Update references. - Docs code includes: change from `.../example.py` to `.../example/main.py`. -- Tests/imports: update module imports to new package paths if needed. +- Tests/imports: use direct module imports and avoid relying on package-level `__init__.py` re-exports. 8. Validate. - Run `python -m compileall` on changed `main.py` files. diff --git a/sdk/python/examples/controls/checkbox/__init__.py b/sdk/python/examples/controls/checkbox/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/chip/__init__.py b/sdk/python/examples/controls/chip/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/chip/assist_chips/__init__.py b/sdk/python/examples/controls/chip/assist_chips/__init__.py deleted file mode 100644 index 45afd30165..0000000000 --- a/sdk/python/examples/controls/chip/assist_chips/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .main import main as main diff --git a/sdk/python/examples/controls/chip/filter_chips/__init__.py b/sdk/python/examples/controls/chip/filter_chips/__init__.py deleted file mode 100644 index 45afd30165..0000000000 --- a/sdk/python/examples/controls/chip/filter_chips/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .main import main as main diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py b/sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py index 627de3da6c..d6648d4ba8 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py @@ -1,8 +1,10 @@ import pytest +import examples.controls.checkbox.basic as basic +import examples.controls.checkbox.handling_events as handling_events +import examples.controls.checkbox.styled as styled import flet as ft import flet.testing as ftt -from examples.controls.checkbox import basic, handling_events, styled @pytest.mark.asyncio(loop_scope="function") From 2f9bd50d2def553eef1e3a634a4b54e6f19ac232 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 18:03:02 -0700 Subject: [PATCH 04/96] Log selected amenity in filter_chips example Replace the no-op handler with a print statement so the example logs the selected amenity when a Chip is activated. This demonstrates event handling by printing the chip's label (e.control.label.value) to the console for debugging and instructional purposes. --- sdk/python/examples/controls/chip/filter_chips/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/python/examples/controls/chip/filter_chips/main.py b/sdk/python/examples/controls/chip/filter_chips/main.py index 75fe21c4ef..d2f4b4ff67 100644 --- a/sdk/python/examples/controls/chip/filter_chips/main.py +++ b/sdk/python/examples/controls/chip/filter_chips/main.py @@ -3,7 +3,7 @@ def main(page: ft.Page): def handle_amenity_selection(e: ft.Event[ft.Chip]): - pass + print("Amenity selected:", e.control.label.value) amenities = ["Washer / Dryer", "Ramp access", "Dogs OK", "Cats OK", "Smoke-free"] From 12f02d90fb341bf872f8adcbd6c52402d3fc9807 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 18:42:01 -0700 Subject: [PATCH 05/96] Reorganize checkbox examples and add pyproject Move checkbox example scripts into per-example main.py files and add pyproject.toml metadata for basic, handling_events, and styled examples. Update docs to reference the new example paths and adjust integration test imports to point to the new modules. Also tweak a gallery category in filter_chips pyproject.toml. These changes standardize example layout and provide per-example metadata for the gallery/tooling. --- .../examples/controls/checkbox/basic.py | 29 --------------- .../examples/controls/checkbox/basic/main.py | 37 +++++++++++++++++++ .../controls/checkbox/basic/pyproject.toml | 26 +++++++++++++ .../controls/checkbox/handling_events.py | 18 --------- .../controls/checkbox/handling_events/main.py | 27 ++++++++++++++ .../checkbox/handling_events/pyproject.toml | 26 +++++++++++++ .../examples/controls/checkbox/styled.py | 25 ------------- .../examples/controls/checkbox/styled/main.py | 30 +++++++++++++++ .../controls/checkbox/styled/pyproject.toml | 26 +++++++++++++ .../controls/chip/filter_chips/pyproject.toml | 2 +- .../packages/flet/docs/controls/checkbox.md | 6 +-- .../examples/material/test_checkbox.py | 6 +-- 12 files changed, 179 insertions(+), 79 deletions(-) delete mode 100644 sdk/python/examples/controls/checkbox/basic.py create mode 100644 sdk/python/examples/controls/checkbox/basic/main.py create mode 100644 sdk/python/examples/controls/checkbox/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/checkbox/handling_events.py create mode 100644 sdk/python/examples/controls/checkbox/handling_events/main.py create mode 100644 sdk/python/examples/controls/checkbox/handling_events/pyproject.toml delete mode 100644 sdk/python/examples/controls/checkbox/styled.py create mode 100644 sdk/python/examples/controls/checkbox/styled/main.py create mode 100644 sdk/python/examples/controls/checkbox/styled/pyproject.toml diff --git a/sdk/python/examples/controls/checkbox/basic.py b/sdk/python/examples/controls/checkbox/basic.py deleted file mode 100644 index e96c6ce105..0000000000 --- a/sdk/python/examples/controls/checkbox/basic.py +++ /dev/null @@ -1,29 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_button_click(e: ft.Event[ft.Button]): - message.value = ( - f"Checkboxes values are: {c1.value}, {c2.value}, {c3.value}, " - f"{c4.value}, {c5.value}." - ) - page.update() - - page.add( - c1 := ft.Checkbox(label="Unchecked by default checkbox", value=False), - c2 := ft.Checkbox( - label="Undefined by default tristate checkbox", tristate=True - ), - c3 := ft.Checkbox(label="Checked by default checkbox", value=True), - c4 := ft.Checkbox(label="Disabled checkbox", disabled=True), - c5 := ft.Checkbox( - label="Checkbox with LEFT label_position", - label_position=ft.LabelPosition.LEFT, - ), - ft.Button(content="Submit", on_click=handle_button_click), - message := ft.Text(), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/checkbox/basic/main.py b/sdk/python/examples/controls/checkbox/basic/main.py new file mode 100644 index 0000000000..e01f91131c --- /dev/null +++ b/sdk/python/examples/controls/checkbox/basic/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = ( + f"Checkboxes values are: {c1.value}, {c2.value}, {c3.value}, " + f"{c4.value}, {c5.value}." + ) + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + c1 := ft.Checkbox( + label="Unchecked by default checkbox", value=False + ), + c2 := ft.Checkbox( + label="Undefined by default tristate checkbox", tristate=True + ), + c3 := ft.Checkbox(label="Checked by default checkbox", value=True), + c4 := ft.Checkbox(label="Disabled checkbox", disabled=True), + c5 := ft.Checkbox( + label="Checkbox with LEFT label_position", + label_position=ft.LabelPosition.LEFT, + ), + ft.Button(content="Submit", on_click=handle_button_click), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/checkbox/basic/pyproject.toml b/sdk/python/examples/controls/checkbox/basic/pyproject.toml new file mode 100644 index 0000000000..bf501bd923 --- /dev/null +++ b/sdk/python/examples/controls/checkbox/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "checkbox-basic" +version = "1.0.0" +description = "Basic checkbox states with a submit action." +requires-python = ">=3.10" +keywords = ["checkbox", "material", "input", "form", "state", "tristate"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Checkbox", "Apps/Basic controls"] + +[tool.flet.metadata] +title = "Basic checkbox" +controls = ["SafeArea", "Column", "Checkbox", "Button", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["checkbox state examples", "button click handling", "value summary output"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/checkbox/handling_events.py b/sdk/python/examples/controls/checkbox/handling_events.py deleted file mode 100644 index 22719231bc..0000000000 --- a/sdk/python/examples/controls/checkbox/handling_events.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_checkbox_change(e: ft.Event[ft.Checkbox]): - page.add(ft.Text(f"Checkbox value changed to {e.control.value}")) - page.update() - - page.add( - ft.Checkbox( - label="Checkbox with 'change' event", - on_change=handle_checkbox_change, - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/checkbox/handling_events/main.py b/sdk/python/examples/controls/checkbox/handling_events/main.py new file mode 100644 index 0000000000..b8cbac804a --- /dev/null +++ b/sdk/python/examples/controls/checkbox/handling_events/main.py @@ -0,0 +1,27 @@ +import flet as ft + + +def main(page: ft.Page): + events = ft.Column() + + def handle_checkbox_change(e: ft.Event[ft.Checkbox]): + events.controls.append(ft.Text(f"Checkbox value changed to {e.control.value}")) + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Checkbox( + label="Checkbox with 'change' event", + on_change=handle_checkbox_change, + ), + events, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/checkbox/handling_events/pyproject.toml b/sdk/python/examples/controls/checkbox/handling_events/pyproject.toml new file mode 100644 index 0000000000..7623eeb768 --- /dev/null +++ b/sdk/python/examples/controls/checkbox/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "checkbox-handling-events" +version = "1.0.0" +description = "Checkbox change event handling with dynamic text updates." +requires-python = ">=3.10" +keywords = ["checkbox", "material", "input", "events", "on_change", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Checkbox", "Apps/Basic controls"] + +[tool.flet.metadata] +title = "Checkbox events" +controls = ["SafeArea", "Column", "Checkbox", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["on_change handling", "event-driven UI updates", "state change log"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/checkbox/styled.py b/sdk/python/examples/controls/checkbox/styled.py deleted file mode 100644 index 951570ff67..0000000000 --- a/sdk/python/examples/controls/checkbox/styled.py +++ /dev/null @@ -1,25 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Checkbox(label="Checkbox with default style"), - ft.Checkbox( - label="Checkbox with constant fill color", - fill_color=ft.Colors.RED, - check_color=ft.Colors.YELLOW, - ), - ft.Checkbox( - label="Checkbox with dynamic fill color", - fill_color={ - ft.ControlState.HOVERED: ft.Colors.BLUE, - ft.ControlState.SELECTED: ft.Colors.GREEN, - ft.ControlState.DEFAULT: ft.Colors.RED, - }, - # border_side={ft.ControlState.HOVERED: ft.BorderSide(width=1.0)}, - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/checkbox/styled/main.py b/sdk/python/examples/controls/checkbox/styled/main.py new file mode 100644 index 0000000000..980fbc2544 --- /dev/null +++ b/sdk/python/examples/controls/checkbox/styled/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Checkbox(label="Checkbox with default style"), + ft.Checkbox( + label="Checkbox with constant fill color", + fill_color=ft.Colors.RED, + check_color=ft.Colors.YELLOW, + ), + ft.Checkbox( + label="Checkbox with dynamic fill color", + fill_color={ + ft.ControlState.HOVERED: ft.Colors.BLUE, + ft.ControlState.SELECTED: ft.Colors.GREEN, + ft.ControlState.DEFAULT: ft.Colors.RED, + }, + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/checkbox/styled/pyproject.toml b/sdk/python/examples/controls/checkbox/styled/pyproject.toml new file mode 100644 index 0000000000..9d8fc7b545 --- /dev/null +++ b/sdk/python/examples/controls/checkbox/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "checkbox-styled" +version = "1.0.0" +description = "Styled checkboxes with fixed and state-based colors." +requires-python = ">=3.10" +keywords = ["checkbox", "material", "input", "styling", "colors", "controlstate"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Checkbox", "Apps/Basic controls"] + +[tool.flet.metadata] +title = "Styled checkboxes" +controls = ["SafeArea", "Column", "Checkbox"] +layout_pattern = "form" +complexity = "basic" +features = ["static styling", "state-based fill colors", "custom check color"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/chip/filter_chips/pyproject.toml b/sdk/python/examples/controls/chip/filter_chips/pyproject.toml index 8732c3aca3..7cb20186e2 100644 --- a/sdk/python/examples/controls/chip/filter_chips/pyproject.toml +++ b/sdk/python/examples/controls/chip/filter_chips/pyproject.toml @@ -11,7 +11,7 @@ dependencies = ["flet"] dev = ["flet-cli", "flet-desktop", "flet-web"] [tool.flet.gallery] -categories = ["Input/Chip", "Apps/Basic controls"] +categories = ["Input controls"] [tool.flet.metadata] title = "Filter chips" diff --git a/sdk/python/packages/flet/docs/controls/checkbox.md b/sdk/python/packages/flet/docs/controls/checkbox.md index 401d0eaea2..63e8eac04f 100644 --- a/sdk/python/packages/flet/docs/controls/checkbox.md +++ b/sdk/python/packages/flet/docs/controls/checkbox.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/checkbox ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="50%", caption="After clicking Submit") }} @@ -22,7 +22,7 @@ example_images: ../test-images/examples/material/golden/macos/checkbox ### Handling events ```python ---8<-- "{{ examples }}/handling_events.py" +--8<-- "{{ examples }}/handling_events/main.py" ``` {{ image(example_images + "/handling_events.png", alt="handling-events", width="50%", caption="After three clicks") }} @@ -31,7 +31,7 @@ example_images: ../test-images/examples/material/golden/macos/checkbox ### Styled checkboxes ```python ---8<-- "{{ examples }}/styled.py" +--8<-- "{{ examples }}/styled/main.py" ``` {{ image(example_images + "/styled_checkboxes.png", alt="Styled checkboxes", width="50%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py b/sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py index d6648d4ba8..e0ccab0563 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_checkbox.py @@ -1,8 +1,8 @@ import pytest -import examples.controls.checkbox.basic as basic -import examples.controls.checkbox.handling_events as handling_events -import examples.controls.checkbox.styled as styled +import examples.controls.checkbox.basic.main as basic +import examples.controls.checkbox.handling_events.main as handling_events +import examples.controls.checkbox.styled.main as styled import flet as ft import flet.testing as ftt From a2cce6520f25b18a8be7279d618624b51c63e6fd Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 18:44:24 -0700 Subject: [PATCH 06/96] Improve create-flet-example-projects skill doc Expand and clarify the SKILL.md for creating Flet example projects: add support for migrating flat examples and normalizing mixed/partially converted folders, detect example states (flat file, project folder, mixed), and adjust the workflow to convert/repair examples without overwriting existing main.py. Add guidance to create or update pyproject.toml metadata, avoid unnecessary edits to already-converted examples, preserve media/asset handling, and enhance validation steps (compile changed main.py, search for stale paths, run targeted integration tests when present). Also clarify import conventions (no __init__.py) and when to update references to avoid churn. --- .../create-flet-example-projects/SKILL.md | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index ce97a60e28..335a0bc4ca 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -5,11 +5,14 @@ description: Use when asked to create Flet example projects from flat .py files ## When to use -Use this skill when a user asks to create one control/example folder (for example `examples/controls/chip`) in the project-per-example format. +Use this skill when a user asks to: +- create one control/example folder (for example `examples/controls/chip`) in the project-per-example format +- migrate existing flat examples to the project-per-example format +- normalize a partially converted folder so all examples follow the same structure ## Goal -Turn each runnable example file into a standalone project containing: +Ensure each runnable example is a standalone project containing: - `main.py` - `pyproject.toml` with Gallery/MCP metadata @@ -18,15 +21,23 @@ Turn each runnable example file into a standalone project containing: ## Workflow 1. Inspect source folder. -- Find example modules: `*.py` in the target folder, excluding `__init__.py`. +- Detect current state per example: + - flat file: `foo.py` + - project folder: `foo/main.py` + - mixed/partial conversion: both styles present or missing metadata files +- Find candidate flat modules: `*.py` in the target folder (exclude helper files such as `__init__.py`). - Keep existing `media/` unless an example needs local assets copied into its own `assets/`. -2. Create one folder per example. +2. Convert or normalize examples. - For `foo.py`, create `foo/` and move file to `foo/main.py`. +- If `foo/main.py` already exists, keep it and do not recreate/move files. +- If folder exists but `main.py` is missing, repair structure only when there is a clear source file. - Do not create `foo/__init__.py`; import example modules directly in tests/docs (for example `import examples.controls.foo.bar.main as bar` or `import examples.controls.foo.bar as bar` when using namespace-package imports). 3. Add `pyproject.toml` for each example project. - Infer from path and code. +- Create missing `pyproject.toml` files for existing project folders. +- Update obviously stale metadata when migrating existing examples (for example wrong title/description/categories). - Required fields: - `[project]`: `name`, `version`, `description`, `requires-python`, `keywords`, `authors`, `dependencies` - `[dependency-groups].dev`: include `flet-cli`, `flet-desktop`, `flet-web` @@ -58,11 +69,13 @@ Turn each runnable example file into a standalone project containing: 7. Update references. - Docs code includes: change from `.../example.py` to `.../example/main.py`. - Tests/imports: use direct module imports and avoid relying on package-level `__init__.py` re-exports. +- For already-converted examples, only update references that are stale; avoid unnecessary churn. 8. Validate. - Run `python -m compileall` on changed `main.py` files. - Search for stale paths to old flat files. - Check `git status` to confirm expected moves and edits. +- When integration tests exist for the touched control, run the targeted test file(s). ## Command checklist From 74b61afc400e0f94a88f55ee1e3cdf7ee46b2367 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 18:48:25 -0700 Subject: [PATCH 07/96] Remove redundant page.update() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary explicit page.update() calls from checkbox examples to avoid redundant UI refreshes. The changes update sdk/python/examples/controls/checkbox/basic/main.py and sdk/python/examples/controls/checkbox/handling_events/main.py — cleaning up minor, non-functional code and relying on the framework's automatic update handling. --- sdk/python/examples/controls/checkbox/basic/main.py | 1 - sdk/python/examples/controls/checkbox/handling_events/main.py | 1 - 2 files changed, 2 deletions(-) diff --git a/sdk/python/examples/controls/checkbox/basic/main.py b/sdk/python/examples/controls/checkbox/basic/main.py index e01f91131c..39d2161d59 100644 --- a/sdk/python/examples/controls/checkbox/basic/main.py +++ b/sdk/python/examples/controls/checkbox/basic/main.py @@ -7,7 +7,6 @@ def handle_button_click(e: ft.Event[ft.Button]): f"Checkboxes values are: {c1.value}, {c2.value}, {c3.value}, " f"{c4.value}, {c5.value}." ) - page.update() page.add( ft.SafeArea( diff --git a/sdk/python/examples/controls/checkbox/handling_events/main.py b/sdk/python/examples/controls/checkbox/handling_events/main.py index b8cbac804a..01588ec09b 100644 --- a/sdk/python/examples/controls/checkbox/handling_events/main.py +++ b/sdk/python/examples/controls/checkbox/handling_events/main.py @@ -6,7 +6,6 @@ def main(page: ft.Page): def handle_checkbox_change(e: ft.Event[ft.Checkbox]): events.controls.append(ft.Text(f"Checkbox value changed to {e.control.value}")) - page.update() page.add( ft.SafeArea( From 4ff0cfccc2734d212771e7a8979cd0c04e91eb9a Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 18:56:47 -0700 Subject: [PATCH 08/96] Reorganize column examples and update metadata Move column example scripts into per-example folders (rename *.py to */main.py) and add per-example pyproject.toml metadata for column examples (alignment, custom_scrollbar, horizontal_alignment, infinite_scrolling, programmatic_scroll, scroll, scroll_events, scroll_to_key, spacing, wrap). Update docs (controls/column.md) to reference new example paths. Also adjust gallery categories in several example pyproject.toml files for checkbox and chip examples (simplify categories to Input/Checkbox or Input/Chip) to keep gallery metadata consistent. --- .../controls/checkbox/basic/pyproject.toml | 2 +- .../checkbox/handling_events/pyproject.toml | 2 +- .../controls/checkbox/styled/pyproject.toml | 2 +- .../controls/chip/assist_chips/pyproject.toml | 2 +- .../controls/chip/filter_chips/pyproject.toml | 2 +- .../{alignment.py => alignment/main.py} | 0 .../controls/column/alignment/pyproject.toml | 26 +++++++++++++++++++ .../main.py} | 0 .../column/custom_scrollbar/pyproject.toml | 26 +++++++++++++++++++ .../main.py} | 0 .../horizontal_alignment/pyproject.toml | 26 +++++++++++++++++++ .../main.py} | 0 .../column/infinite_scrolling/pyproject.toml | 26 +++++++++++++++++++ .../main.py} | 0 .../column/programmatic_scroll/pyproject.toml | 26 +++++++++++++++++++ .../column/{scroll.py => scroll/main.py} | 0 .../controls/column/scroll/pyproject.toml | 26 +++++++++++++++++++ .../main.py} | 0 .../column/scroll_events/pyproject.toml | 26 +++++++++++++++++++ .../main.py} | 0 .../column/scroll_to_key/pyproject.toml | 26 +++++++++++++++++++ .../column/{spacing.py => spacing/main.py} | 0 .../controls/column/spacing/pyproject.toml | 26 +++++++++++++++++++ .../controls/column/{wrap.py => wrap/main.py} | 3 ++- .../controls/column/wrap/pyproject.toml | 26 +++++++++++++++++++ .../packages/flet/docs/controls/column.md | 12 ++++----- 26 files changed, 273 insertions(+), 12 deletions(-) rename sdk/python/examples/controls/column/{alignment.py => alignment/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/alignment/pyproject.toml rename sdk/python/examples/controls/column/{custom_scrollbar.py => custom_scrollbar/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/custom_scrollbar/pyproject.toml rename sdk/python/examples/controls/column/{horizontal_alignment.py => horizontal_alignment/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/horizontal_alignment/pyproject.toml rename sdk/python/examples/controls/column/{infinite_scrolling.py => infinite_scrolling/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/infinite_scrolling/pyproject.toml rename sdk/python/examples/controls/column/{programmatic_scroll.py => programmatic_scroll/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/programmatic_scroll/pyproject.toml rename sdk/python/examples/controls/column/{scroll.py => scroll/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/scroll/pyproject.toml rename sdk/python/examples/controls/column/{scroll_events.py => scroll_events/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/scroll_events/pyproject.toml rename sdk/python/examples/controls/column/{scroll_to_key.py => scroll_to_key/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/scroll_to_key/pyproject.toml rename sdk/python/examples/controls/column/{spacing.py => spacing/main.py} (100%) create mode 100644 sdk/python/examples/controls/column/spacing/pyproject.toml rename sdk/python/examples/controls/column/{wrap.py => wrap/main.py} (96%) create mode 100644 sdk/python/examples/controls/column/wrap/pyproject.toml diff --git a/sdk/python/examples/controls/checkbox/basic/pyproject.toml b/sdk/python/examples/controls/checkbox/basic/pyproject.toml index bf501bd923..5c43b689e5 100644 --- a/sdk/python/examples/controls/checkbox/basic/pyproject.toml +++ b/sdk/python/examples/controls/checkbox/basic/pyproject.toml @@ -11,7 +11,7 @@ dependencies = ["flet"] dev = ["flet-cli", "flet-desktop", "flet-web"] [tool.flet.gallery] -categories = ["Input/Checkbox", "Apps/Basic controls"] +categories = ["Input/Checkbox"] [tool.flet.metadata] title = "Basic checkbox" diff --git a/sdk/python/examples/controls/checkbox/handling_events/pyproject.toml b/sdk/python/examples/controls/checkbox/handling_events/pyproject.toml index 7623eeb768..fce792665c 100644 --- a/sdk/python/examples/controls/checkbox/handling_events/pyproject.toml +++ b/sdk/python/examples/controls/checkbox/handling_events/pyproject.toml @@ -11,7 +11,7 @@ dependencies = ["flet"] dev = ["flet-cli", "flet-desktop", "flet-web"] [tool.flet.gallery] -categories = ["Input/Checkbox", "Apps/Basic controls"] +categories = ["Input/Checkbox"] [tool.flet.metadata] title = "Checkbox events" diff --git a/sdk/python/examples/controls/checkbox/styled/pyproject.toml b/sdk/python/examples/controls/checkbox/styled/pyproject.toml index 9d8fc7b545..ecd06ccd75 100644 --- a/sdk/python/examples/controls/checkbox/styled/pyproject.toml +++ b/sdk/python/examples/controls/checkbox/styled/pyproject.toml @@ -11,7 +11,7 @@ dependencies = ["flet"] dev = ["flet-cli", "flet-desktop", "flet-web"] [tool.flet.gallery] -categories = ["Input/Checkbox", "Apps/Basic controls"] +categories = ["Input/Checkbox"] [tool.flet.metadata] title = "Styled checkboxes" diff --git a/sdk/python/examples/controls/chip/assist_chips/pyproject.toml b/sdk/python/examples/controls/chip/assist_chips/pyproject.toml index fe88e9c36b..3f1b5da46d 100644 --- a/sdk/python/examples/controls/chip/assist_chips/pyproject.toml +++ b/sdk/python/examples/controls/chip/assist_chips/pyproject.toml @@ -11,7 +11,7 @@ dependencies = ["flet"] dev = ["flet-cli", "flet-desktop", "flet-web"] [tool.flet.gallery] -categories = ["Input/Chip", "Apps/Basic controls"] +categories = ["Input/Chip"] [tool.flet.metadata] title = "Assist chips" diff --git a/sdk/python/examples/controls/chip/filter_chips/pyproject.toml b/sdk/python/examples/controls/chip/filter_chips/pyproject.toml index 7cb20186e2..d0c2aea954 100644 --- a/sdk/python/examples/controls/chip/filter_chips/pyproject.toml +++ b/sdk/python/examples/controls/chip/filter_chips/pyproject.toml @@ -11,7 +11,7 @@ dependencies = ["flet"] dev = ["flet-cli", "flet-desktop", "flet-web"] [tool.flet.gallery] -categories = ["Input controls"] +categories = ["Input/Chip"] [tool.flet.metadata] title = "Filter chips" diff --git a/sdk/python/examples/controls/column/alignment.py b/sdk/python/examples/controls/column/alignment/main.py similarity index 100% rename from sdk/python/examples/controls/column/alignment.py rename to sdk/python/examples/controls/column/alignment/main.py diff --git a/sdk/python/examples/controls/column/alignment/pyproject.toml b/sdk/python/examples/controls/column/alignment/pyproject.toml new file mode 100644 index 0000000000..59f3b1f6fb --- /dev/null +++ b/sdk/python/examples/controls/column/alignment/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-alignment" +version = "1.0.0" +description = "Column vertical alignment modes demonstrated side by side." +requires-python = ">=3.10" +keywords = ["column", "layout", "alignment", "mainaxisalignment", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column vertical alignment" +controls = ["Row", "Column", "Container", "Text"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["main axis alignment", "layout comparison", "horizontal scrolling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/custom_scrollbar.py b/sdk/python/examples/controls/column/custom_scrollbar/main.py similarity index 100% rename from sdk/python/examples/controls/column/custom_scrollbar.py rename to sdk/python/examples/controls/column/custom_scrollbar/main.py diff --git a/sdk/python/examples/controls/column/custom_scrollbar/pyproject.toml b/sdk/python/examples/controls/column/custom_scrollbar/pyproject.toml new file mode 100644 index 0000000000..b459a8ca61 --- /dev/null +++ b/sdk/python/examples/controls/column/custom_scrollbar/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-custom-scrollbar" +version = "1.0.0" +description = "Column with a customized scrollbar theme and styled message list." +requires-python = ">=3.10" +keywords = ["column", "layout", "scrollbar", "theme", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column custom scrollbar" +controls = ["Theme", "ScrollbarTheme", "Row", "Column", "Container", "Text"] +layout_pattern = "chat-list" +complexity = "basic" +features = ["custom scrollbar styling", "themed scroll behavior", "scrollable message list"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/horizontal_alignment.py b/sdk/python/examples/controls/column/horizontal_alignment/main.py similarity index 100% rename from sdk/python/examples/controls/column/horizontal_alignment.py rename to sdk/python/examples/controls/column/horizontal_alignment/main.py diff --git a/sdk/python/examples/controls/column/horizontal_alignment/pyproject.toml b/sdk/python/examples/controls/column/horizontal_alignment/pyproject.toml new file mode 100644 index 0000000000..3d6cbf3e84 --- /dev/null +++ b/sdk/python/examples/controls/column/horizontal_alignment/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-horizontal-alignment" +version = "1.0.0" +description = "Column cross-axis alignment modes with visual comparison." +requires-python = ">=3.10" +keywords = ["column", "layout", "crossaxisalignment", "alignment"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column horizontal alignment" +controls = ["Row", "Column", "Container", "Text"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["cross axis alignment", "layout comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/infinite_scrolling.py b/sdk/python/examples/controls/column/infinite_scrolling/main.py similarity index 100% rename from sdk/python/examples/controls/column/infinite_scrolling.py rename to sdk/python/examples/controls/column/infinite_scrolling/main.py diff --git a/sdk/python/examples/controls/column/infinite_scrolling/pyproject.toml b/sdk/python/examples/controls/column/infinite_scrolling/pyproject.toml new file mode 100644 index 0000000000..943e45b564 --- /dev/null +++ b/sdk/python/examples/controls/column/infinite_scrolling/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-infinite-scrolling" +version = "1.0.0" +description = "Infinite scrolling in a column by appending items on scroll." +requires-python = ">=3.10" +keywords = ["column", "layout", "infinite scrolling", "on_scroll", "lazy loading"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column infinite scrolling" +controls = ["Container", "Column", "Text"] +layout_pattern = "infinite-list" +complexity = "basic" +features = ["on_scroll handling", "dynamic item appending", "semaphore guard"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/programmatic_scroll.py b/sdk/python/examples/controls/column/programmatic_scroll/main.py similarity index 100% rename from sdk/python/examples/controls/column/programmatic_scroll.py rename to sdk/python/examples/controls/column/programmatic_scroll/main.py diff --git a/sdk/python/examples/controls/column/programmatic_scroll/pyproject.toml b/sdk/python/examples/controls/column/programmatic_scroll/pyproject.toml new file mode 100644 index 0000000000..7a75ab126e --- /dev/null +++ b/sdk/python/examples/controls/column/programmatic_scroll/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-programmatic-scroll" +version = "1.0.0" +description = "Programmatic scrolling of a column using offsets, keys, and deltas." +requires-python = ">=3.10" +keywords = ["column", "layout", "scroll_to", "scroll key", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column programmatic scroll" +controls = ["Container", "Column", "Row", "Button", "Text"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["async scroll_to", "offset and delta scrolling", "scroll key targeting"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/scroll.py b/sdk/python/examples/controls/column/scroll/main.py similarity index 100% rename from sdk/python/examples/controls/column/scroll.py rename to sdk/python/examples/controls/column/scroll/main.py diff --git a/sdk/python/examples/controls/column/scroll/pyproject.toml b/sdk/python/examples/controls/column/scroll/pyproject.toml new file mode 100644 index 0000000000..605d832631 --- /dev/null +++ b/sdk/python/examples/controls/column/scroll/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-scroll" +version = "1.0.0" +description = "Interactive column scrolling with dynamic controls and scroll mode switching." +requires-python = ">=3.10" +keywords = ["column", "layout", "scroll mode", "dynamic controls", "text field"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column scrolling" +controls = ["Row", "Column", "Container", "Button", "Text", "TextField"] +layout_pattern = "split-panel" +complexity = "basic" +features = ["dynamic add/remove", "scroll mode cycling", "interactive control panel"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/scroll_events.py b/sdk/python/examples/controls/column/scroll_events/main.py similarity index 100% rename from sdk/python/examples/controls/column/scroll_events.py rename to sdk/python/examples/controls/column/scroll_events/main.py diff --git a/sdk/python/examples/controls/column/scroll_events/pyproject.toml b/sdk/python/examples/controls/column/scroll_events/pyproject.toml new file mode 100644 index 0000000000..d956025ba2 --- /dev/null +++ b/sdk/python/examples/controls/column/scroll_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-scroll-events" +version = "1.0.0" +description = "Column on_scroll event handling example." +requires-python = ">=3.10" +keywords = ["column", "layout", "on_scroll", "events", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column scroll events" +controls = ["Container", "Column", "Text"] +layout_pattern = "event-monitor" +complexity = "basic" +features = ["on_scroll callback", "scroll event inspection"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/scroll_to_key.py b/sdk/python/examples/controls/column/scroll_to_key/main.py similarity index 100% rename from sdk/python/examples/controls/column/scroll_to_key.py rename to sdk/python/examples/controls/column/scroll_to_key/main.py diff --git a/sdk/python/examples/controls/column/scroll_to_key/pyproject.toml b/sdk/python/examples/controls/column/scroll_to_key/pyproject.toml new file mode 100644 index 0000000000..54749c767b --- /dev/null +++ b/sdk/python/examples/controls/column/scroll_to_key/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-scroll-to-key" +version = "1.0.0" +description = "Scroll a column to keyed sections using action buttons." +requires-python = ">=3.10" +keywords = ["column", "layout", "scroll_to", "scroll key", "sections"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column scroll to key" +controls = ["Container", "Column", "Row", "Button", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["scroll key navigation", "async button actions", "section anchors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/spacing.py b/sdk/python/examples/controls/column/spacing/main.py similarity index 100% rename from sdk/python/examples/controls/column/spacing.py rename to sdk/python/examples/controls/column/spacing/main.py diff --git a/sdk/python/examples/controls/column/spacing/pyproject.toml b/sdk/python/examples/controls/column/spacing/pyproject.toml new file mode 100644 index 0000000000..273a2a7d02 --- /dev/null +++ b/sdk/python/examples/controls/column/spacing/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-spacing" +version = "1.0.0" +description = "Adjust column spacing interactively with a slider." +requires-python = ">=3.10" +keywords = ["column", "layout", "spacing", "slider", "interactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column spacing" +controls = ["Column", "Container", "Text", "Slider"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["slider-driven spacing", "dynamic layout updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/column/wrap.py b/sdk/python/examples/controls/column/wrap/main.py similarity index 96% rename from sdk/python/examples/controls/column/wrap.py rename to sdk/python/examples/controls/column/wrap/main.py index f14daa0e4f..e403fa54fa 100644 --- a/sdk/python/examples/controls/column/wrap.py +++ b/sdk/python/examples/controls/column/wrap/main.py @@ -25,7 +25,8 @@ def handle_slider_change(e: ft.Event[ft.Slider]): ft.Column( controls=[ ft.Text( - "Change the column height to see how child items wrap onto multiple columns:" + "Change the column height to see how child items wrap onto " + "multiple columns:" ), ft.Slider( min=0, diff --git a/sdk/python/examples/controls/column/wrap/pyproject.toml b/sdk/python/examples/controls/column/wrap/pyproject.toml new file mode 100644 index 0000000000..45c393b6d2 --- /dev/null +++ b/sdk/python/examples/controls/column/wrap/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-wrap" +version = "1.0.0" +description = "Column wrapping behavior controlled by dynamic height." +requires-python = ">=3.10" +keywords = ["column", "layout", "wrap", "slider", "responsive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column wrapping" +controls = ["Column", "Container", "Text", "Slider"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["wrap behavior", "height-driven layout", "slider interaction"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/column.md b/sdk/python/packages/flet/docs/controls/column.md index bc0b3523a1..49f019951d 100644 --- a/sdk/python/packages/flet/docs/controls/column.md +++ b/sdk/python/packages/flet/docs/controls/column.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/column/media ### Column `spacing` ```python ---8<-- "{{ examples }}/spacing.py" +--8<-- "{{ examples }}/spacing/main.py" ``` {{ image(example_media + "/spacing.gif", alt="spacing", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/column/media ### Column wrapping ```python ---8<-- "{{ examples }}/wrap.py" +--8<-- "{{ examples }}/wrap/main.py" ``` {{ image(example_media + "/wrap.gif", alt="wrap", width="80%") }} @@ -32,7 +32,7 @@ example_media: ../examples/controls/column/media ### Column vertical alignments ```python ---8<-- "{{ examples }}/alignment.py" +--8<-- "{{ examples }}/alignment/main.py" ``` {{ image(example_media + "/alignment.png", alt="alignment", width="80%") }} @@ -41,7 +41,7 @@ example_media: ../examples/controls/column/media ### Column horizontal alignments ```python ---8<-- "{{ examples }}/horizontal_alignment.py" +--8<-- "{{ examples }}/horizontal_alignment/main.py" ``` {{ image(example_media + "/horizontal_alignment.png", alt="horizontal-alignment", width="80%") }} @@ -53,7 +53,7 @@ This example demonstrates adding of list items on-the-fly, as user scroll to the creating the illusion of infinite list: ```python ---8<-- "{{ examples }}/infinite_scrolling.py" +--8<-- "{{ examples }}/infinite_scrolling/main.py" ``` ### Scrolling programmatically @@ -61,7 +61,7 @@ creating the illusion of infinite list: This example shows how to use [`scroll_to()`][flet.Column.scroll_to] to programmatically scroll a column: ```python ---8<-- "{{ examples }}/programmatic_scroll.py" +--8<-- "{{ examples }}/programmatic_scroll/main.py" ``` {{ image(example_media + "/programmatic_scroll.png", alt="programmatic-scroll", width="80%") }} From ba5e5f8d1fab9069339cbfa65e9d353d25006ca7 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 9 Mar 2026 19:07:42 -0700 Subject: [PATCH 09/96] Convert column examples to @ft.control style Update SKILL.md to prefer using @ft.control for custom Flet controls and recommend moving constructor setup to declarative fields + init(). Convert two example projects (column/alignment and column/horizontal_alignment) to the new pattern: add @ft.control, replace __init__ with a declarative alignment field and init() method, use self.alignment in controls, and update example instantiations to use the alignment= keyword. Also renumbered the validation step in SKILL.md. These changes keep behavior identical while aligning examples with the preferred control style. --- .../create-flet-example-projects/SKILL.md | 9 ++++-- .../controls/column/alignment/main.py | 28 ++++++++++++------- .../column/horizontal_alignment/main.py | 16 ++++++----- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 335a0bc4ca..8340a8df47 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -66,12 +66,17 @@ Ensure each runnable example is a standalone project containing: - If `ft.context.disable_auto_update()` is not used, do not add explicit `page.update()` unless strictly necessary. - Wrap app content in `ft.SafeArea` so example renders correctly on mobile. -7. Update references. +7. Prefer `@ft.control` for custom controls in examples. +- If an example defines a custom control class inheriting from a Flet control (for example `class MyThing(ft.Column)`), prefer `@ft.control` style. +- Move constructor-style setup to declarative fields + `init()` where practical. +- Keep behavior unchanged and avoid refactors that alter public usage unless needed for compatibility. + +8. Update references. - Docs code includes: change from `.../example.py` to `.../example/main.py`. - Tests/imports: use direct module imports and avoid relying on package-level `__init__.py` re-exports. - For already-converted examples, only update references that are stale; avoid unnecessary churn. -8. Validate. +9. Validate. - Run `python -m compileall` on changed `main.py` files. - Search for stale paths to old flat files. - Check `git status` to confirm expected moves and edits. diff --git a/sdk/python/examples/controls/column/alignment/main.py b/sdk/python/examples/controls/column/alignment/main.py index d0238ba9be..f22f88f1c9 100644 --- a/sdk/python/examples/controls/column/alignment/main.py +++ b/sdk/python/examples/controls/column/alignment/main.py @@ -1,13 +1,15 @@ import flet as ft +@ft.control class ColumnFromVerticalAlignment(ft.Column): - def __init__(self, alignment: ft.MainAxisAlignment): - super().__init__() + alignment: ft.MainAxisAlignment = ft.MainAxisAlignment.START + + def init(self): self.controls = [ - ft.Text(str(alignment), size=10), + ft.Text(str(self.alignment), size=10), ft.Container( - content=ft.Column(self.generate_items(3), alignment=alignment), + content=ft.Column(self.generate_items(3), alignment=self.alignment), bgcolor=ft.Colors.AMBER_100, height=400, ), @@ -35,12 +37,18 @@ def main(page: ft.Page): alignment=ft.MainAxisAlignment.START, scroll=ft.ScrollMode.AUTO, controls=[ - ColumnFromVerticalAlignment(ft.MainAxisAlignment.START), - ColumnFromVerticalAlignment(ft.MainAxisAlignment.CENTER), - ColumnFromVerticalAlignment(ft.MainAxisAlignment.END), - ColumnFromVerticalAlignment(ft.MainAxisAlignment.SPACE_BETWEEN), - ColumnFromVerticalAlignment(ft.MainAxisAlignment.SPACE_AROUND), - ColumnFromVerticalAlignment(ft.MainAxisAlignment.SPACE_EVENLY), + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.START), + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.CENTER), + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.END), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN + ), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_AROUND + ), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_EVENLY + ), ], ) ) diff --git a/sdk/python/examples/controls/column/horizontal_alignment/main.py b/sdk/python/examples/controls/column/horizontal_alignment/main.py index 97145c483f..0eb838c110 100644 --- a/sdk/python/examples/controls/column/horizontal_alignment/main.py +++ b/sdk/python/examples/controls/column/horizontal_alignment/main.py @@ -1,18 +1,20 @@ import flet as ft +@ft.control class ColumnFromHorizontalAlignment(ft.Column): - def __init__(self, alignment: ft.CrossAxisAlignment): - super().__init__() + alignment: ft.CrossAxisAlignment = ft.CrossAxisAlignment.START + + def init(self): self.controls = [ - ft.Text(str(alignment), size=16), + ft.Text(str(self.alignment), size=16), ft.Container( bgcolor=ft.Colors.AMBER_100, width=100, content=ft.Column( controls=self.generate_items(3), alignment=ft.MainAxisAlignment.START, - horizontal_alignment=alignment, + horizontal_alignment=self.alignment, ), ), ] @@ -38,9 +40,9 @@ def main(page: ft.Page): spacing=30, alignment=ft.MainAxisAlignment.START, controls=[ - ColumnFromHorizontalAlignment(ft.CrossAxisAlignment.START), - ColumnFromHorizontalAlignment(ft.CrossAxisAlignment.CENTER), - ColumnFromHorizontalAlignment(ft.CrossAxisAlignment.END), + ColumnFromHorizontalAlignment(alignment=ft.CrossAxisAlignment.START), + ColumnFromHorizontalAlignment(alignment=ft.CrossAxisAlignment.CENTER), + ColumnFromHorizontalAlignment(alignment=ft.CrossAxisAlignment.END), ], ) ) From 647352798207591122426d7d17388f79e3bdc3fa Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 11:38:19 -0700 Subject: [PATCH 10/96] Wrap column examples in SafeArea Wrap multiple Python Column example pages in ft.SafeArea so their UI respects device safe areas. Refactor layout nesting by moving Row/Column/Container controls into the SafeArea content (improves padding and layout consistency). Updated examples: alignment, custom_scrollbar, horizontal_alignment, infinite_scrolling, programmatic_scroll, scroll, scroll_events, scroll_to_key, spacing, and wrap. --- client/pubspec.lock | 8 +- .../controls/column/alignment/main.py | 38 ++--- .../controls/column/custom_scrollbar/main.py | 38 ++--- .../column/horizontal_alignment/main.py | 22 ++- .../column/infinite_scrolling/main.py | 2 +- .../column/programmatic_scroll/main.py | 34 +++-- .../examples/controls/column/scroll/main.py | 58 +++---- .../controls/column/scroll_events/main.py | 28 ++-- .../controls/column/scroll_to_key/main.py | 142 ++++++++++-------- .../examples/controls/column/spacing/main.py | 34 +++-- .../examples/controls/column/wrap/main.py | 62 ++++---- 11 files changed, 256 insertions(+), 210 deletions(-) diff --git a/client/pubspec.lock b/client/pubspec.lock index b73b620915..16d10e59c9 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -911,10 +911,10 @@ packages: dependency: transitive description: name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.18" + version: "0.12.19" material_color_utilities: dependency: transitive description: @@ -1628,10 +1628,10 @@ packages: dependency: transitive description: name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.9" + version: "0.7.10" torch_light: dependency: transitive description: diff --git a/sdk/python/examples/controls/column/alignment/main.py b/sdk/python/examples/controls/column/alignment/main.py index f22f88f1c9..d8126b2b4f 100644 --- a/sdk/python/examples/controls/column/alignment/main.py +++ b/sdk/python/examples/controls/column/alignment/main.py @@ -32,24 +32,26 @@ def generate_items(count: int): def main(page: ft.Page): page.add( - ft.Row( - spacing=30, - alignment=ft.MainAxisAlignment.START, - scroll=ft.ScrollMode.AUTO, - controls=[ - ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.START), - ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.CENTER), - ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.END), - ColumnFromVerticalAlignment( - alignment=ft.MainAxisAlignment.SPACE_BETWEEN - ), - ColumnFromVerticalAlignment( - alignment=ft.MainAxisAlignment.SPACE_AROUND - ), - ColumnFromVerticalAlignment( - alignment=ft.MainAxisAlignment.SPACE_EVENLY - ), - ], + ft.SafeArea( + content=ft.Row( + spacing=30, + alignment=ft.MainAxisAlignment.START, + scroll=ft.ScrollMode.AUTO, + controls=[ + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.START), + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.CENTER), + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.END), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN + ), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_AROUND + ), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_EVENLY + ), + ], + ) ) ) diff --git a/sdk/python/examples/controls/column/custom_scrollbar/main.py b/sdk/python/examples/controls/column/custom_scrollbar/main.py index 133cb072fb..1cd4a2a1b6 100644 --- a/sdk/python/examples/controls/column/custom_scrollbar/main.py +++ b/sdk/python/examples/controls/column/custom_scrollbar/main.py @@ -33,24 +33,26 @@ def main(page: ft.Page): ] page.add( - ft.Row( - [ - ft.Container( - content=ft.Column( - controls=fake_messages, - spacing=10, - scroll=ft.ScrollMode.ALWAYS, - expand=True, - ), - width=320, - height=420, - bgcolor=ft.Colors.with_opacity(0.15, ft.Colors.AMBER_200), - padding=15, - border_radius=12, - ) - ], - alignment=ft.MainAxisAlignment.CENTER, - expand=True, + ft.SafeArea( + content=ft.Row( + [ + ft.Container( + content=ft.Column( + controls=fake_messages, + spacing=10, + scroll=ft.ScrollMode.ALWAYS, + expand=True, + ), + width=320, + height=420, + bgcolor=ft.Colors.with_opacity(0.15, ft.Colors.AMBER_200), + padding=15, + border_radius=12, + ) + ], + alignment=ft.MainAxisAlignment.CENTER, + expand=True, + ) ) ) diff --git a/sdk/python/examples/controls/column/horizontal_alignment/main.py b/sdk/python/examples/controls/column/horizontal_alignment/main.py index 0eb838c110..673ce59112 100644 --- a/sdk/python/examples/controls/column/horizontal_alignment/main.py +++ b/sdk/python/examples/controls/column/horizontal_alignment/main.py @@ -36,14 +36,20 @@ def generate_items(count: int): def main(page: ft.Page): page.add( - ft.Row( - spacing=30, - alignment=ft.MainAxisAlignment.START, - controls=[ - ColumnFromHorizontalAlignment(alignment=ft.CrossAxisAlignment.START), - ColumnFromHorizontalAlignment(alignment=ft.CrossAxisAlignment.CENTER), - ColumnFromHorizontalAlignment(alignment=ft.CrossAxisAlignment.END), - ], + ft.SafeArea( + content=ft.Row( + spacing=30, + alignment=ft.MainAxisAlignment.START, + controls=[ + ColumnFromHorizontalAlignment( + alignment=ft.CrossAxisAlignment.START + ), + ColumnFromHorizontalAlignment( + alignment=ft.CrossAxisAlignment.CENTER + ), + ColumnFromHorizontalAlignment(alignment=ft.CrossAxisAlignment.END), + ], + ) ) ) diff --git a/sdk/python/examples/controls/column/infinite_scrolling/main.py b/sdk/python/examples/controls/column/infinite_scrolling/main.py index f41263c3f6..da92616025 100644 --- a/sdk/python/examples/controls/column/infinite_scrolling/main.py +++ b/sdk/python/examples/controls/column/infinite_scrolling/main.py @@ -34,7 +34,7 @@ def on_scroll(e: ft.OnScrollEvent): cl.controls.append(ft.Text(f"Text line {s.i}", key=str(s.i))) s.i += 1 - page.add(ft.Container(cl, border=ft.Border.all(1))) + page.add(ft.SafeArea(content=ft.Container(cl, border=ft.Border.all(1)))) ft.run(main) diff --git a/sdk/python/examples/controls/column/programmatic_scroll/main.py b/sdk/python/examples/controls/column/programmatic_scroll/main.py index 7b5c15e5a0..2f3ed31adc 100644 --- a/sdk/python/examples/controls/column/programmatic_scroll/main.py +++ b/sdk/python/examples/controls/column/programmatic_scroll/main.py @@ -33,20 +33,26 @@ async def scroll_to_minus_delta(e): await column.scroll_to(delta=-100, duration=200) page.add( - ft.Container(content=column, border=ft.Border.all(1)), - ft.Button("Scroll to offset 500", on_click=scroll_to_offset), - ft.Row( - controls=[ - ft.Button("Scroll -100", on_click=scroll_to_minus_delta), - ft.Button("Scroll +100", on_click=scroll_to_delta), - ] - ), - ft.Button("Scroll to key '20'", on_click=scroll_to_key), - ft.Row( - controls=[ - ft.Button("Scroll to start", on_click=scroll_to_start), - ft.Button("Scroll to end", on_click=scroll_to_end), - ] + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container(content=column, border=ft.Border.all(1)), + ft.Button("Scroll to offset 500", on_click=scroll_to_offset), + ft.Row( + controls=[ + ft.Button("Scroll -100", on_click=scroll_to_minus_delta), + ft.Button("Scroll +100", on_click=scroll_to_delta), + ] + ), + ft.Button("Scroll to key '20'", on_click=scroll_to_key), + ft.Row( + controls=[ + ft.Button("Scroll to start", on_click=scroll_to_start), + ft.Button("Scroll to end", on_click=scroll_to_end), + ] + ), + ] + ) ), ) diff --git a/sdk/python/examples/controls/column/scroll/main.py b/sdk/python/examples/controls/column/scroll/main.py index f1f66404d4..ceddb3a424 100644 --- a/sdk/python/examples/controls/column/scroll/main.py +++ b/sdk/python/examples/controls/column/scroll/main.py @@ -53,35 +53,37 @@ def change_scroll(_): scroll_mode_text = ft.Text(str(left_column.scroll)) page.add( - ft.Row( - expand=True, - controls=[ - ft.Container( - content=left_column, - expand=True, - margin=10, - padding=10, - bgcolor=ft.Colors.AMBER_100, - border_radius=10, - alignment=ft.Alignment.TOP_CENTER, - ), - ft.Container( - margin=10, - padding=10, - bgcolor=ft.Colors.CYAN_500, - border_radius=10, - expand=True, - alignment=ft.Alignment.TOP_LEFT, - content=ft.Column( - controls=[ - add_text_box_button, - remove_text_box_button, - scroll_change_button, - scroll_mode_text, - ], + ft.SafeArea( + content=ft.Row( + expand=True, + controls=[ + ft.Container( + content=left_column, + expand=True, + margin=10, + padding=10, + bgcolor=ft.Colors.AMBER_100, + border_radius=10, + alignment=ft.Alignment.TOP_CENTER, ), - ), - ], + ft.Container( + margin=10, + padding=10, + bgcolor=ft.Colors.CYAN_500, + border_radius=10, + expand=True, + alignment=ft.Alignment.TOP_LEFT, + content=ft.Column( + controls=[ + add_text_box_button, + remove_text_box_button, + scroll_change_button, + scroll_mode_text, + ], + ), + ), + ], + ) ) ) diff --git a/sdk/python/examples/controls/column/scroll_events/main.py b/sdk/python/examples/controls/column/scroll_events/main.py index e4d15bbeff..11a8549e3e 100644 --- a/sdk/python/examples/controls/column/scroll_events/main.py +++ b/sdk/python/examples/controls/column/scroll_events/main.py @@ -6,19 +6,21 @@ def handle_column_scroll(e: ft.OnScrollEvent): print(e) page.add( - ft.Container( - border=ft.Border.all(1), - content=ft.Column( - spacing=10, - height=200, - width=200, - scroll=ft.ScrollMode.ALWAYS, - on_scroll=handle_column_scroll, - controls=[ - ft.Text(f"Text line {i}", key=ft.ScrollKey(str(i))) - for i in range(0, 50) - ], - ), + ft.SafeArea( + content=ft.Container( + border=ft.Border.all(1), + content=ft.Column( + spacing=10, + height=200, + width=200, + scroll=ft.ScrollMode.ALWAYS, + on_scroll=handle_column_scroll, + controls=[ + ft.Text(f"Text line {i}", key=ft.ScrollKey(str(i))) + for i in range(0, 50) + ], + ), + ) ), ) diff --git a/sdk/python/examples/controls/column/scroll_to_key/main.py b/sdk/python/examples/controls/column/scroll_to_key/main.py index c4fa4ef9c9..8b07b3afed 100644 --- a/sdk/python/examples/controls/column/scroll_to_key/main.py +++ b/sdk/python/examples/controls/column/scroll_to_key/main.py @@ -15,71 +15,85 @@ async def scroll_d(): await column1.scroll_to(scroll_key=ft.ScrollKey("D"), duration=1000) page.add( - ft.Container( - border=ft.Border.all(1), - content=( - column1 := ft.Column( - spacing=10, - height=200, - width=300, - scroll=ft.ScrollMode.ALWAYS, - controls=[ - ft.Container( - content=ft.Text("Section A", color=ft.Colors.BLACK), - alignment=ft.Alignment.TOP_LEFT, - bgcolor=ft.Colors.YELLOW_200, - height=100, - key=ft.ScrollKey("A"), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + border=ft.Border.all(1), + content=( + column1 := ft.Column( + spacing=10, + height=200, + width=300, + scroll=ft.ScrollMode.ALWAYS, + controls=[ + ft.Container( + content=ft.Text( + "Section A", color=ft.Colors.BLACK + ), + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.YELLOW_200, + height=100, + key=ft.ScrollKey("A"), + ), + ft.Container( + content=ft.Text( + "Section B", color=ft.Colors.BLACK + ), + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.GREEN_200, + height=100, + key=ft.ScrollKey("B"), + ), + ft.Container( + content=ft.Text( + "Section C", color=ft.Colors.BLACK + ), + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.BLUE_200, + height=100, + key=ft.ScrollKey("C"), + ), + ft.Container( + content=ft.Text( + "Section D", color=ft.Colors.BLACK + ), + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.PINK_200, + height=100, + key=ft.ScrollKey("D"), + ), + ], + ) ), - ft.Container( - content=ft.Text("Section B", color=ft.Colors.BLACK), - alignment=ft.Alignment.TOP_LEFT, - bgcolor=ft.Colors.GREEN_200, - height=100, - key=ft.ScrollKey("B"), - ), - ft.Container( - content=ft.Text("Section C", color=ft.Colors.BLACK), - alignment=ft.Alignment.TOP_LEFT, - bgcolor=ft.Colors.BLUE_200, - height=100, - key=ft.ScrollKey("C"), - ), - ft.Container( - content=ft.Text("Section D", color=ft.Colors.BLACK), - alignment=ft.Alignment.TOP_LEFT, - bgcolor=ft.Colors.PINK_200, - height=100, - key=ft.ScrollKey("D"), - ), - ], - ) - ), - ), - ft.Column( - controls=[ - ft.Text("Scroll to:"), - ft.Row( - controls=[ - ft.Button( - content="Section A", - on_click=scroll_a, - ), - ft.Button( - content="Section B", - on_click=scroll_b, - ), - ft.Button( - content="Section C", - on_click=scroll_c, - ), - ft.Button( - content="Section D", - on_click=scroll_d, - ), - ] - ), - ] + ), + ft.Column( + controls=[ + ft.Text("Scroll to:"), + ft.Row( + controls=[ + ft.Button( + content="Section A", + on_click=scroll_a, + ), + ft.Button( + content="Section B", + on_click=scroll_b, + ), + ft.Button( + content="Section C", + on_click=scroll_c, + ), + ft.Button( + content="Section D", + on_click=scroll_d, + ), + ] + ), + ] + ), + ] + ) ), ) diff --git a/sdk/python/examples/controls/column/spacing/main.py b/sdk/python/examples/controls/column/spacing/main.py index 6baac249f7..c1a1deb03f 100644 --- a/sdk/python/examples/controls/column/spacing/main.py +++ b/sdk/python/examples/controls/column/spacing/main.py @@ -22,21 +22,27 @@ def handle_slider_change(e: ft.Event[ft.Slider]): column.update() page.add( - ft.Column( - controls=[ - ft.Text("Spacing between items"), - ft.Slider( - min=0, - max=100, - divisions=10, - value=0, - label="{value}", - width=500, - on_change=handle_slider_change, - ), - ] + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + ft.Text("Spacing between items"), + ft.Slider( + min=0, + max=100, + divisions=10, + value=0, + label="{value}", + width=500, + on_change=handle_slider_change, + ), + ] + ), + column := ft.Column(spacing=0, controls=generate_items(5)), + ] + ) ), - column := ft.Column(spacing=0, controls=generate_items(5)), ) diff --git a/sdk/python/examples/controls/column/wrap/main.py b/sdk/python/examples/controls/column/wrap/main.py index e403fa54fa..e948318435 100644 --- a/sdk/python/examples/controls/column/wrap/main.py +++ b/sdk/python/examples/controls/column/wrap/main.py @@ -22,34 +22,40 @@ def handle_slider_change(e: ft.Event[ft.Slider]): col.update() page.add( - ft.Column( - controls=[ - ft.Text( - "Change the column height to see how child items wrap onto " - "multiple columns:" - ), - ft.Slider( - min=0, - max=HEIGHT, - divisions=20, - value=HEIGHT, - label="{value}", - width=500, - on_change=handle_slider_change, - ), - ] - ), - ft.Container( - bgcolor=ft.Colors.TRANSPARENT, - content=( - col := ft.Column( - wrap=True, - spacing=10, - run_spacing=10, - controls=items(10), - height=HEIGHT, - ) - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + ft.Text( + "Change the column height to see how child items " + "wrap onto multiple columns:" + ), + ft.Slider( + min=0, + max=HEIGHT, + divisions=20, + value=HEIGHT, + label="{value}", + width=500, + on_change=handle_slider_change, + ), + ] + ), + ft.Container( + bgcolor=ft.Colors.TRANSPARENT, + content=( + col := ft.Column( + wrap=True, + spacing=10, + run_spacing=10, + controls=items(10), + height=HEIGHT, + ) + ), + ), + ] + ) ), ) From b75d327d414b845c5b97368c536e9979224694e8 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 11:39:55 -0700 Subject: [PATCH 11/96] Enforce ft.SafeArea for all examples Clarify mobile-safety guidance: apply the SafeArea requirement to all examples in the touched folder (new, migrated, and already converted), not just files changed by moves. Add validation to confirm every /main.py in scope wraps rendered content in a top-level ft.SafeArea so examples render correctly on mobile. --- .codex/skills/create-flet-example-projects/SKILL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 8340a8df47..db6fec342c 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -65,6 +65,8 @@ Ensure each runnable example is a standalone project containing: 6. Make examples mobile-safe. - If `ft.context.disable_auto_update()` is not used, do not add explicit `page.update()` unless strictly necessary. - Wrap app content in `ft.SafeArea` so example renders correctly on mobile. +- Apply this to all examples in the touched folder (new, migrated, and already converted), not only files changed by moves. +- During validation, confirm every `/main.py` in scope includes a top-level `ft.SafeArea` around rendered content. 7. Prefer `@ft.control` for custom controls in examples. - If an example defines a custom control class inheriting from a Flet control (for example `class MyThing(ft.Column)`), prefer `@ft.control` style. From fe8cf6a208863b1ae240c3e66f4f3a44cd4b654f Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 11:56:09 -0700 Subject: [PATCH 12/96] Add __main__ guard and SafeArea expand Wrap ft.run(main) calls with if __name__ == "__main__": in column examples to prevent running examples on import (applies to multiple files under sdk/python/examples/controls/column). Also set SafeArea expand=True in the scroll example to ensure it fills available space for proper layout. --- sdk/python/examples/controls/column/alignment/main.py | 3 ++- .../examples/controls/column/custom_scrollbar/main.py | 3 ++- .../examples/controls/column/horizontal_alignment/main.py | 3 ++- .../examples/controls/column/infinite_scrolling/main.py | 3 ++- .../examples/controls/column/programmatic_scroll/main.py | 3 ++- sdk/python/examples/controls/column/scroll/main.py | 6 ++++-- sdk/python/examples/controls/column/scroll_events/main.py | 3 ++- sdk/python/examples/controls/column/scroll_to_key/main.py | 3 ++- sdk/python/examples/controls/column/spacing/main.py | 3 ++- sdk/python/examples/controls/column/wrap/main.py | 3 ++- 10 files changed, 22 insertions(+), 11 deletions(-) diff --git a/sdk/python/examples/controls/column/alignment/main.py b/sdk/python/examples/controls/column/alignment/main.py index d8126b2b4f..eb9ae5dd90 100644 --- a/sdk/python/examples/controls/column/alignment/main.py +++ b/sdk/python/examples/controls/column/alignment/main.py @@ -56,4 +56,5 @@ def main(page: ft.Page): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/custom_scrollbar/main.py b/sdk/python/examples/controls/column/custom_scrollbar/main.py index 1cd4a2a1b6..f0376fdfba 100644 --- a/sdk/python/examples/controls/column/custom_scrollbar/main.py +++ b/sdk/python/examples/controls/column/custom_scrollbar/main.py @@ -57,4 +57,5 @@ def main(page: ft.Page): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/horizontal_alignment/main.py b/sdk/python/examples/controls/column/horizontal_alignment/main.py index 673ce59112..dcd9b92f36 100644 --- a/sdk/python/examples/controls/column/horizontal_alignment/main.py +++ b/sdk/python/examples/controls/column/horizontal_alignment/main.py @@ -54,4 +54,5 @@ def main(page: ft.Page): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/infinite_scrolling/main.py b/sdk/python/examples/controls/column/infinite_scrolling/main.py index da92616025..22f3212983 100644 --- a/sdk/python/examples/controls/column/infinite_scrolling/main.py +++ b/sdk/python/examples/controls/column/infinite_scrolling/main.py @@ -37,4 +37,5 @@ def on_scroll(e: ft.OnScrollEvent): page.add(ft.SafeArea(content=ft.Container(cl, border=ft.Border.all(1)))) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/programmatic_scroll/main.py b/sdk/python/examples/controls/column/programmatic_scroll/main.py index 2f3ed31adc..1e5f5026fd 100644 --- a/sdk/python/examples/controls/column/programmatic_scroll/main.py +++ b/sdk/python/examples/controls/column/programmatic_scroll/main.py @@ -57,4 +57,5 @@ async def scroll_to_minus_delta(e): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/scroll/main.py b/sdk/python/examples/controls/column/scroll/main.py index ceddb3a424..e7a9bb7883 100644 --- a/sdk/python/examples/controls/column/scroll/main.py +++ b/sdk/python/examples/controls/column/scroll/main.py @@ -54,6 +54,7 @@ def change_scroll(_): page.add( ft.SafeArea( + expand=True, content=ft.Row( expand=True, controls=[ @@ -83,9 +84,10 @@ def change_scroll(_): ), ), ], - ) + ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/scroll_events/main.py b/sdk/python/examples/controls/column/scroll_events/main.py index 11a8549e3e..741ff6f31e 100644 --- a/sdk/python/examples/controls/column/scroll_events/main.py +++ b/sdk/python/examples/controls/column/scroll_events/main.py @@ -25,4 +25,5 @@ def handle_column_scroll(e: ft.OnScrollEvent): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/scroll_to_key/main.py b/sdk/python/examples/controls/column/scroll_to_key/main.py index 8b07b3afed..5592e09f2f 100644 --- a/sdk/python/examples/controls/column/scroll_to_key/main.py +++ b/sdk/python/examples/controls/column/scroll_to_key/main.py @@ -98,4 +98,5 @@ async def scroll_d(): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/spacing/main.py b/sdk/python/examples/controls/column/spacing/main.py index c1a1deb03f..aa3bc60204 100644 --- a/sdk/python/examples/controls/column/spacing/main.py +++ b/sdk/python/examples/controls/column/spacing/main.py @@ -46,4 +46,5 @@ def handle_slider_change(e: ft.Event[ft.Slider]): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/column/wrap/main.py b/sdk/python/examples/controls/column/wrap/main.py index e948318435..b7e581963a 100644 --- a/sdk/python/examples/controls/column/wrap/main.py +++ b/sdk/python/examples/controls/column/wrap/main.py @@ -60,4 +60,5 @@ def handle_slider_change(e: ft.Event[ft.Slider]): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) From 4c2abf577452432a8607d77de13084a2526a0506 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 11:57:07 -0700 Subject: [PATCH 13/96] Require runnable main.py entrypoints in examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new checklist item requiring every example main.py to end with an if __name__ == "__main__": ft.run(main) entrypoint and apply it to new, migrated, and already-converted examples. Adjust numbering for subsequent items (Update references → 9, Validate → 10) and expand validation to compile changed main.py files and confirm top-level ft.SafeArea wrapping plus the ft.run(main) entrypoint. Keep existing guidance on updating docs/tests references and avoiding unnecessary churn. --- .codex/skills/create-flet-example-projects/SKILL.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index db6fec342c..5d46e42bc0 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -73,16 +73,23 @@ Ensure each runnable example is a standalone project containing: - Move constructor-style setup to declarative fields + `init()` where practical. - Keep behavior unchanged and avoid refactors that alter public usage unless needed for compatibility. -8. Update references. +8. Ensure runnable entrypoint. +- Every example `main.py` should end with: + - `if __name__ == "__main__":` + - ` ft.run(main)` +- Apply this to all examples in the touched folder (new, migrated, and already converted). + +9. Update references. - Docs code includes: change from `.../example.py` to `.../example/main.py`. - Tests/imports: use direct module imports and avoid relying on package-level `__init__.py` re-exports. - For already-converted examples, only update references that are stale; avoid unnecessary churn. -9. Validate. +10. Validate. - Run `python -m compileall` on changed `main.py` files. - Search for stale paths to old flat files. - Check `git status` to confirm expected moves and edits. - When integration tests exist for the touched control, run the targeted test file(s). +- Confirm all in-scope `main.py` files include both top-level `ft.SafeArea` wrapping and the `if __name__ == "__main__": ft.run(main)` entrypoint. ## Command checklist From 498b87827f7c732532d664039030b0bdbd8e414f Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 12:04:00 -0700 Subject: [PATCH 14/96] Reorganize alert_dialog example and add metadata Rename and reorganize the AlertDialog example: move modal_and_non_modal.py to modal_and_non_modal/main.py and remove the package __init__.py. Wrap example buttons in a SafeArea/Column. Add a pyproject.toml for the example with gallery and metadata (title, controls, layout_pattern, etc.). Update docs to reference the new example path and adjust the integration test import accordingly. Also replace the golden GIF asset (updated visual). --- .../controls/alert_dialog/__init__.py | 0 .../main.py} | 22 +++++++++------ .../modal_and_non_modal/pyproject.toml | 26 ++++++++++++++++++ .../flet/docs/controls/alertdialog.md | 2 +- .../macos/alert_dialog/alert_dialog_flow.gif | Bin 30975 -> 43512 bytes .../examples/material/test_alert_dialog.py | 2 +- 6 files changed, 42 insertions(+), 10 deletions(-) delete mode 100644 sdk/python/examples/controls/alert_dialog/__init__.py rename sdk/python/examples/controls/alert_dialog/{modal_and_non_modal.py => modal_and_non_modal/main.py} (64%) create mode 100644 sdk/python/examples/controls/alert_dialog/modal_and_non_modal/pyproject.toml diff --git a/sdk/python/examples/controls/alert_dialog/__init__.py b/sdk/python/examples/controls/alert_dialog/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/alert_dialog/modal_and_non_modal.py b/sdk/python/examples/controls/alert_dialog/modal_and_non_modal/main.py similarity index 64% rename from sdk/python/examples/controls/alert_dialog/modal_and_non_modal.py rename to sdk/python/examples/controls/alert_dialog/modal_and_non_modal/main.py index baf7df861a..138ade206d 100644 --- a/sdk/python/examples/controls/alert_dialog/modal_and_non_modal.py +++ b/sdk/python/examples/controls/alert_dialog/modal_and_non_modal/main.py @@ -25,14 +25,20 @@ def main(page: ft.Page): ) page.add( - ft.Button( - content="Open dialog", - on_click=lambda e: page.show_dialog(dialog), - ), - ft.Button( - content="Open modal dialog", - on_click=lambda e: page.show_dialog(modal_dialog), - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Open dialog", + on_click=lambda e: page.show_dialog(dialog), + ), + ft.Button( + content="Open modal dialog", + on_click=lambda e: page.show_dialog(modal_dialog), + ), + ] + ) + ) ) diff --git a/sdk/python/examples/controls/alert_dialog/modal_and_non_modal/pyproject.toml b/sdk/python/examples/controls/alert_dialog/modal_and_non_modal/pyproject.toml new file mode 100644 index 0000000000..cc9dd91aec --- /dev/null +++ b/sdk/python/examples/controls/alert_dialog/modal_and_non_modal/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "alert-dialog-modal-and-non-modal" +version = "1.0.0" +description = "AlertDialog example showing modal and non-modal dialog behavior." +requires-python = ">=3.10" +keywords = ["alertdialog", "dialog", "modal", "material", "actions"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/AlertDialog"] + +[tool.flet.metadata] +title = "Modal and non-modal dialogs" +controls = ["SafeArea", "Column", "Button", "AlertDialog", "Text", "TextButton"] +layout_pattern = "dialog-flow" +complexity = "basic" +features = ["modal dialog", "non-modal dialog", "dialog actions", "dismiss events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/alertdialog.md b/sdk/python/packages/flet/docs/controls/alertdialog.md index f911ec31cb..b77db22267 100644 --- a/sdk/python/packages/flet/docs/controls/alertdialog.md +++ b/sdk/python/packages/flet/docs/controls/alertdialog.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/alert_dialog ### Modal and non-modal dialogs ```python ---8<-- "{{ examples }}/modal_and_non_modal.py" +--8<-- "{{ examples }}/modal_and_non_modal/main.py" ``` {{ image(example_images + "/alert_dialog_flow.gif", alt="Modal and non-modal dialogs", caption="Modal and non-modal dialogs",width="50%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/alert_dialog/alert_dialog_flow.gif b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/alert_dialog/alert_dialog_flow.gif index 45692cbdff11c2610da17b744cf910a197452045..8ae322426961b1e490b80143716c9f0a9845114d 100644 GIT binary patch literal 43512 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 ZM}IU(hqOqKG)b4VNuM-I2XsIH06P&SCa3@a literal 30975 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 Date: Tue, 10 Mar 2026 12:18:03 -0700 Subject: [PATCH 15/96] Organize animated_switcher examples and docs Restructure animated_switcher examples: move example scripts into example-specific main.py entrypoints, add pyproject.toml metadata for each example, and wrap example UIs in SafeArea/Column. Refactor the buffered image switcher: mark as @ft.control, use typed image fields and a default_factory-backed image_queue, initialize content in init, improve async preloading and base64 handling, and update how the control is instantiated. Add guarded ft.run(main) entrypoints instead of unconditional runs. Update documentation references to point to the new example/main.py paths and remove the old top-level example files. --- .../animated_switcher/image_switch.py | 32 --------------- .../animated_switcher/image_switch/main.py | 39 +++++++++++++++++++ .../image_switch/pyproject.toml | 26 +++++++++++++ .../main.py} | 39 ++++++++++++------- .../image_switch_buffered/pyproject.toml | 26 +++++++++++++ .../{scale_effect.py => scale_effect/main.py} | 17 +++++--- .../scale_effect/pyproject.toml | 26 +++++++++++++ .../flet/docs/controls/animatedswitcher.md | 6 +-- 8 files changed, 158 insertions(+), 53 deletions(-) delete mode 100644 sdk/python/examples/controls/animated_switcher/image_switch.py create mode 100644 sdk/python/examples/controls/animated_switcher/image_switch/main.py create mode 100644 sdk/python/examples/controls/animated_switcher/image_switch/pyproject.toml rename sdk/python/examples/controls/animated_switcher/{image_switch_buffered.py => image_switch_buffered/main.py} (58%) create mode 100644 sdk/python/examples/controls/animated_switcher/image_switch_buffered/pyproject.toml rename sdk/python/examples/controls/animated_switcher/{scale_effect.py => scale_effect/main.py} (77%) create mode 100644 sdk/python/examples/controls/animated_switcher/scale_effect/pyproject.toml diff --git a/sdk/python/examples/controls/animated_switcher/image_switch.py b/sdk/python/examples/controls/animated_switcher/image_switch.py deleted file mode 100644 index 57dd38a392..0000000000 --- a/sdk/python/examples/controls/animated_switcher/image_switch.py +++ /dev/null @@ -1,32 +0,0 @@ -import time - -import flet as ft - - -def main(page: ft.Page): - def animate(e: ft.Event[ft.Button]): - switcher.content = ft.Image( - src=f"https://picsum.photos/200/300?{time.time()}", - width=200, - height=300, - ) - page.update() - - page.add( - switcher := ft.AnimatedSwitcher( - content=ft.Image( - src="https://picsum.photos/200/300", - width=200, - height=300, - ), - transition=ft.AnimatedSwitcherTransition.SCALE, - duration=500, - reverse_duration=100, - switch_in_curve=ft.AnimationCurve.BOUNCE_OUT, - switch_out_curve=ft.AnimationCurve.BOUNCE_IN, - ), - ft.Button("Animate!", on_click=animate), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/animated_switcher/image_switch/main.py b/sdk/python/examples/controls/animated_switcher/image_switch/main.py new file mode 100644 index 0000000000..1cdafbdf0d --- /dev/null +++ b/sdk/python/examples/controls/animated_switcher/image_switch/main.py @@ -0,0 +1,39 @@ +import time + +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + switcher.content = ft.Image( + src=f"https://picsum.photos/200/300?{time.time()}", + width=200, + height=300, + ) + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + switcher := ft.AnimatedSwitcher( + content=ft.Image( + src="https://picsum.photos/200/300", + width=200, + height=300, + ), + transition=ft.AnimatedSwitcherTransition.SCALE, + duration=500, + reverse_duration=100, + switch_in_curve=ft.AnimationCurve.BOUNCE_OUT, + switch_out_curve=ft.AnimationCurve.BOUNCE_IN, + ), + ft.Button("Animate!", on_click=animate), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/animated_switcher/image_switch/pyproject.toml b/sdk/python/examples/controls/animated_switcher/image_switch/pyproject.toml new file mode 100644 index 0000000000..1c92219c45 --- /dev/null +++ b/sdk/python/examples/controls/animated_switcher/image_switch/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "animated-switcher-image-switch" +version = "1.0.0" +description = "Animated image switching with scale transition." +requires-python = ">=3.10" +keywords = ["animated switcher", "animation", "image", "transition", "scale"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Animations/AnimatedSwitcher"] + +[tool.flet.metadata] +title = "Animate image switch" +controls = ["SafeArea", "Column", "AnimatedSwitcher", "Image", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dynamic image source", "scale transition", "button-triggered animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/animated_switcher/image_switch_buffered.py b/sdk/python/examples/controls/animated_switcher/image_switch_buffered/main.py similarity index 58% rename from sdk/python/examples/controls/animated_switcher/image_switch_buffered.py rename to sdk/python/examples/controls/animated_switcher/image_switch_buffered/main.py index 203b732c5d..d3c176e941 100644 --- a/sdk/python/examples/controls/animated_switcher/image_switch_buffered.py +++ b/sdk/python/examples/controls/animated_switcher/image_switch_buffered/main.py @@ -1,22 +1,26 @@ import base64 import time +from dataclasses import field import httpx import flet as ft +@ft.control class BufferingSwitcher(ft.AnimatedSwitcher): - image_queue = [] + image: ft.Image | None = None + image_queue: list[str] = field(default_factory=list) - def __init__(self, image: ft.Image): - super().__init__(image) + def init(self): + self.content = self.image self.transition = ft.AnimatedSwitcherTransition.SCALE self.duration = 500 self.reverse_duration = 100 self.switch_in_curve = ft.AnimationCurve.EASE_IN self.switch_out_curve = ft.AnimationCurve.EASE_OUT - self.image_queue.append(image) + if self.image and self.image.src: + self.image_queue.append(self.image.src) def animate(self, e): self.content = ft.Image( @@ -29,11 +33,11 @@ def animate(self, e): async def fill_queue(self): while len(self.image_queue) < 10: - self.image_queue.append( - await self.image_to_base64( - f"https://picsum.photos/200/300?{time.time()}" - ) + image_base64 = await self.image_to_base64( + f"https://picsum.photos/200/300?{time.time()}" ) + if image_base64: + self.image_queue.append(image_base64) async def image_to_base64(self, url): response = await httpx.AsyncClient(follow_redirects=True).get(url) @@ -52,15 +56,24 @@ def before_update(self): def main(page: ft.Page): switcher = BufferingSwitcher( - ft.Image( - src=f"https://picsum.photos/200/300?{time.time()}", width=200, height=300 + image=ft.Image( + src=f"https://picsum.photos/200/300?{time.time()}", + width=200, + height=300, ) ) page.add( - switcher, - ft.Button("Animate!", on_click=switcher.animate), + ft.SafeArea( + content=ft.Column( + controls=[ + switcher, + ft.Button("Animate!", on_click=switcher.animate), + ] + ) + ), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/animated_switcher/image_switch_buffered/pyproject.toml b/sdk/python/examples/controls/animated_switcher/image_switch_buffered/pyproject.toml new file mode 100644 index 0000000000..4096f8f44a --- /dev/null +++ b/sdk/python/examples/controls/animated_switcher/image_switch_buffered/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "animated-switcher-image-switch-buffered" +version = "1.0.0" +description = "Buffered AnimatedSwitcher image transitions with preloaded base64 images." +requires-python = ">=3.10" +keywords = ["animated switcher", "animation", "image", "buffering", "async", "httpx"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "httpx"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Animations/AnimatedSwitcher"] + +[tool.flet.metadata] +title = "Animate image switch buffered" +controls = ["SafeArea", "Column", "AnimatedSwitcher", "Image", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["@ft.control custom switcher", "buffered image queue", "async preloading", "gapless playback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/animated_switcher/scale_effect.py b/sdk/python/examples/controls/animated_switcher/scale_effect/main.py similarity index 77% rename from sdk/python/examples/controls/animated_switcher/scale_effect.py rename to sdk/python/examples/controls/animated_switcher/scale_effect/main.py index eeef63638f..b0b4bb72ec 100644 --- a/sdk/python/examples/controls/animated_switcher/scale_effect.py +++ b/sdk/python/examples/controls/animated_switcher/scale_effect/main.py @@ -41,11 +41,18 @@ def rotate(e): switcher.update() page.add( - switcher, - ft.Button("Scale", on_click=scale), - ft.Button("Fade", on_click=fade), - ft.Button("Rotate", on_click=rotate), + ft.SafeArea( + content=ft.Column( + controls=[ + switcher, + ft.Button("Scale", on_click=scale), + ft.Button("Fade", on_click=fade), + ft.Button("Rotate", on_click=rotate), + ] + ) + ), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/animated_switcher/scale_effect/pyproject.toml b/sdk/python/examples/controls/animated_switcher/scale_effect/pyproject.toml new file mode 100644 index 0000000000..e8f25dc950 --- /dev/null +++ b/sdk/python/examples/controls/animated_switcher/scale_effect/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "animated-switcher-scale-effect" +version = "1.0.0" +description = "AnimatedSwitcher transitions between two containers with multiple effects." +requires-python = ">=3.10" +keywords = ["animated switcher", "animation", "scale", "fade", "rotation", "transition"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Animations/AnimatedSwitcher"] + +[tool.flet.metadata] +title = "Scale, fade, and rotate effects" +controls = ["SafeArea", "Column", "Container", "Text", "AnimatedSwitcher", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["multiple transitions", "animated content swap", "button-triggered effects"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/animatedswitcher.md b/sdk/python/packages/flet/docs/controls/animatedswitcher.md index 44ee2ca039..cce198f6a0 100644 --- a/sdk/python/packages/flet/docs/controls/animatedswitcher.md +++ b/sdk/python/packages/flet/docs/controls/animatedswitcher.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/animated_switcher/media ### Animated switching between two containers with scale effect ```python ---8<-- "{{ examples }}/scale_effect.py" +--8<-- "{{ examples }}/scale_effect/main.py" ``` {{ image(example_images + "/scale_effect.gif", alt="scale-effect", width="80%") }} @@ -22,13 +22,13 @@ example_images: ../examples/controls/animated_switcher/media ### Animate Image switch ```python ---8<-- "{{ examples }}/image_switch.py" +--8<-- "{{ examples }}/image_switch/main.py" ``` ### Animate Image switch buffered ```python ---8<-- "{{ examples }}/image_switch_buffered.py" +--8<-- "{{ examples }}/image_switch_buffered/main.py" ``` {{ class_members(class_name) }} From 8abc41e83d5ab30f279f3cacad0b05b82dc474c6 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 12:23:21 -0700 Subject: [PATCH 16/96] Rename BufferingSwitcher.image to content Refactor BufferingSwitcher to use a 'content' attribute instead of 'image'. Updated attribute name, initialization checks, and queue append logic to reference 'content', removed the redundant assignment from 'image' to 'content', and updated the example instantiation in main() to pass content=ft.Image(...). This clarifies intent and avoids confusion between the control and its inner Image instance. --- .../animated_switcher/image_switch_buffered/main.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sdk/python/examples/controls/animated_switcher/image_switch_buffered/main.py b/sdk/python/examples/controls/animated_switcher/image_switch_buffered/main.py index d3c176e941..436f5867dd 100644 --- a/sdk/python/examples/controls/animated_switcher/image_switch_buffered/main.py +++ b/sdk/python/examples/controls/animated_switcher/image_switch_buffered/main.py @@ -9,18 +9,17 @@ @ft.control class BufferingSwitcher(ft.AnimatedSwitcher): - image: ft.Image | None = None + content: ft.Image | None = None image_queue: list[str] = field(default_factory=list) def init(self): - self.content = self.image self.transition = ft.AnimatedSwitcherTransition.SCALE self.duration = 500 self.reverse_duration = 100 self.switch_in_curve = ft.AnimationCurve.EASE_IN self.switch_out_curve = ft.AnimationCurve.EASE_OUT - if self.image and self.image.src: - self.image_queue.append(self.image.src) + if self.content and self.content.src: + self.image_queue.append(self.content.src) def animate(self, e): self.content = ft.Image( @@ -56,7 +55,7 @@ def before_update(self): def main(page: ft.Page): switcher = BufferingSwitcher( - image=ft.Image( + content=ft.Image( src=f"https://picsum.photos/200/300?{time.time()}", width=200, height=300, From 3ed07b5ced0473a23ae711528677d080d63857c7 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 12:34:41 -0700 Subject: [PATCH 17/96] Migrate AppBar examples to project layout Rename AppBar example scripts into standalone project folders (moved to .../actions_and_popup_menu/main.py and .../theme_and_material_mode_toggles/main.py) and add corresponding pyproject.toml files. Wrap example UI in ft.SafeArea, remove unnecessary page.update() calls, and add a proper if __name__ == "__main__": ft.run(main) entrypoint. Update docs (appbar.md) to reference the new example paths. Update SKILL.md to enforce the page.update() rule for all examples in the touched folder and to require validation of SafeArea and entrypoints. --- .../create-flet-example-projects/SKILL.md | 2 + .../main.py} | 4 +- .../actions_and_popup_menu/pyproject.toml | 26 +++++++++++++ .../main.py} | 39 +++++++++++-------- .../pyproject.toml | 26 +++++++++++++ .../packages/flet/docs/controls/appbar.md | 4 +- 6 files changed, 80 insertions(+), 21 deletions(-) rename sdk/python/examples/controls/app_bar/{actions_and_popup_menu.py => actions_and_popup_menu/main.py} (92%) create mode 100644 sdk/python/examples/controls/app_bar/actions_and_popup_menu/pyproject.toml rename sdk/python/examples/controls/app_bar/{theme_and_material_mode_toggles.py => theme_and_material_mode_toggles/main.py} (73%) create mode 100644 sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/pyproject.toml diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 5d46e42bc0..66f8aa755e 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -64,6 +64,7 @@ Ensure each runnable example is a standalone project containing: 6. Make examples mobile-safe. - If `ft.context.disable_auto_update()` is not used, do not add explicit `page.update()` unless strictly necessary. +- Apply this `page.update()` rule to all examples in the touched folder (new, migrated, and already converted). - Wrap app content in `ft.SafeArea` so example renders correctly on mobile. - Apply this to all examples in the touched folder (new, migrated, and already converted), not only files changed by moves. - During validation, confirm every `/main.py` in scope includes a top-level `ft.SafeArea` around rendered content. @@ -90,6 +91,7 @@ Ensure each runnable example is a standalone project containing: - Check `git status` to confirm expected moves and edits. - When integration tests exist for the touched control, run the targeted test file(s). - Confirm all in-scope `main.py` files include both top-level `ft.SafeArea` wrapping and the `if __name__ == "__main__": ft.run(main)` entrypoint. +- Confirm there are no unnecessary `page.update()` calls in in-scope examples (unless explicitly required by isolated-control or non-auto-update behavior). ## Command checklist diff --git a/sdk/python/examples/controls/app_bar/actions_and_popup_menu.py b/sdk/python/examples/controls/app_bar/actions_and_popup_menu/main.py similarity index 92% rename from sdk/python/examples/controls/app_bar/actions_and_popup_menu.py rename to sdk/python/examples/controls/app_bar/actions_and_popup_menu/main.py index ef6b5a405f..eede1872ae 100644 --- a/sdk/python/examples/controls/app_bar/actions_and_popup_menu.py +++ b/sdk/python/examples/controls/app_bar/actions_and_popup_menu/main.py @@ -1,11 +1,11 @@ import flet as ft + def main(page: ft.Page): page.title = "AppBar Example" def handle_checked_item_click(e: ft.Event[ft.PopupMenuItem]): e.control.checked = not e.control.checked - page.update() page.appbar = ft.AppBar( leading=ft.Icon(ft.Icons.PALETTE), @@ -29,7 +29,7 @@ def handle_checked_item_click(e: ft.Event[ft.PopupMenuItem]): ), ], ) - page.add(ft.Text("Body!")) + page.add(ft.SafeArea(content=ft.Column(controls=[ft.Text("Body!")]))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/app_bar/actions_and_popup_menu/pyproject.toml b/sdk/python/examples/controls/app_bar/actions_and_popup_menu/pyproject.toml new file mode 100644 index 0000000000..78c52f2a25 --- /dev/null +++ b/sdk/python/examples/controls/app_bar/actions_and_popup_menu/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "app-bar-actions-and-popup-menu" +version = "1.0.0" +description = "AppBar with action icons and popup menu interactions." +requires-python = ">=3.10" +keywords = ["appbar", "navigation", "popup menu", "actions", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/AppBar"] + +[tool.flet.metadata] +title = "Actions and popup menu" +controls = ["AppBar", "Icon", "IconButton", "PopupMenuButton", "PopupMenuItem", "SafeArea", "Column", "Text"] +layout_pattern = "toolbar-actions" +complexity = "basic" +features = ["popup menu actions", "checked state toggle", "app bar actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles.py b/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/main.py similarity index 73% rename from sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles.py rename to sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/main.py index b2eda194b8..34dd4aef33 100644 --- a/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles.py +++ b/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/main.py @@ -9,12 +9,10 @@ def main(page: ft.Page): def handle_checked_item_click(e: ft.Event[ft.PopupMenuItem]): e.control.checked = not e.control.checked - page.update() page.theme_mode = ft.ThemeMode.LIGHT page.theme = ft.Theme(color_scheme_seed=LIGHT_SEED_COLOR, use_material3=False) page.dark_theme = ft.Theme(color_scheme_seed=DARK_SEED_COLOR, use_material3=False) - page.update() def toggle_theme_mode(e: ft.Event[ft.IconButton]): page.theme_mode = ( @@ -27,7 +25,6 @@ def toggle_theme_mode(e: ft.Event[ft.IconButton]): if page.theme_mode == ft.ThemeMode.LIGHT else ft.Icons.WB_SUNNY ) - page.update() theme_mode_toggle = ft.IconButton( icon=( @@ -49,7 +46,6 @@ def toggle_material(e: ft.Event[ft.IconButton]): material_mode_toggle.icon = ( ft.Icons.FILTER_3 if page.theme.use_material3 else ft.Icons.FILTER_2 ) - page.update() material_mode_toggle = ft.IconButton( icon=ft.Icons.FILTER_3 if page.theme.use_material3 else ft.Icons.FILTER_2, @@ -93,19 +89,28 @@ def toggle_material(e: ft.Event[ft.IconButton]): ], ) page.add( - ft.Text( - value="Flet is a framework that allows building web, desktop and mobile " - "applications in Python without prior experience in frontend development." - "You can build a UI for your program with Flet controls which are based " - "on Flutter by Google. Flet goes beyond merely wrapping Flutter widgets. " - "It adds its own touch by combining smaller widgets, simplifying " - "complexities, implementing UI best practices, and applying sensible " - "defaults. This ensures that your applications look stylish and polished " - "without requiring additional design efforts on your part.", - text_align=ft.TextAlign.END, - ), - ft.Button("Click me!"), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Flet is a framework that allows building web, desktop " + "and mobile applications in Python without prior experience " + "in frontend development.You can build a UI for your program " + "with Flet controls which are based on Flutter by Google. " + "Flet goes beyond merely wrapping Flutter widgets. It adds " + "its own touch by combining smaller widgets, simplifying " + "complexities, implementing UI best practices, and applying " + "sensible defaults. This ensures that your applications look " + "stylish and polished without requiring additional design " + "efforts on your part.", + text_align=ft.TextAlign.END, + ), + ft.Button("Click me!"), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/pyproject.toml b/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/pyproject.toml new file mode 100644 index 0000000000..0c9c01bb82 --- /dev/null +++ b/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "app-bar-theme-and-material-mode-toggles" +version = "1.0.0" +description = "AppBar example with theme mode and Material version toggles." +requires-python = ">=3.10" +keywords = ["appbar", "navigation", "theme mode", "material 3", "popup menu"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/AppBar"] + +[tool.flet.metadata] +title = "Theme and Material mode toggles" +controls = ["AppBar", "Icon", "IconButton", "PopupMenuButton", "PopupMenuItem", "SafeArea", "Column", "Text", "Button", "Theme"] +layout_pattern = "toolbar-actions" +complexity = "basic" +features = ["theme mode toggle", "material mode toggle", "popup menu interactions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/appbar.md b/sdk/python/packages/flet/docs/controls/appbar.md index 205c076c7b..62e0a4fb62 100644 --- a/sdk/python/packages/flet/docs/controls/appbar.md +++ b/sdk/python/packages/flet/docs/controls/appbar.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/app_bar/media ### Actions and Popup Menu ```python ---8<-- "{{ examples }}/actions_and_popup_menu.py" +--8<-- "{{ examples }}/actions_and_popup_menu/main.py" ``` {{ image(example_media + "/actions_and_popup_menu.gif", alt="actions-and-popup-menu", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/app_bar/media ### Theme and Material Mode Toggles ```python ---8<-- "{{ examples }}/theme_and_material_mode_toggles.py" +--8<-- "{{ examples }}/theme_and_material_mode_toggles/main.py" ``` {{ class_members(class_name) }} From 4443edbc46b6caec4d3947759f68270a74413016 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 12:42:33 -0700 Subject: [PATCH 18/96] Remove redundant page.update() calls Remove unnecessary explicit page.update() calls from example scripts to avoid extra UI refreshes. Deleted calls in sdk/python/examples/controls/animated_switcher/image_switch/main.py and sdk/python/examples/controls/column/scroll/main.py (add/remove textbox handlers and change_scroll). These rely on the framework's automatic updates, so the explicit calls were redundant. --- .../examples/controls/animated_switcher/image_switch/main.py | 1 - sdk/python/examples/controls/column/scroll/main.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/sdk/python/examples/controls/animated_switcher/image_switch/main.py b/sdk/python/examples/controls/animated_switcher/image_switch/main.py index 1cdafbdf0d..400b957016 100644 --- a/sdk/python/examples/controls/animated_switcher/image_switch/main.py +++ b/sdk/python/examples/controls/animated_switcher/image_switch/main.py @@ -10,7 +10,6 @@ def animate(e: ft.Event[ft.Button]): width=200, height=300, ) - page.update() page.add( ft.SafeArea( diff --git a/sdk/python/examples/controls/column/scroll/main.py b/sdk/python/examples/controls/column/scroll/main.py index e7a9bb7883..b39090274c 100644 --- a/sdk/python/examples/controls/column/scroll/main.py +++ b/sdk/python/examples/controls/column/scroll/main.py @@ -10,12 +10,10 @@ def add_text_box(e: ft.Event[ft.Button]): value=str(len(left_column.controls)), ) left_column.controls.append(text_field) - page.update() def remove_text_box(e: ft.Event[ft.Button]): if left_column.controls: left_column.controls.pop() - page.update() def scroll_generator(scroll_mode_list: list): while True: @@ -24,7 +22,6 @@ def scroll_generator(scroll_mode_list: list): def change_scroll(_): left_column.scroll = next(scroll_mode) scroll_mode_text.value = str(left_column.scroll) - page.update() add_text_box_button = ft.Button("Add TextBox", on_click=add_text_box) remove_text_box_button = ft.Button( From b19292c6532505848d867d8657114ec85a1af0e0 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 13:01:04 -0700 Subject: [PATCH 19/96] Add code style guidelines to Flet examples skill Introduce a 'Code style' section in the skill docs to enforce consistent argument ordering for wrapped controls (keep content= or controls= as the last named argument) and require adherence to the repository's Ruff linting rules in pyproject.toml. This ensures consistent formatting when creating or refactoring standalone Flet example projects. --- .codex/skills/create-flet-example-projects/SKILL.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 66f8aa755e..92d49bbb93 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -93,6 +93,12 @@ Ensure each runnable example is a standalone project containing: - Confirm all in-scope `main.py` files include both top-level `ft.SafeArea` wrapping and the `if __name__ == "__main__": ft.run(main)` entrypoint. - Confirm there are no unnecessary `page.update()` calls in in-scope examples (unless explicitly required by isolated-control or non-auto-update behavior). +## Code style + +- When writing wrapped controls (`SafeArea`, `Column`, `Row`, `Container`, etc.), keep `content=` or `controls=` as the last named argument in that control call. +- Apply this ordering consistently when creating or refactoring examples. +- Follow code style and linting rules defined in the repository `pyproject.toml` under `[tool.ruff]` for all edits. + ## Command checklist - Discover files: `rg --files ` From 3d028a1b9b8853b4806041783901d3c8cce9a1c5 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 13:11:21 -0700 Subject: [PATCH 20/96] Remove Material 3 toggle and rename example Remove deprecated Material 3 toggle from the AppBar theme example and rename the example to focus on theme mode only. Changes: removed use_material3 flags and the material-mode toggle UI/logic from example main.py, simplified theme initialization, updated example package metadata (pyproject.toml) to remove Material 3 references and adjust name/description/keywords/features, renamed example path from theme_and_material_mode_toggles to theme_mode_toggle, and updated docs (appbar.md) to point to the new example and title. Also updated the SKILL checklist to require removal of use_material3 and related validation steps. --- .../create-flet-example-projects/SKILL.md | 12 +++++++--- .../main.py | 22 ++----------------- .../pyproject.toml | 10 ++++----- .../packages/flet/docs/controls/appbar.md | 4 ++-- 4 files changed, 18 insertions(+), 30 deletions(-) rename sdk/python/examples/controls/app_bar/{theme_and_material_mode_toggles => theme_mode_toggle}/main.py (81%) rename sdk/python/examples/controls/app_bar/{theme_and_material_mode_toggles => theme_mode_toggle}/pyproject.toml (63%) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 92d49bbb93..dd405c9e76 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -74,24 +74,30 @@ Ensure each runnable example is a standalone project containing: - Move constructor-style setup to declarative fields + `init()` where practical. - Keep behavior unchanged and avoid refactors that alter public usage unless needed for compatibility. -8. Ensure runnable entrypoint. +8. Remove deprecated Material 3 toggle usage. +- If `use_material3` appears in example code, remove it and simplify the example to current API usage. +- Remove related Material 3 toggle logic/UI that exists only to switch `use_material3`. +- Update example metadata (`pyproject.toml`) to remove stale Material 3 references when code is changed. + +9. Ensure runnable entrypoint. - Every example `main.py` should end with: - `if __name__ == "__main__":` - ` ft.run(main)` - Apply this to all examples in the touched folder (new, migrated, and already converted). -9. Update references. +10. Update references. - Docs code includes: change from `.../example.py` to `.../example/main.py`. - Tests/imports: use direct module imports and avoid relying on package-level `__init__.py` re-exports. - For already-converted examples, only update references that are stale; avoid unnecessary churn. -10. Validate. +11. Validate. - Run `python -m compileall` on changed `main.py` files. - Search for stale paths to old flat files. - Check `git status` to confirm expected moves and edits. - When integration tests exist for the touched control, run the targeted test file(s). - Confirm all in-scope `main.py` files include both top-level `ft.SafeArea` wrapping and the `if __name__ == "__main__": ft.run(main)` entrypoint. - Confirm there are no unnecessary `page.update()` calls in in-scope examples (unless explicitly required by isolated-control or non-auto-update behavior). +- Confirm no in-scope examples use `use_material3`. ## Code style diff --git a/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/main.py b/sdk/python/examples/controls/app_bar/theme_mode_toggle/main.py similarity index 81% rename from sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/main.py rename to sdk/python/examples/controls/app_bar/theme_mode_toggle/main.py index 34dd4aef33..cf1ed36311 100644 --- a/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/main.py +++ b/sdk/python/examples/controls/app_bar/theme_mode_toggle/main.py @@ -11,8 +11,8 @@ def handle_checked_item_click(e: ft.Event[ft.PopupMenuItem]): e.control.checked = not e.control.checked page.theme_mode = ft.ThemeMode.LIGHT - page.theme = ft.Theme(color_scheme_seed=LIGHT_SEED_COLOR, use_material3=False) - page.dark_theme = ft.Theme(color_scheme_seed=DARK_SEED_COLOR, use_material3=False) + page.theme = ft.Theme(color_scheme_seed=LIGHT_SEED_COLOR) + page.dark_theme = ft.Theme(color_scheme_seed=DARK_SEED_COLOR) def toggle_theme_mode(e: ft.Event[ft.IconButton]): page.theme_mode = ( @@ -35,23 +35,6 @@ def toggle_theme_mode(e: ft.Event[ft.IconButton]): on_click=toggle_theme_mode, ) - def toggle_material(e: ft.Event[ft.IconButton]): - use_material3 = not page.theme.use_material3 - page.theme = ft.Theme( - color_scheme_seed=LIGHT_SEED_COLOR, use_material3=use_material3 - ) - page.dark_theme = ft.Theme( - color_scheme_seed=DARK_SEED_COLOR, use_material3=use_material3 - ) - material_mode_toggle.icon = ( - ft.Icons.FILTER_3 if page.theme.use_material3 else ft.Icons.FILTER_2 - ) - - material_mode_toggle = ft.IconButton( - icon=ft.Icons.FILTER_3 if page.theme.use_material3 else ft.Icons.FILTER_2, - on_click=toggle_material, - ) - page.padding = 50 page.appbar = ft.AppBar( # toolbar_height=100, @@ -62,7 +45,6 @@ def toggle_material(e: ft.Event[ft.IconButton]): center_title=False, actions=[ theme_mode_toggle, - material_mode_toggle, ft.PopupMenuButton( items=[ ft.PopupMenuItem(content="Item 1"), diff --git a/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/pyproject.toml b/sdk/python/examples/controls/app_bar/theme_mode_toggle/pyproject.toml similarity index 63% rename from sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/pyproject.toml rename to sdk/python/examples/controls/app_bar/theme_mode_toggle/pyproject.toml index 0c9c01bb82..03a0df11f3 100644 --- a/sdk/python/examples/controls/app_bar/theme_and_material_mode_toggles/pyproject.toml +++ b/sdk/python/examples/controls/app_bar/theme_mode_toggle/pyproject.toml @@ -1,9 +1,9 @@ [project] -name = "app-bar-theme-and-material-mode-toggles" +name = "app-bar-theme-mode-toggle" version = "1.0.0" -description = "AppBar example with theme mode and Material version toggles." +description = "AppBar example with theme mode toggle and popup menu actions." requires-python = ">=3.10" -keywords = ["appbar", "navigation", "theme mode", "material 3", "popup menu"] +keywords = ["appbar", "navigation", "theme mode", "popup menu"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] dependencies = ["flet"] @@ -14,11 +14,11 @@ dev = ["flet-cli", "flet-desktop", "flet-web"] categories = ["Navigation/AppBar"] [tool.flet.metadata] -title = "Theme and Material mode toggles" +title = "Theme mode toggle" controls = ["AppBar", "Icon", "IconButton", "PopupMenuButton", "PopupMenuItem", "SafeArea", "Column", "Text", "Button", "Theme"] layout_pattern = "toolbar-actions" complexity = "basic" -features = ["theme mode toggle", "material mode toggle", "popup menu interactions"] +features = ["theme mode toggle", "popup menu interactions"] [tool.flet] org = "dev.flet" diff --git a/sdk/python/packages/flet/docs/controls/appbar.md b/sdk/python/packages/flet/docs/controls/appbar.md index 62e0a4fb62..98fb0c00a4 100644 --- a/sdk/python/packages/flet/docs/controls/appbar.md +++ b/sdk/python/packages/flet/docs/controls/appbar.md @@ -20,10 +20,10 @@ example_media: ../examples/controls/app_bar/media {{ image(example_media + "/actions_and_popup_menu.gif", alt="actions-and-popup-menu", width="80%") }} -### Theme and Material Mode Toggles +### Theme Mode Toggle ```python ---8<-- "{{ examples }}/theme_and_material_mode_toggles/main.py" +--8<-- "{{ examples }}/theme_mode_toggle/main.py" ``` {{ class_members(class_name) }} From 40b1ea3946b2542d04c2b889edb6e2d6a8a26a88 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 13:27:47 -0700 Subject: [PATCH 21/96] Organize AutoComplete example and add pyproject Rename and restructure the AutoComplete example: move basic.py to basic/main.py, wrap the AutoComplete control in SafeArea and Column (placing the info Text alongside it) and add a standard if __name__ == "__main__" guard for ft.run. Add a pyproject.toml for the example with project metadata, dependencies, and tool.flet gallery metadata. Update the autocomplete docs include to point to the new basic/main.py path. --- .../auto_complete/{basic.py => basic/main.py} | 31 ++++++++++++------- .../auto_complete/basic/pyproject.toml | 26 ++++++++++++++++ .../flet/docs/controls/autocomplete.md | 2 +- 3 files changed, 47 insertions(+), 12 deletions(-) rename sdk/python/examples/controls/auto_complete/{basic.py => basic/main.py} (52%) create mode 100644 sdk/python/examples/controls/auto_complete/basic/pyproject.toml diff --git a/sdk/python/examples/controls/auto_complete/basic.py b/sdk/python/examples/controls/auto_complete/basic/main.py similarity index 52% rename from sdk/python/examples/controls/auto_complete/basic.py rename to sdk/python/examples/controls/auto_complete/basic/main.py index 750a331e4d..7edc3f42bc 100644 --- a/sdk/python/examples/controls/auto_complete/basic.py +++ b/sdk/python/examples/controls/auto_complete/basic/main.py @@ -29,18 +29,27 @@ def handle_select(e: ft.AutoCompleteSelectEvent): ) page.add( - ft.AutoComplete( - value="One", - width=200, - on_change=handle_change, - on_select=handle_select, - suggestions=[ - ft.AutoCompleteSuggestion(key=key, value=value) - for key, value in numbers - ], + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AutoComplete( + value="One", + width=200, + on_change=handle_change, + on_select=handle_select, + suggestions=[ + ft.AutoCompleteSuggestion(key=key, value=value) + for key, value in numbers + ], + ), + info := ft.Text( + "Enter a number (in words or digits) to get suggestions." + ), + ] + ) ), - info := ft.Text("Enter a number (in words or digits) to get suggestions."), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/auto_complete/basic/pyproject.toml b/sdk/python/examples/controls/auto_complete/basic/pyproject.toml new file mode 100644 index 0000000000..f5e35a1a6c --- /dev/null +++ b/sdk/python/examples/controls/auto_complete/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "auto-complete-basic" +version = "1.0.0" +description = "Basic AutoComplete with change and select event handling." +requires-python = ">=3.10" +keywords = ["autocomplete", "input", "suggestions", "events", "selection"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/AutoComplete"] + +[tool.flet.metadata] +title = "Basic AutoComplete" +controls = ["SafeArea", "Column", "AutoComplete", "AutoCompleteSuggestion", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["input suggestions", "on_change handling", "on_select handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/autocomplete.md b/sdk/python/packages/flet/docs/controls/autocomplete.md index 117b806fe0..cf38ec1a76 100644 --- a/sdk/python/packages/flet/docs/controls/autocomplete.md +++ b/sdk/python/packages/flet/docs/controls/autocomplete.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/auto_complete/media ### Basic example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` From b15764c71d53b097cc97341ca7ef8ee496661387 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 14:13:47 -0700 Subject: [PATCH 22/96] Move example scripts to main.py and add pyproject Reorganize Python example files: replace example root scripts with main.py entrypoints and add per-example pyproject.toml metadata. AutofillGroup example moved to basic/main.py, wrapped in SafeArea, added __main__ guard and new pyproject. Badge example renamed to basic/main.py (removed package __init__.py), minor layout change wrapping body in SafeArea/Column, and added its pyproject. Update docs to point to "basic/main.py" paths and update integration test import to import examples.controls.badge.basic.main. Remove obsolete files from the previous layout. --- .../examples/controls/autofill_group/basic.py | 35 ----------------- .../controls/autofill_group/basic/main.py | 38 +++++++++++++++++++ .../autofill_group/basic/pyproject.toml | 26 +++++++++++++ .../examples/controls/badge/__init__.py | 0 .../badge/{basic.py => basic/main.py} | 2 +- .../controls/badge/basic/pyproject.toml | 26 +++++++++++++ .../flet/docs/controls/autofillgroup.md | 2 +- sdk/python/packages/flet/docs/types/badge.md | 2 +- .../examples/material/test_badge.py | 2 +- 9 files changed, 94 insertions(+), 39 deletions(-) delete mode 100644 sdk/python/examples/controls/autofill_group/basic.py create mode 100644 sdk/python/examples/controls/autofill_group/basic/main.py create mode 100644 sdk/python/examples/controls/autofill_group/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/badge/__init__.py rename sdk/python/examples/controls/badge/{basic.py => basic/main.py} (90%) create mode 100644 sdk/python/examples/controls/badge/basic/pyproject.toml diff --git a/sdk/python/examples/controls/autofill_group/basic.py b/sdk/python/examples/controls/autofill_group/basic.py deleted file mode 100644 index 0d630481b8..0000000000 --- a/sdk/python/examples/controls/autofill_group/basic.py +++ /dev/null @@ -1,35 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.AutofillGroup( - content=ft.Column( - controls=[ - ft.TextField( - label="Name", - autofill_hints=ft.AutofillHint.NAME, - ), - ft.TextField( - label="Email", - autofill_hints=[ft.AutofillHint.EMAIL], - ), - ft.TextField( - label="Phone Number", - autofill_hints=[ft.AutofillHint.TELEPHONE_NUMBER], - ), - ft.TextField( - label="Street Address", - autofill_hints=ft.AutofillHint.FULL_STREET_ADDRESS, - ), - ft.TextField( - label="Postal Code", - autofill_hints=ft.AutofillHint.POSTAL_CODE, - ), - ] - ) - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/autofill_group/basic/main.py b/sdk/python/examples/controls/autofill_group/basic/main.py new file mode 100644 index 0000000000..b391f4f215 --- /dev/null +++ b/sdk/python/examples/controls/autofill_group/basic/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.AutofillGroup( + content=ft.Column( + controls=[ + ft.TextField( + label="Name", + autofill_hints=ft.AutofillHint.NAME, + ), + ft.TextField( + label="Email", + autofill_hints=[ft.AutofillHint.EMAIL], + ), + ft.TextField( + label="Phone Number", + autofill_hints=[ft.AutofillHint.TELEPHONE_NUMBER], + ), + ft.TextField( + label="Street Address", + autofill_hints=ft.AutofillHint.FULL_STREET_ADDRESS, + ), + ft.TextField( + label="Postal Code", + autofill_hints=ft.AutofillHint.POSTAL_CODE, + ), + ] + ) + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/autofill_group/basic/pyproject.toml b/sdk/python/examples/controls/autofill_group/basic/pyproject.toml new file mode 100644 index 0000000000..3127e997f6 --- /dev/null +++ b/sdk/python/examples/controls/autofill_group/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "autofill-group-basic" +version = "1.0.0" +description = "Basic AutofillGroup with common autofill hints." +requires-python = ">=3.10" +keywords = ["autofillgroup", "autofill", "input", "text field", "form"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/AutofillGroup"] + +[tool.flet.metadata] +title = "Basic AutofillGroup" +controls = ["SafeArea", "AutofillGroup", "Column", "TextField"] +layout_pattern = "form" +complexity = "basic" +features = ["autofill hints", "grouped form fields"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/badge/__init__.py b/sdk/python/examples/controls/badge/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/badge/basic.py b/sdk/python/examples/controls/badge/basic/main.py similarity index 90% rename from sdk/python/examples/controls/badge/basic.py rename to sdk/python/examples/controls/badge/basic/main.py index 2c2972e81e..1bcb907ef2 100644 --- a/sdk/python/examples/controls/badge/basic.py +++ b/sdk/python/examples/controls/badge/basic/main.py @@ -24,7 +24,7 @@ def main(page: ft.Page): ), ] ) - page.add(ft.Text("Body!")) + page.add(ft.SafeArea(content=ft.Column(controls=[ft.Text("Body!")]))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/badge/basic/pyproject.toml b/sdk/python/examples/controls/badge/basic/pyproject.toml new file mode 100644 index 0000000000..1172027519 --- /dev/null +++ b/sdk/python/examples/controls/badge/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "badge-basic" +version = "1.0.0" +description = "Basic Badge usage on NavigationBar icons." +requires-python = ">=3.10" +keywords = ["badge", "display", "navigation bar", "icon", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Badge"] + +[tool.flet.metadata] +title = "Basic Badge" +controls = ["NavigationBar", "NavigationBarDestination", "Icon", "Badge", "SafeArea", "Column", "Text"] +layout_pattern = "navigation" +complexity = "basic" +features = ["badge on icon", "text badge", "small badge indicator"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/autofillgroup.md b/sdk/python/packages/flet/docs/controls/autofillgroup.md index bf62110a5f..64ff1c4e8f 100644 --- a/sdk/python/packages/flet/docs/controls/autofillgroup.md +++ b/sdk/python/packages/flet/docs/controls/autofillgroup.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/autofill_group/media ### Basic example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/badge.md b/sdk/python/packages/flet/docs/types/badge.md index e393ff734d..93bb96924d 100644 --- a/sdk/python/packages/flet/docs/types/badge.md +++ b/sdk/python/packages/flet/docs/types/badge.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/badge ### Badge decorating an icon on a NavigationBar ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_badge.py b/sdk/python/packages/flet/integration_tests/examples/material/test_badge.py index 67a8ee52b7..76749ebfaa 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_badge.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_badge.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.badge.basic.main as basic import flet as ft import flet.testing as ftt -from examples.controls.badge import basic @pytest.mark.asyncio(loop_scope="function") From fe7e517549af7be41f81de62cc05b53710a938a1 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 10 Mar 2026 14:22:07 -0700 Subject: [PATCH 23/96] Move examples to main.py and add pyproject Refactor example files: rename example scripts to main.py (banner/basic, bottom_app_bar/border_radius, bottom_app_bar/notched_fab), wrap example page content in SafeArea/Column and guard ft.run with if __name__ == "__main__". Add pyproject.toml metadata for each example (banner-basic, bottom-app-bar-border-radius, bottom-app-bar-notched-fab). Remove bottom_app_bar __init__.py and update docs and integration test imports to reference the new example paths. --- .../banner/{basic.py => basic/main.py} | 15 +++++++++-- .../controls/banner/basic/pyproject.toml | 26 +++++++++++++++++++ .../controls/bottom_app_bar/__init__.py | 0 .../main.py} | 2 +- .../border_radius/pyproject.toml | 26 +++++++++++++++++++ .../{notched_fab.py => notched_fab/main.py} | 2 +- .../bottom_app_bar/notched_fab/pyproject.toml | 26 +++++++++++++++++++ .../packages/flet/docs/controls/banner.md | 2 +- .../flet/docs/controls/bottomappbar.md | 4 +-- .../examples/material/test_bottom_app_bar.py | 3 ++- 10 files changed, 98 insertions(+), 8 deletions(-) rename sdk/python/examples/controls/banner/{basic.py => basic/main.py} (80%) create mode 100644 sdk/python/examples/controls/banner/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/bottom_app_bar/__init__.py rename sdk/python/examples/controls/bottom_app_bar/{border_radius.py => border_radius/main.py} (88%) create mode 100644 sdk/python/examples/controls/bottom_app_bar/border_radius/pyproject.toml rename sdk/python/examples/controls/bottom_app_bar/{notched_fab.py => notched_fab/main.py} (91%) create mode 100644 sdk/python/examples/controls/bottom_app_bar/notched_fab/pyproject.toml diff --git a/sdk/python/examples/controls/banner/basic.py b/sdk/python/examples/controls/banner/basic/main.py similarity index 80% rename from sdk/python/examples/controls/banner/basic.py rename to sdk/python/examples/controls/banner/basic/main.py index b9512478d6..38fe8f4578 100644 --- a/sdk/python/examples/controls/banner/basic.py +++ b/sdk/python/examples/controls/banner/basic/main.py @@ -39,7 +39,18 @@ def handle_banner_close(e: ft.Event[ft.TextButton]): ], ) - page.add(ft.Button("Show Banner", on_click=lambda e: page.show_dialog(banner))) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Show Banner", on_click=lambda e: page.show_dialog(banner) + ) + ] + ) + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/banner/basic/pyproject.toml b/sdk/python/examples/controls/banner/basic/pyproject.toml new file mode 100644 index 0000000000..42eda939e0 --- /dev/null +++ b/sdk/python/examples/controls/banner/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "banner-basic" +version = "1.0.0" +description = "Basic Banner dialog with action buttons." +requires-python = ">=3.10" +keywords = ["banner", "dialog", "actions", "material", "notification"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/Banner"] + +[tool.flet.metadata] +title = "Basic Banner" +controls = ["SafeArea", "Column", "Button", "Banner", "Icon", "Text", "TextButton"] +layout_pattern = "dialog-flow" +complexity = "basic" +features = ["banner dialog", "action buttons", "dialog close and follow-up message"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/bottom_app_bar/__init__.py b/sdk/python/examples/controls/bottom_app_bar/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/bottom_app_bar/border_radius.py b/sdk/python/examples/controls/bottom_app_bar/border_radius/main.py similarity index 88% rename from sdk/python/examples/controls/bottom_app_bar/border_radius.py rename to sdk/python/examples/controls/bottom_app_bar/border_radius/main.py index 73ba65b856..e23794c53e 100644 --- a/sdk/python/examples/controls/bottom_app_bar/border_radius.py +++ b/sdk/python/examples/controls/bottom_app_bar/border_radius/main.py @@ -18,7 +18,7 @@ def main(page: ft.Page): ), ) - page.add(ft.Text("Content goes here...")) + page.add(ft.SafeArea(content=ft.Column(controls=[ft.Text("Content goes here...")]))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/bottom_app_bar/border_radius/pyproject.toml b/sdk/python/examples/controls/bottom_app_bar/border_radius/pyproject.toml new file mode 100644 index 0000000000..ee7bd517a8 --- /dev/null +++ b/sdk/python/examples/controls/bottom_app_bar/border_radius/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "bottom-app-bar-border-radius" +version = "1.0.0" +description = "BottomAppBar with custom border radius." +requires-python = ">=3.10" +keywords = ["bottom app bar", "navigation", "border radius", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/BottomAppBar"] + +[tool.flet.metadata] +title = "BottomAppBar border radius" +controls = ["BottomAppBar", "Row", "IconButton", "Container", "SafeArea", "Column", "Text"] +layout_pattern = "navigation" +complexity = "basic" +features = ["custom border radius", "app bar actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/bottom_app_bar/notched_fab.py b/sdk/python/examples/controls/bottom_app_bar/notched_fab/main.py similarity index 91% rename from sdk/python/examples/controls/bottom_app_bar/notched_fab.py rename to sdk/python/examples/controls/bottom_app_bar/notched_fab/main.py index ea1b3dd187..4e3e1dee21 100644 --- a/sdk/python/examples/controls/bottom_app_bar/notched_fab.py +++ b/sdk/python/examples/controls/bottom_app_bar/notched_fab/main.py @@ -24,7 +24,7 @@ def main(page: ft.Page): ), ) - page.add(ft.Text("Content goes here...")) + page.add(ft.SafeArea(content=ft.Column(controls=[ft.Text("Content goes here...")]))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/bottom_app_bar/notched_fab/pyproject.toml b/sdk/python/examples/controls/bottom_app_bar/notched_fab/pyproject.toml new file mode 100644 index 0000000000..f36832054d --- /dev/null +++ b/sdk/python/examples/controls/bottom_app_bar/notched_fab/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "bottom-app-bar-notched-fab" +version = "1.0.0" +description = "BottomAppBar with a notched centered FloatingActionButton." +requires-python = ">=3.10" +keywords = ["bottom app bar", "navigation", "floating action button", "notch", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/BottomAppBar"] + +[tool.flet.metadata] +title = "Notched FloatingActionButton" +controls = ["BottomAppBar", "FloatingActionButton", "Row", "IconButton", "Container", "SafeArea", "Column", "Text"] +layout_pattern = "navigation" +complexity = "basic" +features = ["center docked FAB", "notched app bar", "app bar actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/banner.md b/sdk/python/packages/flet/docs/controls/banner.md index 242aad0e43..72baf19628 100644 --- a/sdk/python/packages/flet/docs/controls/banner.md +++ b/sdk/python/packages/flet/docs/controls/banner.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/banner/media ### Basic example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/bottomappbar.md b/sdk/python/packages/flet/docs/controls/bottomappbar.md index e2b500afe5..d469bd9918 100644 --- a/sdk/python/packages/flet/docs/controls/bottomappbar.md +++ b/sdk/python/packages/flet/docs/controls/bottomappbar.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/bottom_app_bar ### Notched `FloatingActionButton` ```python ---8<-- "{{ examples }}/notched_fab.py" +--8<-- "{{ examples }}/notched_fab/main.py" ``` {{ image(example_images + "/notched_fab.png", width="80%") }} @@ -21,7 +21,7 @@ example_images: ../test-images/examples/material/golden/macos/bottom_app_bar ### Custom border radius ```python ---8<-- "{{ examples }}/border_radius.py" +--8<-- "{{ examples }}/border_radius/main.py" ``` {{ image(example_images + "/border_radius.png", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_bottom_app_bar.py b/sdk/python/packages/flet/integration_tests/examples/material/test_bottom_app_bar.py index 32e55ea9ad..fff254d679 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_bottom_app_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_bottom_app_bar.py @@ -1,8 +1,9 @@ import pytest +import examples.controls.bottom_app_bar.border_radius.main as border_radius +import examples.controls.bottom_app_bar.notched_fab.main as notched_fab import flet as ft import flet.testing as ftt -from examples.controls.bottom_app_bar import border_radius, notched_fab @pytest.mark.asyncio(loop_scope="function") From 6160f72cd73cabc03c8f3561c655a67f8ce117da Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 08:11:48 -0700 Subject: [PATCH 24/96] Reorganize bottom_sheet examples and add metadata Move bottom_sheet example scripts into per-example subpackages (basic/main.py, fullscreen/main.py) and remove the old top-level files. Wrap example BottomSheet contents with SafeArea to handle intrusions, add pyproject.toml metadata for both examples (gallery, controls, features), and remove the examples __init__.py. Update docs examples includes to point to the new main.py paths and adjust integration test imports accordingly. Golden example images were also updated. --- .../controls/bottom_sheet/__init__.py | 0 .../bottom_sheet/{basic.py => basic/main.py} | 16 ++++-- .../bottom_sheet/basic/pyproject.toml | 26 ++++++++++ .../controls/bottom_sheet/fullscreen.py | 35 ------------- .../controls/bottom_sheet/fullscreen/main.py | 47 ++++++++++++++++++ .../bottom_sheet/fullscreen/pyproject.toml | 26 ++++++++++ .../flet/docs/controls/bottomsheet.md | 4 +- .../golden/macos/bottom_sheet/basic.gif | Bin 14537 -> 19362 bytes .../golden/macos/bottom_sheet/fullscreen.gif | Bin 38191 -> 50647 bytes .../examples/material/test_bottom_sheet.py | 3 +- 10 files changed, 116 insertions(+), 41 deletions(-) delete mode 100644 sdk/python/examples/controls/bottom_sheet/__init__.py rename sdk/python/examples/controls/bottom_sheet/{basic.py => basic/main.py} (63%) create mode 100644 sdk/python/examples/controls/bottom_sheet/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/bottom_sheet/fullscreen.py create mode 100644 sdk/python/examples/controls/bottom_sheet/fullscreen/main.py create mode 100644 sdk/python/examples/controls/bottom_sheet/fullscreen/pyproject.toml diff --git a/sdk/python/examples/controls/bottom_sheet/__init__.py b/sdk/python/examples/controls/bottom_sheet/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/bottom_sheet/basic.py b/sdk/python/examples/controls/bottom_sheet/basic/main.py similarity index 63% rename from sdk/python/examples/controls/bottom_sheet/basic.py rename to sdk/python/examples/controls/bottom_sheet/basic/main.py index caa3e255e2..d177d87532 100644 --- a/sdk/python/examples/controls/bottom_sheet/basic.py +++ b/sdk/python/examples/controls/bottom_sheet/basic/main.py @@ -24,9 +24,19 @@ def handle_sheet_dismissal(e: ft.Event[ft.DialogControl]): ) page.add( - ft.Button( - content="Display bottom sheet", - on_click=lambda e: page.show_dialog(sheet), + ft.SafeArea( + # avoid_intrusions_left=False, + # avoid_intrusions_top=False, + # avoid_intrusions_right=False, + # avoid_intrusions_bottom=False, + content=ft.Column( + controls=[ + ft.Button( + content="Display bottom sheet", + on_click=lambda e: page.show_dialog(sheet), + ) + ] + ), ) ) diff --git a/sdk/python/examples/controls/bottom_sheet/basic/pyproject.toml b/sdk/python/examples/controls/bottom_sheet/basic/pyproject.toml new file mode 100644 index 0000000000..8ca7ef2873 --- /dev/null +++ b/sdk/python/examples/controls/bottom_sheet/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "bottom-sheet-basic" +version = "1.0.0" +description = "Basic BottomSheet dialog with dismiss handling." +requires-python = ">=3.10" +keywords = ["bottom sheet", "dialog", "material", "dismiss", "actions"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/BottomSheet"] + +[tool.flet.metadata] +title = "Basic BottomSheet" +controls = ["SafeArea", "Column", "Button", "BottomSheet", "Container", "Text"] +layout_pattern = "dialog-flow" +complexity = "basic" +features = ["bottom sheet dialog", "dismiss callback", "dialog actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/bottom_sheet/fullscreen.py b/sdk/python/examples/controls/bottom_sheet/fullscreen.py deleted file mode 100644 index b3696825f9..0000000000 --- a/sdk/python/examples/controls/bottom_sheet/fullscreen.py +++ /dev/null @@ -1,35 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_switch_change(e: ft.Event[ft.Switch]): - sheet.fullscreen = e.control.value - - sheet = ft.BottomSheet( - fullscreen=True, - show_drag_handle=True, - content=ft.Container( - padding=ft.Padding.all(10), - content=ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text("This is bottom sheet's content!"), - ft.Button("Close bottom sheet", on_click=lambda: page.pop_dialog()), - ], - ), - ), - ) - - page.add( - ft.Button( - content="Display bottom sheet", - on_click=lambda e: page.show_dialog(sheet), - ), - ft.Switch(value=True, label="Fullscreen", on_change=handle_switch_change), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/bottom_sheet/fullscreen/main.py b/sdk/python/examples/controls/bottom_sheet/fullscreen/main.py new file mode 100644 index 0000000000..604fd90a8c --- /dev/null +++ b/sdk/python/examples/controls/bottom_sheet/fullscreen/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def handle_switch_change(e: ft.Event[ft.Switch]): + sheet.fullscreen = e.control.value + + sheet = ft.BottomSheet( + fullscreen=True, + show_drag_handle=True, + content=ft.SafeArea( + avoid_intrusions_left=False, + avoid_intrusions_top=False, + avoid_intrusions_right=False, + avoid_intrusions_bottom=False, + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("This is bottom sheet's content!"), + ft.Button( + "Close bottom sheet", on_click=lambda: page.pop_dialog() + ), + ], + ), + ), + ), + ) + + page.add( + ft.Button( + content="Display bottom sheet", + on_click=lambda e: page.show_dialog(sheet), + ), + ft.Switch( + value=True, + label="Fullscreen", + on_change=handle_switch_change, + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/bottom_sheet/fullscreen/pyproject.toml b/sdk/python/examples/controls/bottom_sheet/fullscreen/pyproject.toml new file mode 100644 index 0000000000..ed8a9d2eff --- /dev/null +++ b/sdk/python/examples/controls/bottom_sheet/fullscreen/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "bottom-sheet-fullscreen" +version = "1.0.0" +description = "BottomSheet with fullscreen toggle and drag handle." +requires-python = ">=3.10" +keywords = ["bottom sheet", "dialog", "fullscreen", "switch", "drag handle"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/BottomSheet"] + +[tool.flet.metadata] +title = "BottomSheet fullscreen" +controls = ["SafeArea", "Column", "Button", "Switch", "BottomSheet", "Container", "Text"] +layout_pattern = "dialog-flow" +complexity = "basic" +features = ["fullscreen toggle", "bottom sheet dialog", "drag handle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/bottomsheet.md b/sdk/python/packages/flet/docs/controls/bottomsheet.md index 53d4e5feb8..6c66c0c423 100644 --- a/sdk/python/packages/flet/docs/controls/bottomsheet.md +++ b/sdk/python/packages/flet/docs/controls/bottomsheet.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/bottom_sheet ### Basic example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.gif", width="60%") }} @@ -21,7 +21,7 @@ example_images: ../test-images/examples/material/golden/macos/bottom_sheet ### Fullscreen ```python ---8<-- "{{ examples }}/fullscreen.py" +--8<-- "{{ examples }}/fullscreen/main.py" ``` {{ image(example_images + "/fullscreen.gif", width="60%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/basic.gif b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/basic.gif index cb51a04769e6e04647e8058ffc2c64f03eeb21b9..ee176dbd4642ecb2761b380e168a2151c4fbff26 100644 GIT binary patch literal 19362 zcmeF&XHZl9`!4zm^MAW%cIKLI){B%i$y%A@`rOgbQkS`7SqTcE2?qcU z|4j&}F{?(F{E-Z{&kt?j>C+h^#_1(3zb!~ffV}Esh ze`S4db!~fjZEtC9Z)J6RWp!(1m9n(DyS%csyh2%C*<4!QTwK{*SlL-v-dSAQTwK~% zTv}gP+*nvVTi527x966&XP35T7PsaX*5(&h=jP9{GB>v}v#>S2K$)Feoju#0U7nsf z%hL4BB6*%dp5L6B+nk)+oS5AhpIIkQFN{sEk4~>mkr$`P3sdCz$*Hr3Ge|&jtY z4-Ag=j4YBy7P^NQx`yUE2j}|-M*I3ldi%~Y+|xVM(=*gf8tCfo@9gU97@X@Em}?)H zZR?+HJxkwAbMJIh&vYY++;Eoesk*MI&d%PB&c61Jp7st>TRW+xwX3W7Nz1`BHke%1~Y z5c_}B^nI`H`*xP9-Y=Cs`4yzRa#HSD%DQvPy0c5WvVM1E{_e~y>C7nUOfT*r6t$-o zwWSuer4+U$|7=YvXi5Ch^7$;^n-jh_$A4@3be6A;abFrgerf!W-w>NuACp)AKDQ2^ zQx~0G8sw|75WBELJo{pJ+$)$z?2`|y0*usrLKT+84b z3rx0IQ0BA143pPsMlT5lFH#6R(JiR=n#9$G79kjeG#NG=&2b#Qc==ZlafHv z0MBkI_y-JVIlC7B=U)GuCIBcE0EF^t77%KKq35rdwiKk*hr@-nlQe&(H@@YPb{cQ_ znb90Apc28WRhZctEA}Ygw6!p+{S(r()VVxA+vcmcHc|AXqvmrD$Ms_{fLz+;wj6(Un`TzPVIxU)LdT~iZ8T}4pL z{lO9<02hL|u@0xtv3=DkFkFyRLi!d-|G?eXYZjs9u%b#DXTo3%L1ZsC;_yp+o z#X%|nV=52swr46$z}9+qrr6d3w*=}JWu31z>}&cvLVv8h<^*2$%T*@|jL}3f_PzJo zkY>1jT+sH1Nx8dSO!q~5`@D?S&qjDTqcrZa&6h3H@%{Gc=EXs4Z#jW>now_Hf9xCZ zWsSTZy}sYQRm7V%uxNE+2|YYD{RH6BB}-O#C_Yx=dRmmo3}&6Y=hOHX z;}SjG(@5>~iS>2My*-7{Ln}4eHQz+T_|LgK80$rV3a<9t6b$3KtD8e)`&=0VW$h33 z_yd9ZQNk~$A5UNQ#%PGva>f&tThH~nxR-H>=-#fMN158+h6NKq5xm249$HuP_3P@r z<#0Xp6(NyPXf`W-ukZINAJJ)u{`_EtqwAORxHHJm&=Ya#fngv_JUoeP2E%?8ir~)F zv424uT#CgV4K6FTUTGChT3CS7KS6^$dmJZsy4d9;`=eDZaVgF$7y!6#M7i{Dfh$H? z5wRmG7kXJ~djSv@un+;XCIuE<02cW1)&-iYph3oxbs<%hI~J(N*Rs#Q^XgFn4wfZc zp*lIRyy(El>T%Jv6xP-(?jmhM6&3F(+eHstm_Y!)gkR6ji1MPfKBp=U0c(>Z(UR78 z@9J9-BY-ytZ;HFFftqR3iZG&}jtedyn1u?U$QMu{SzksIw!7e9kS9Yv=EO_nlvf8N!aQ(D=WC8?MhI88{G(*z=Xldd9qp8({#)LK{coi7Mx&@H8B z(D>>1@XjeK3II78FNbwJ3WU!iGyBwDI|t(y(;IIo`$n!2Frk9aG$bzXN8$s7qoqvk zT6!-g-_ifcXNm5T7`ds*T&t)U?$7X>ZA7s7<~do0U(J_9TD6xHm0aV+z}E>dDvLl0 z^6hYZ)0J-8=yvbG3qxnYRLlvL7Lhvez^KM8Q z)`Weuns>y@@1D?l9)TkW z65saS)HsKGt(R6%wTH%M1U_dQ*i$unhJBJZWiTm4td?npe3S&>^-{BHEs=Ub`+DZ z%ND`h+DVpAhTiuABk&%I^GbR!Bi1V1YM&6Ma8aMxHyI@B&ZzEPS}S2dRknA3GB)b1 z{7OPqk&d?dS95QQilM1uGdo~)#mlMoyYN#DkgzGOHyh=h*BhEIi&9|k8RB*MTg120uF1Au#H>1a& z&=u~-(@m=ro83@DR&YETY`lnJ%?HV*{c83}n{7|}8)dc;Kg$e>kh;(|Yr3c}4$^bC zVyZuID!Z2Mz421QQj?B(t&r9`0v5d_;8)+Rgn9m>9$T9-nAMy2U9L&6%d3heksWO( zkdHGsqpOwKg z4K@MmW(nxKC;14D!EPnH7B&RKL(p2-6~unHt2^d8e}#A}bstzX^@n#ZMW+mEBJFL3 z9Eucz*M5kPy4{@>7BRbiM^C`1rR#)ubwrq_`)5f#gG;oeuIPCrM9)|RZ%O&P zuIv7q$#(H^efyeTUt?P-Ue~H*lf-UU5YmPp2myZX`!#!UkUiiE_NzX>HNO0*`VId> zm=k@#5Exvrz0z-*-Fxe+x0QRu^IxS7%SVf4(5ndjf_CD!=X4cq4j;UV81#U7f4|r>R)rz556l@!*gH_(%TJ?(ZKFODwf3IS2YwcqHPmhwmMo5gcZQHF-yk~DX2A=Gn_ zYu{_T!;KgwHm#6gp02PE*w!jB&eYn zIRBW#-xj>giTD6OW|0CT!U3KXx*!6L{4M1!iV1V5v6HC7Qs@{{; z3cTwRY*%|tfqdA@h1DcpMUUXNc++}bH2LuJ}GFI^MxLT_a556sK7tU%R!9G z)I`hy@QCGTKXf0(+@2A3$(AL--D5F^X%1wt7UM-?)%7lxg}O8R5Jg4Fm6d{6qyoUr0Eg6h*30|Pk zyu27;Ey*vTPxIFB#irt2#bND{@Sx5D`Zj%)`cTx`HnV+;#3Eh;vlFyd$lL~JRt*V- z5?-z;GmT-MKC^bx;6yMeK2wusHl_MWOwuBlqxj@bL9g zZj@k46dlBHN}r(^#XMc?Pg?Tt?(tCDVQR<6?ox0cxlA`GjDrBfM@_Lq`>_ZE8VR%> zy%qMB^1@Q85 zvA|hJ640npRijhWjkEPfu9r;qMXsXfY*eXt== znCbf=Z@iWsA_gpk()7^cpdkPslLZ^%Z!7{B**FnZ_AH%ji2Q6Rs^5GBD z>OjJp6m1U%s^!SiNYw|4YrX7|1g}Z4&^|%zO3?PmuVqH;1H|;B<3aJNqH8$7o<)GT;j|y`>AIP7lSTjFj#$DlzKQ= zm^(nVr1dkhK)+%KQ-G%KS#}1w^ylcCNU7f%a#Lhqm{Nf9=kv@Z{e1F7N^_wPjB?P=X_tuv!le}Wxp6H0l4vCBg&TnL0ShwZrk5H zBRrTJncvXHzS<9I-2OUR{*9XiiGKRc%JQog>dV;E?=?=4UhQvW?JqDg$ksi7f&0fm z4A_&Vn99sFq^=a!+dt2K0pvo>x0Sz92LAP1o*&d1@!^- zuL=xnuSpPS-2gxN7_PVxX!l?J3>+#!BM=z9{>w}4iS0J?y$sHmvAkpR4+4}L~P(Y=GiBGGjA`m{1| z5R*RO>)T4Zv`R)2@H!l9tPgR+(*=;BcsMMERC9V%1K=fs?h(PJM9A4rB@yW>iHze! z=3^q9xAxqt&MaWh?9Njn~T`*DLZiDBo*PHEmG$Z_qG>*brz<2w-It%~cZcygLA^ zQ|DvJ4MqWAC>aDCbcp~$@itlAYqBwIvh#0pNNRGbY;qoNay@Qx=WX`9*X(WD?Calr z1qBi$0Ucuj5CPui=Z#L5+__2sTK5)QQcDE2vL$l7CF-~Z&)XVvul0jzYn*>;d{XP@ z%GRXu)|AMWJV{>cy|zr#wru~l+@!Yr%C@iLZQqaE3V7QK@3sFjZ7=a}FHLGMuWYXz zZ?8UXC-QdG-Ro#D?P&7vXi4g5tL*3)@8~-2An|tg-s|i)?Hu&)98T&St?V2h@0>jD zB=dI7-0PY%?OO2fT1x6#sq9)C@7g%-qVRTa-|OBr?cVqAK1}NVTiJa)-hF!94M31U zawM=B>Fh{@CX?u^NQ@IC<`WVe(Q{6&hs~^qBcO*Xxre)|hj*ff@1#cn(JLg^D`M7r zDWF#@x%Wy{ulPi-#7Qp_(I+L>cY|uycPpSzCb>_xs_))JpZrOmBBEbeu3y!xUp=5- zGr3>8s$X}aU+<(}A2DDcH(+QsU>q=Dl05LVYQS`2!2DzYg&4Gw8?-SSvm z8g!l*bUhh#M+|w&4SAal`34O6B@ex-8uFhQ3OpG?BZjeZ!y#tFVFAOqM zsFPtlVkAaxwxVl-WDG}CM}J76?7c{IOj^y|dv_mj~A z#8{!+*e|oOl7O+&XR`dV!Tdnyuoa|DPX)MdAzM^ykla#>tvjSnCO+8 z=r@}f444>Bo*1o~7@wG!q@GNW5tB1=lXGU13jvc$$&)KplWP-`8z++##MHLj)UMgo ze!$dW^3>m|spE;M(~~Ix9~mT12Ah*1fn;b3nZBCLI7wzcCBylq&&f}-nNM>BPIIM9 zb5~FEPEPZkP7CnO2+7Zgn9p1aoDoZzxl%nNJ~<8v8(oU;6!s`;FH;GAa4oObn`?&O@_>6|{_yn+0@q4~UV;Jiu7{L|`r)5&@B z(|Hu%f|dM&jroFI;DSTSf>ZT^^W=i->4H1oqNn_#xA~%P;G$p3;;ZUK|H;L`(?vAj z5>|dG#C$0%a0y3ES&FD$ikw`EI$gr^Eyu_&e=uK;3tWy*S^iwToHV(da=J|5TS=E+ z$uwWd4qVAiS;?(Z?#Z<^_Tf-N#JT}%4&J_YUSi=_30{+Z>>&#t-*Y) zDR8YNWv#7xtz&Yn>vWC8x85ti-fzA>7`Q&1vOZe9K0diVdAd&K+nABxm^0s42;5jo z*;uLGSex9~INhM|ZEnkN?wW7z2W}pwZ2qm@Jf7S3NGQ$Pw7umuGYM1iJK=xZp9 zQxs+@19PGO79Vv8eaiz{`DyJm}bYKxD$CBVNeq_8bwv3)6MTP$_^O3k+T)V2h5 z8_B;TMOE0jVX<>7Xh$Y>N493?-qemfbw`nZS6N|K)nZpYXje0JSG#6ccWPIUx~tE> zXP~fWXt8G;v}cmK_q1lubZXC>x`*Q5w^G=*vDmi@+IL9ZcdFTUp4xY%?z{6Jcq$xt zTO9ZX9r&dlysA0ypE?Mn9-#RTu?mMF7KdR$hq%L5slzDhA)fzFjKZG}7JuS` z{=}#L`CRiSY3ff3^$&snZ@R+YOpCwSL4R{o|K`{H{W|scJN0h?|52gB(JzamlAxo~ z)T8p6qspnHYU&Y@|F}-!xWVGMDd@N*^|-C(xMS+Li+W7rKj~FC>9;r;3_2N3JsGVz z8NWVta&``o`A=sQPUkF67lKZgQcqWEPS>VRH>jr+e(JUYb=QKrA4EM&rHb;w|LIVH zEr6c?yF(2>1BI>s2^9Y02xo|JMhX8BgnuaEA3^vB5jOr2gntp?Uq1L(4R-$H1!r(@ zh6PK@lrt$fV}dgy_>T_EFRsrotk2J{%`I-s&9BYOtuk9EkwhS~jcQrJ25F0vb>spAlEj7gE8e&s5vFWUP zudJ#sEhqjitu864{8ds}^sDTwdq3;j&&u|*j{Qqf%~`en?MLyKFF&($zGY^8NlVW; ztJcp-_1LV+hAf} zgwU_=I!F@>Ei0);_B|=;_mF?;q2o6{A_i0d+zN1{GZj; z>1^Ye{*@m-&<8yl_S35^nI|mng2Pazx7d!jsHulc8 zwhlIDv9Y(Yv9q>wwzhk2WqTGUOIs%^8+(+Ela-aNg|(x(m7|t3{;b2dK-rjDIy^(! zKSkM_TUb7`uz6;RdSYSs#N5ur+}6a*_OYq8(KDN;Pt6`bH8*@}{phLnS?&Mm3Chs; z*@MTHdd8@Sh9>uoEOZSmbPUb44a_tjnrc5VR(tSFP4B6y-cuF5ry9DCly#q|Yu#7W zF_F_UzNcxVqNXjYVR%Q~@Ro{!w35D@g6f@nic*UDx9-SYm)E-{cmLYG`&VUkuE^?$ z$!LqpXkEIkC3!b7B=14T$wYVg!Hi`8{bhR})rAogL5owzrL+LO z^bA4-%m9{-S0A;zXeV`LI8;+Re>vOe%HzDOAl7ZMoXof@HW$xhW#f~wOIEJD^UJ5w zn+SfYbXxr;YF?Q8H4vr@`%Z*>5xkhX?Zo*_*-5!mItIGB7GKWY{z>2sTfX3>VY|0l zMZ;Bn4;1DOo7;Y$6wHuIr#>Hvm(M%NY6&%J^Kc3lyZSMd9qt!J-8v zt#3-XbNV7>(v(vWf6q#?tV~f<>zYCA5pyp~b)|RxAIpj8K~mQJ;uu$ZvD*{e@>Gyk zgL!wNR`|VxM4kSxM|#K2 zmQ0}uk%VVb6QWUlp2=fzfZ0D1!#|bp+-&(EWp=sPM8y>u71XMIZQeie!CL?POvlYW z=3;+Ne4+<09K1xRHAp} zdsQBgu&jN@C-`kJy$TyrVq1wkTpe1wloV|G9nB2B2u;4q;c>xE_>R$C8^D@$ke@e*4hpR->e|^@ohgD53Vwl-gP$=r~oDi#Y++}mNpZpW}sPjh{=F5Q$ zJWDOZw+p=(SnS04vgd4?dehX;El62U$8m9|?Iy!?P^FsnGwD%H;WnS(Yfk z$$UHEN5F@SxH)Y2Wl7d(h^H`b#xaLvsu!aRZxR0#DeRV^29ryN=Ns-&y=!{8QO>2Y zrbD1YZ<8&( zKzuOwTrNT0FdP?Qej|hDquo&c2!|39lz8`%fRE{)Z;cq~SW+#7aX@o0kTP?JTjZ1M za0xVVKlshguTh;T%WwAhb_<*sZCN&JvODqoUB*?7JN?U0=zefPH%$0;x>t{;vb|g1 z&oOWAzt^l4bIyNp9`Z6Cty}ai;#UdKy9IuQ&@jYvlb$r_3{3aAQM2Hzp>OBCuu9); zDBdPzgP)22opaGx)?W~o7)Z(==sZAzpujI_eIaN zM(4K9*b!m_ex_N z%;4z}Ez9VI#2r1A}%tNnL6OMTg0#_3?7d(Brd?S~4cb;`!PO{JH z>!g$)cAu0!d)lg|u3CA6kCZSUHS4dl3_a`{*m_<)m-g;zG@R9GolcHm-5%-lXXwYT zb=%hQH2vewUMFDUW!Fl_6>sTcLKMnd-s9ne4Y$gc_%11rNL){rRn~=!J+Byz_C-AR z82BXabJ~uz*3N!UU!I@B=@TPg;b$Y=(-6iy>lSE58Gj#DT~(F+H0im${e{AfZ`?JA z4G&=~>vFYQi&x;PkItw{w%_f_9-)axq}PevWnxA<-?Wzet+*HA?%n-2&5P7E#!liV zmoz7$ef?&+yGb(b*SlD>k`5P(ggL9zibew|^`&##VQnq8ZPprt9pfUOSf+Ja9TXnQ zUj1E?^ShqGO~mNEPLy6}>wPVInbWNlucm^EKZk9P>bH1*SA^+3Tu$pdWK|!!(ff09 zzG!7kwsQEgO*6w{#X&va8|wD&UzNBQg-NW{H^Qi+m6loB&Dqyf8bnQG5Mc}*i(Yr# z3$rq|e$!V^i#~Ws&Y0ca@UG+DycbyeZ9l0|A?Mw%7v zP1zRWr~CxwWHSnuGac_vTO?y1Nc_sS8RGD=@dh`YcDJPa3DFaWzcmX`3XJpBg4`h~ zG0dfF?EoIUj-zK6LBBV4>v@0cSYJ0?QKFR{(W)qsddUU-*rorr-{3>~gCULSL6$$i z19Xd=XN)!5gddPR7+TPbwKwVK($R60;AZ?~&tPx3Cw*5|pq&FH5`)U&Flm~h6hm#?}zZ$MF zs!0Ip5H5R6X~9sJAr?>S zjNlw%Vcypaz(M2Ob={W2c{y-!DOh%ak)904_B1Sk!}y*C%bZ3~wwlB~lDQwwEUN0m zrNY9QdrMkFs#rr}3(mYEphk~_n&y~{y*GIjY)?AijdXu_Okj?p)#;V=2WBwi!=PW) zC3f+l-GbV{Smth-h<7;8tMTY=I*(pK*k-2W2%afw{#inNFbU&&jAv%zLf(_1PrJ!7 z>(0EFYdZ;5A(slKkzt_i2wO{NLIM5feeFd+c&V6Ebf#)(sb0}1$-hM0E$HoTjL%^& zGaeUy;{L2^h-E44`Zgdurr_P-xj-Bh^_WV7h((1HFX>f>NPgrB*vv)8m>}BpUC%WJ zA31ongh?JFJ#a)rHC5)PhtE8J34X!Dd_~^dC_z6^=y`j?ly;cM-EIBDANDFS$(OM# zD+bP9Wc*$5Zdu=S2CUg*$=JQbl#y-OD`=vX9WhWV@g2a}?Z^E4totXwJ&a))(brYA zW~v`%@!I9hBQx!B$rh2^PT(voVy4w}i28VgYlkKy@9CEX)V2X0A(s&~5Kj?rrotwc zX`)Au5<}8u7XA_Qm<#v0x9LCN1I8Il37 zg=oI1HoFBY(`VqmjEExAA5cHhV=p7(NU*8PPRZ`cnVJklJVQsT0Md_P?K0n6JpJs; zkNuXgVgTc00%9>Cg<%GkLxR@bNqXjSpTkkqqg5cvHnIC$TJKMK0yzRo&k?E*`=Os= z-Ag##Vw^%I+!sv~dFAy(A9l+t&ElaqgSIH&D1Z1T=dCB{-G%f^Iq6ocZ-1ghzt2m% z&GFZ(F@v--YR@si|Cq`+v4<+czL4luW#ixOXR40Ue^G>8{+wy%alf2$)nGKsTpL!d zpQag+W%M)iOF@SD=WJDO2BTM5Hf`+vGq3_uy3^B~xj3ZP9W8hK+^n!p~V@im+?}h8pCRvR7X% z4PZ3_4B3jXPk+DM;r?1L%eWr?b+An&2g%s6@->tGo3S829!~#*@NMYncP$}?dJ6r< z{?|$Rx1mV0B<*htvOjLdd`qLZUhnzt@SZopoqkD{aYy|J=($ifl5zAEeFBm1FSlDQ zH~l-O0zKJ+a}0vtPz4{j>APML7!osDJzz8W4E6eqH3jt1vOh2B@I@BT*XT3W!}HVJ zVQW3#cyyA&NKiiN7=42*V+X15hdX^D5_a)*p)wC55(!Imr{5|sY9FP)J_ZdV{FHvq z5rTq7>chYhIpq`v!DnZ8DKjI3$)hRg^f7mAD?2xbyt>y!+dG zwYZU3SVPXgwF3J{gr1p$7lwD|AuI__pHo2p17BJozz{iB8g*2P=P8T1TlV2uS={Tg z_{6f$6=g|dWhqBx1fKHrtK|jw(jTadG$QOHT;LCV=~;~)ih{l&-~Q+hODKSqCRUVJ zR8)>tR3B9kc`EDfRyI7VYzNzh=+aBhgrr#!vuJxR?GjX(OE0P zC{<)CPxZ{*>bYmt3$Lq}6027#s@KMQYj&U2>>pK~)##%YHOFKB1w$~c znl>8yH<~0hKCNst9d9&0Zv3wpf?rbetIB5o@#eteW;AaL_FhYf zX-k;@f5i}vTM4{v>Ho(N{*NL2Z(|5TU+G*GAt?A67t&lN0AWY~!2Q2$2ruLTFaq#0 zfkq8Zi&BKR66m-X>1_0AmC3-E|Cb>IZvd6`X>9;>tR0XiNbq^U|HBZn<$)@ATIT|y z8vvrL_&*!Mk}?3|rcVq+L-a_%f&a@8zAqujUH(F%wz{J$Flr3?HVS>)|bJK06~k0De|0v{{V{f&Sqq5r!fMDl?h0N-A^ z(^lyHYY3a$=iO;vQuXtl-ND!YH3aq`aBEkN4T?tgUqje&r2#+4wp3hE{nrqBH-MJ- z%-48Y2zmD(L+DRu(KIed>sM&- z=QBfa+tPI3ALu{GI5Px(3fAJj0}A-%%n+_`awz`6c+qvr|6>T#65tp5in-lKXNEwU z{Cm3yBBc0_ArK`%EJ4zG#N#tV_`U(Y9Skvg@Q)$HP+b8f-B$xqJL6}DP_v{#*l5B+ z=FbelVrlBf6~ff%nIXK60yh;xMjlZAUZ+AR$N56E0H7jS5lhQ-HhHW+tsKULkPqQ{ zIHMZDe$Big{^6{86hbc0TkIl9Gv?y`6x9TSdF{AsX4N4V9xZglyKAEx5*{t;rN{-G zg1HTs^l=x-B-PJ`%Ldu^lT#Q~3|9>EjlP*Tel~jEfP7FDNXujVwN2<*XNp>)@%qye zmA8?hJdZcVKf3b%YD|2*Xio97C=J2zd-sF+qrER{ z3VpIEloWm+B6aa%VrHRsRZ66kPE7W%LY?cKbq4L?WygiO(pmJ6bj4cl72Uu6Lietg09&qo~ zzAd+7pex+};nBm2-Q7MK6~s-WOFB1;6%36+eKd@pC2tOxxP^KcKkX}Ge{7-9?=!Ud z>ZI6&E|}d{*6N+DucA$?n(K&NPUGeihj+1YPhG}}_D3fQCvJ_em+x`ha&J@{y5rgI zvp()U#qMh6tK`LL{@Nw>g?Zab)$ghP?SaQqfhQN^rO`AJ&SWfS^%^RK?oqtu8+NZl z%W|O<8SCmRB_s@{s!LkQHMt>l8)(?8|*QH>>HdQ2v*c<(02BaSqSFTW@na z7xA2Xz4ob1zQQG>*SO+h$wc;RfznxX$BpvkY96=C2axfc>JxdbO=2fs5+#OF;dr%y zo&U{N)6YO&&sNdsa?i%=&8Ci>u*J%qG=+n^-aRibA>8_49{^!}TcO8A17BnXf*G0h zTYRA%=ju{}mWcUW{>0iJO#T#)ldo{)0zz5;Y)W#ze zYf63aU*4{5%q!od=m3j_>>u)J9J!Ah#joUwLcUO%sZiL9amxov{S*Zefoy-OOsb*m zmclr@NC4G@-zz1jWa&O_;Nabs!=9Nr-X2;Hqh`L&L}zQhYD$;gy39Qc0Wp0_%R${`KylAJrfT; zB)nD96jl--W5o5NneD%#6~)OwS^et__91CXPGs;^Hp~N){&d<*H25052v8vx%K|~Z zzge;+K&MM)%-3%U%|ydKu8Anu$*3E1WYX{rL-sV?n;z1u1~41#g459E5&I7Pq@USSv-=ls?xNbC_A2WNVKFw z?5k6Fv`WL}?x6T0fm~kH0Yxd?oFfFnBY1T5&hEZt*fqVIwzN9YO9F=89NYE8LP}M5T2?e^4sZ`}s>LIXgO2=CWfWYe> zq#6L~1tdn(att2i(^%%;z$=18@$6VDIUH?ES-3bfjUIl|e7$^BE@-Ki-k3ylXF?W# z)AR<55dnk{UkSr>pkPh}bCI|LFh5ikszX^*=tr7|fe5gPx2jy9Nns%z!gv5)^imVf zc%>{2W~jNTu<{Z=zESdf^Umjg<Cp}9j)2vfx0 zIeH?n+^DK$k9v58GocNj>8aG;+Kn+(Z29ob+0>ku?a*;ARYu+Q<({sb0r(I9IxmhV zS0fC|DBypHf*QIp0BH1C__GI~k3_5BnJetS`)O!m^6Zx}gy}X{=Jcd+P5jYG1{YCo zN5SE6F$j+q&?QXD(knw&(kulV&5?zypkeF{-(Z@bfW7fr2LQ@)sOiHW(8~A7rpz9)ClxLrS zB^|rI z@zPKZBIf*Ykr*#7SsDi?0(k|Bqx%Z@u42xasQX$MhP2#8sR`8qi_RYK3IN%J zRaCcit`E`#?v$$Kw5p{Jt6_5$F?jVCE%H=h{Zs*Abqo}{@e+iE0!zwovavz0>Ps5D zt*zIDrq=Tvdg}9EaN>wN{k0jQcf!V6+~Q-yl}Ks8=&;R}bOg%0HwKNLi08v1Xa-t7HBYo(jXK;ji1>x zq{DAIfFuiO?Xa!b!@?jOSP~u#&>`|xvz&S0oGHa`sbHtjVSElw7*Q*I4`f|NUQ zIx2Lr!>M~V*l9m|=s? z^5VF~#O*$7VJHvmoVu|Ens!g`YY6{BZFg<*Mtyyi9$fJI=~XBTktS*slFV4hE{y{! z2AB8UmJ+*j6C{cyVl42YL5H*ohEPtj!paCOKU{l57wVqd4ul8C)#VBz6a~KN+yqEq z1c0~5(tNZ4e%yB|_6qdMq2%hTS_SDxYk%m(d2k02)nPLKOkHA8`A@l_qGOQYL!iN- zr~#_l{OF;bC!L@i^fHnZWO84GlI-KBPc~`EaBL~jM03kv1)$0iTmTLvR)_+Ka>oce zVBW}}1q47ZFc@Jn=13L?Gyw`DK^)LNb7A1wLH=NLz?2CiCB&1C+RwTH2yD+_()6I~`X{%K3GVEVUkeU>lpOL3_~d;t z!N>Nox5rQvX2_4})63%cSH+KAYKOvmh60k~0@dP!Xie-`htYz=*lTgY1D`^SOe`#i zUwRBv!>c~xY(KrpGBNo%>{&Y;dH>_Py|}17lZU{O=d2^|CqBf4#>J{V(SA5$V>uG% z^5GMET>Qr;DrqBTKSvTzVw18yCeM$^Z;coOM+wCrID8&vBqyca{FrX^^tR>b1CP<1 zb+$~Vw|QBkQg5E>){cJNi~08M!}qHvaGT4 z;<1Y4XEd76aK)ogLv|WG0P2nglb#_Sj)C0)P&|5EWTg5eqDbx?1c!zYjfE}%T0a_n z@-a;w`2a)%pisbV7`pqLslw%FN|^BuE&!~>^tR*KA3rBDCdLUKY*0V6%1eMmRczlt zEVbW-k@#-n_7k%v_R*273FU`?iIekCeL&L9$!v;QBN}bx@&T+rnIABjg)?u+12L&x=9-|r+b7e3Bg3?O&vvHt=8b;YTXkxK&v`9RN zkt^bHlx@cn03K&`OD{(1$pk}ggvJIIBL-j_1}PG(Efg{5%K*azPt7D|u3w(6aJNA+ zFJQ%h){t2l0Vp#8$gOD?%!LslgD&DRNHvVB-3)LTb4?%X#sOu6FN)yjv1B_pdE7q} zw0cngON%NCFgnF)JKu#{VRrBWdXzl$f{g7Y4(R=jVC*o4s(`k!h{s}cX^^*qMPzIp zkij4VS{gkkEd~t_b9nRJI^q@%cQ$BSLJz0R2?FPDUXBHqzOl%*3n77I2eBA|WlTKQ z2x9%75BD}KOlH`@DJt0L77cdE5p(EB;Bd-;I62@}^3duSzNMN!F%TpsxOzF50F;ed z$%X)&A>eBO?6m?KSzr5f$gC_fI5TWcMvSHmGD}N#Lvjmcb zU@ODIsvzi2j=8Q=XAIiKfy)L!aYpj3Q}bkiP>TJ9H;y76&RTH@$K)S>C$X$F1Q zMF`f~#?bVpIgAOQ{SuUsR+@Q#wQsA68_MBOcnh3Ud^i%5Vjt93qggM=@T-!q75H>orn1$_?PZ8|7 zTi0v1_%Cean@p_T-8d(Tqb5PDpHdI10u(8pl$tIH7doyVS13R?od zeN2b;biVIB>-ND8`{c)?CvWYsEpN+Rj)e$d)_8Yha{w0(LC#@e=I&eB8}1gRF7(j3 z_KiIq>Ym!r?%f<80QA7)`T^%}Yrj;VbSUtgzO&F9U!I3P`I-P0_)Z#r`;ECvw(-tT z_N+NB_?j4vtA-cVf**JBIu7M_Fly`<_QG#e?=aNOPgdP49R*}Tq5?Gb8ZXBRb2Ra# zI>~GL21k2i;Cn_A!P4>vtPc)!bNuu~aq-b}3H;EMaGTWBhzlh2C-u3QshHT`Xif*8 zk3Xyx3xcJ^4z(fH@?uZ{_veP+gY$lSJ1n_jp*9lnhxdnUzKBA(@IRUf1cO|5Bw94qQCUWfzqAxkR!gzeKr8`n z8lN;q2T;=iQ*3^9jy)JQ^we0*v2@uu3kmZ*h2uO4*!JM~5r3d?37YK?==2A}hC90T z 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 diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen.gif b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen.gif index 71f2d5846d22a3b5aa875843edd846de1a79f404..b193c95de616ba45745922f3d7827a095a8b71d1 100644 GIT binary patch literal 50647 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Νq@Wi%(29GLxG^%SnKZZynu@04 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%0ADje67(79Gy|Ts)c^|Mum9kw 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 B?q&c0 diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_bottom_sheet.py b/sdk/python/packages/flet/integration_tests/examples/material/test_bottom_sheet.py index b2dd3fc901..b73be06496 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_bottom_sheet.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_bottom_sheet.py @@ -1,8 +1,9 @@ import pytest +import examples.controls.bottom_sheet.basic.main as basic +import examples.controls.bottom_sheet.fullscreen.main as fullscreen import flet as ft import flet.testing as ftt -from examples.controls.bottom_sheet import basic, fullscreen @pytest.mark.asyncio(loop_scope="function") From 89decb7475deaed065dc7b6dbf7573eba6ccd987 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 08:48:34 -0700 Subject: [PATCH 25/96] Move SafeArea from sheet content to page controls Remove SafeArea wrapper from BottomSheet content and simplify sheet to use a Container with padded Column. Add a SafeArea around the page controls (Display button + Fullscreen switch) instead. Update golden assets (GIF/PNGs) for macOS bottom_sheet fullscreen to reflect the visual/layout changes. --- .../controls/bottom_sheet/fullscreen/main.py | 47 +++++++++--------- .../golden/macos/bottom_sheet/fullscreen.gif | Bin 50647 -> 50998 bytes .../macos/bottom_sheet/fullscreen_1.png | Bin 18787 -> 18974 bytes .../macos/bottom_sheet/fullscreen_2.png | Bin 21301 -> 21417 bytes .../macos/bottom_sheet/fullscreen_3.png | Bin 18787 -> 18974 bytes .../macos/bottom_sheet/fullscreen_4.png | Bin 19308 -> 19481 bytes .../macos/bottom_sheet/fullscreen_5.png | Bin 35668 -> 35871 bytes 7 files changed, 23 insertions(+), 24 deletions(-) diff --git a/sdk/python/examples/controls/bottom_sheet/fullscreen/main.py b/sdk/python/examples/controls/bottom_sheet/fullscreen/main.py index 604fd90a8c..c83d974ad3 100644 --- a/sdk/python/examples/controls/bottom_sheet/fullscreen/main.py +++ b/sdk/python/examples/controls/bottom_sheet/fullscreen/main.py @@ -10,35 +10,34 @@ def handle_switch_change(e: ft.Event[ft.Switch]): sheet = ft.BottomSheet( fullscreen=True, show_drag_handle=True, - content=ft.SafeArea( - avoid_intrusions_left=False, - avoid_intrusions_top=False, - avoid_intrusions_right=False, - avoid_intrusions_bottom=False, - content=ft.Container( - padding=ft.Padding.all(10), - content=ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text("This is bottom sheet's content!"), - ft.Button( - "Close bottom sheet", on_click=lambda: page.pop_dialog() - ), - ], - ), + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("This is bottom sheet's content!"), + ft.Button("Close bottom sheet", on_click=lambda: page.pop_dialog()), + ], ), ), ) page.add( - ft.Button( - content="Display bottom sheet", - on_click=lambda e: page.show_dialog(sheet), - ), - ft.Switch( - value=True, - label="Fullscreen", - on_change=handle_switch_change, + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Button( + content="Display bottom sheet", + on_click=lambda e: page.show_dialog(sheet), + ), + ft.Switch( + value=True, + label="Fullscreen", + on_change=handle_switch_change, + ), + ], + ) ), ) diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen.gif b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen.gif index b193c95de616ba45745922f3d7827a095a8b71d1..680d23ffd0dbbfb22872bfcad3ccb1a707eafeb1 100644 GIT binary patch delta 45398 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%0ATxm)iCf?B?bLVJ+ks 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 GI{yQ1xz7jy diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_1.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_1.png index 1467fb94a6b9651fe1a0f71f62ea8f4c524918f2..791f772ff7ad4489443a8ccbca4560aaa1b3b1d9 100644 GIT binary patch literal 18974 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 FzW|%tx&Z(H diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_2.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_2.png index 592c628759c756878a78f7f028ddf21f951bbf7e..fa3b3b0df8ae3782ecd6037a60a46376b7e4f3b5 100644 GIT binary patch literal 21417 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 RBLQTG$Vw?m7Ks~w`d@QNdvyQ+ literal 21301 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 diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_3.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_3.png index 1467fb94a6b9651fe1a0f71f62ea8f4c524918f2..791f772ff7ad4489443a8ccbca4560aaa1b3b1d9 100644 GIT binary patch literal 18974 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 FzW|%tx&Z(H diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_4.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_4.png index 46c5ca0be329d9f18846bb548bace292e0e031c2..6a065ee4cbaf265728b6e8381631dbe62cf2517a 100644 GIT binary patch literal 19481 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 z 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 YoKD-!fZ+8<$HYMOsfJRq!mD@x3oaW%R{#J2 diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_5.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/bottom_sheet/fullscreen_5.png index 5c502af9c67c0aa96b74417bcffb8a7a13b12d3d..a6984865685d8f71a9664b4bf4d85a7bce868eb6 100644 GIT binary patch literal 35871 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 @kmX7^|gtz_D&RXkCZ0xbS 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 From 30fde8e5fa6cb39218d9d9afe26f17737dcc7a8b Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 09:10:30 -0700 Subject: [PATCH 26/96] Organize button examples into per-example packages Move button example scripts into per-example directories (each with main.py and pyproject.toml), remove the old top-level example .py files, and wrap example UI content in SafeArea/Column. Update docs to reference the new example paths (e.g. examples/*/main.py) and adjust integration test imports to import the new modules. Adds metadata for gallery packaging and keeps example behavior unchanged. --- .../examples/controls/button/__init__.py | 0 .../controls/button/animate_on_hover.py | 22 ------- .../controls/button/animate_on_hover/main.py | 31 ++++++++++ .../button/animate_on_hover/pyproject.toml | 26 +++++++++ sdk/python/examples/controls/button/basic.py | 12 ---- .../examples/controls/button/basic/main.py | 18 ++++++ .../controls/button/basic/pyproject.toml | 26 +++++++++ .../examples/controls/button/button_shapes.py | 33 ----------- .../controls/button/button_shapes/main.py | 45 +++++++++++++++ .../button/button_shapes/pyproject.toml | 26 +++++++++ .../controls/button/custom_content.py | 34 ----------- .../controls/button/custom_content/main.py | 40 +++++++++++++ .../button/custom_content/pyproject.toml | 26 +++++++++ .../controls/button/handling_clicks.py | 21 ------- .../controls/button/handling_clicks/main.py | 26 +++++++++ .../button/handling_clicks/pyproject.toml | 26 +++++++++ sdk/python/examples/controls/button/icons.py | 16 ------ .../examples/controls/button/icons/main.py | 22 +++++++ .../controls/button/icons/pyproject.toml | 26 +++++++++ .../examples/controls/button/styling.py | 41 ------------- .../examples/controls/button/styling/main.py | 57 +++++++++++++++++++ .../controls/button/styling/pyproject.toml | 26 +++++++++ .../packages/flet/docs/controls/button.md | 14 ++--- .../examples/material/test_button.py | 16 +++--- 24 files changed, 435 insertions(+), 195 deletions(-) delete mode 100644 sdk/python/examples/controls/button/__init__.py delete mode 100644 sdk/python/examples/controls/button/animate_on_hover.py create mode 100644 sdk/python/examples/controls/button/animate_on_hover/main.py create mode 100644 sdk/python/examples/controls/button/animate_on_hover/pyproject.toml delete mode 100644 sdk/python/examples/controls/button/basic.py create mode 100644 sdk/python/examples/controls/button/basic/main.py create mode 100644 sdk/python/examples/controls/button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/button/button_shapes.py create mode 100644 sdk/python/examples/controls/button/button_shapes/main.py create mode 100644 sdk/python/examples/controls/button/button_shapes/pyproject.toml delete mode 100644 sdk/python/examples/controls/button/custom_content.py create mode 100644 sdk/python/examples/controls/button/custom_content/main.py create mode 100644 sdk/python/examples/controls/button/custom_content/pyproject.toml delete mode 100644 sdk/python/examples/controls/button/handling_clicks.py create mode 100644 sdk/python/examples/controls/button/handling_clicks/main.py create mode 100644 sdk/python/examples/controls/button/handling_clicks/pyproject.toml delete mode 100644 sdk/python/examples/controls/button/icons.py create mode 100644 sdk/python/examples/controls/button/icons/main.py create mode 100644 sdk/python/examples/controls/button/icons/pyproject.toml delete mode 100644 sdk/python/examples/controls/button/styling.py create mode 100644 sdk/python/examples/controls/button/styling/main.py create mode 100644 sdk/python/examples/controls/button/styling/pyproject.toml diff --git a/sdk/python/examples/controls/button/__init__.py b/sdk/python/examples/controls/button/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/button/animate_on_hover.py b/sdk/python/examples/controls/button/animate_on_hover.py deleted file mode 100644 index dd6b538fc8..0000000000 --- a/sdk/python/examples/controls/button/animate_on_hover.py +++ /dev/null @@ -1,22 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate(e: ft.Event[ft.Button]): - e.control.rotate = 0.1 if e.data else 0 - page.update() - - page.add( - ft.Button( - content="Hover over me, I'm animated!", - rotate=0, - animate_rotation=100, - on_hover=animate, - on_click=lambda e: page.add(ft.Text("Clicked! Try a long press!")), - on_long_press=lambda e: page.add(ft.Text("I knew you could do it!")), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/button/animate_on_hover/main.py b/sdk/python/examples/controls/button/animate_on_hover/main.py new file mode 100644 index 0000000000..48bee832f6 --- /dev/null +++ b/sdk/python/examples/controls/button/animate_on_hover/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + e.control.rotate = 0.1 if e.data else 0 + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Hover over me, I'm animated!", + rotate=0, + animate_rotation=100, + on_hover=animate, + on_click=lambda e: page.add( + ft.Text("Clicked! Try a long press!") + ), + on_long_press=lambda e: page.add( + ft.Text("I knew you could do it!") + ), + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/button/animate_on_hover/pyproject.toml b/sdk/python/examples/controls/button/animate_on_hover/pyproject.toml new file mode 100644 index 0000000000..4fdd92ca6a --- /dev/null +++ b/sdk/python/examples/controls/button/animate_on_hover/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-animate-on-hover" +version = "1.0.0" +description = "Animated button rotation on hover with click and long-press actions." +requires-python = ">=3.10" +keywords = ["button", "hover", "animation", "click", "long press"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Animate on hover" +controls = ["SafeArea", "Column", "Button", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["hover animation", "click handling", "long press handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/button/basic.py b/sdk/python/examples/controls/button/basic.py deleted file mode 100644 index 4a5d689e66..0000000000 --- a/sdk/python/examples/controls/button/basic.py +++ /dev/null @@ -1,12 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Button(content="Enabled button"), - ft.Button(content="Disabled button", disabled=True), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/button/basic/main.py b/sdk/python/examples/controls/button/basic/main.py new file mode 100644 index 0000000000..5ed3eb5012 --- /dev/null +++ b/sdk/python/examples/controls/button/basic/main.py @@ -0,0 +1,18 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button(content="Enabled button"), + ft.Button(content="Disabled button", disabled=True), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/button/basic/pyproject.toml b/sdk/python/examples/controls/button/basic/pyproject.toml new file mode 100644 index 0000000000..5f2ab8d7a5 --- /dev/null +++ b/sdk/python/examples/controls/button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-basic" +version = "1.0.0" +description = "Basic enabled and disabled Button examples." +requires-python = ">=3.10" +keywords = ["button", "material", "basic", "disabled"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Basic button" +controls = ["SafeArea", "Column", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["enabled and disabled states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/button/button_shapes.py b/sdk/python/examples/controls/button/button_shapes.py deleted file mode 100644 index 76a0d4afa0..0000000000 --- a/sdk/python/examples/controls/button/button_shapes.py +++ /dev/null @@ -1,33 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.padding = 30 - page.spacing = 30 - - page.add( - ft.Button( - content="Stadium", - style=ft.ButtonStyle(shape=ft.StadiumBorder()), - ), - ft.Button( - content="Rounded rectangle", - style=ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=10)), - ), - ft.Button( - content="Continuous rectangle", - style=ft.ButtonStyle(shape=ft.ContinuousRectangleBorder(radius=30)), - ), - ft.Button( - content="Beveled rectangle", - style=ft.ButtonStyle(shape=ft.BeveledRectangleBorder(radius=10)), - ), - ft.Button( - content="Circle", - style=ft.ButtonStyle(shape=ft.CircleBorder(), padding=30), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/button/button_shapes/main.py b/sdk/python/examples/controls/button/button_shapes/main.py new file mode 100644 index 0000000000..b8535d9b0b --- /dev/null +++ b/sdk/python/examples/controls/button/button_shapes/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + page.padding = 30 + page.spacing = 30 + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Stadium", + style=ft.ButtonStyle(shape=ft.StadiumBorder()), + ), + ft.Button( + content="Rounded rectangle", + style=ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=10) + ), + ), + ft.Button( + content="Continuous rectangle", + style=ft.ButtonStyle( + shape=ft.ContinuousRectangleBorder(radius=30) + ), + ), + ft.Button( + content="Beveled rectangle", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=10) + ), + ), + ft.Button( + content="Circle", + style=ft.ButtonStyle(shape=ft.CircleBorder(), padding=30), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/button/button_shapes/pyproject.toml b/sdk/python/examples/controls/button/button_shapes/pyproject.toml new file mode 100644 index 0000000000..7341199ad7 --- /dev/null +++ b/sdk/python/examples/controls/button/button_shapes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-shapes" +version = "1.0.0" +description = "Button examples demonstrating different shape styles." +requires-python = ">=3.10" +keywords = ["button", "shape", "styling", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Button shapes" +controls = ["SafeArea", "Column", "Button", "ButtonStyle"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["shape styling", "multiple border types"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/button/custom_content.py b/sdk/python/examples/controls/button/custom_content.py deleted file mode 100644 index cb844ff47b..0000000000 --- a/sdk/python/examples/controls/button/custom_content.py +++ /dev/null @@ -1,34 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Button( - width=150, - content=ft.Row( - alignment=ft.MainAxisAlignment.SPACE_AROUND, - controls=[ - ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), - ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), - ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), - ], - ), - ), - ft.Button( - content=ft.Container( - padding=ft.Padding.all(10), - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - spacing=5, - controls=[ - ft.Text(value="Compound button", size=20), - ft.Text(value="This is secondary text"), - ], - ), - ), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/button/custom_content/main.py b/sdk/python/examples/controls/button/custom_content/main.py new file mode 100644 index 0000000000..d55ef98eba --- /dev/null +++ b/sdk/python/examples/controls/button/custom_content/main.py @@ -0,0 +1,40 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + width=150, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), + ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), + ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), + ], + ), + ), + ft.Button( + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + spacing=5, + controls=[ + ft.Text(value="Compound button", size=20), + ft.Text(value="This is secondary text"), + ], + ), + ), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/button/custom_content/pyproject.toml b/sdk/python/examples/controls/button/custom_content/pyproject.toml new file mode 100644 index 0000000000..e35326baaa --- /dev/null +++ b/sdk/python/examples/controls/button/custom_content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-custom-content" +version = "1.0.0" +description = "Buttons with custom row and column content." +requires-python = ">=3.10" +keywords = ["button", "custom content", "layout", "icons", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Custom content" +controls = ["SafeArea", "Column", "Button", "Row", "Container", "Icon", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom button content", "compound button layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/button/handling_clicks.py b/sdk/python/examples/controls/button/handling_clicks.py deleted file mode 100644 index 3a7b2ffb0e..0000000000 --- a/sdk/python/examples/controls/button/handling_clicks.py +++ /dev/null @@ -1,21 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def button_clicked(e: ft.Event[ft.Button]): - button.data += 1 - message.value = f"Button clicked {button.data} time(s)" - page.update() - - page.add( - button := ft.Button( - content="Button with 'click' event", - data=0, - on_click=button_clicked, - ), - message := ft.Text(), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/button/handling_clicks/main.py b/sdk/python/examples/controls/button/handling_clicks/main.py new file mode 100644 index 0000000000..74c18fd0fb --- /dev/null +++ b/sdk/python/examples/controls/button/handling_clicks/main.py @@ -0,0 +1,26 @@ +import flet as ft + + +def main(page: ft.Page): + def button_clicked(e: ft.Event[ft.Button]): + button.data += 1 + message.value = f"Button clicked {button.data} time(s)" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + button := ft.Button( + content="Button with 'click' event", + data=0, + on_click=button_clicked, + ), + message := ft.Text(), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..cd5400a91e --- /dev/null +++ b/sdk/python/examples/controls/button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-handling-clicks" +version = "1.0.0" +description = "Button click handling with a live click counter." +requires-python = ">=3.10" +keywords = ["button", "events", "on_click", "counter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "Button", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["click event handling", "dynamic label updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/button/icons.py b/sdk/python/examples/controls/button/icons.py deleted file mode 100644 index abdf66e0ac..0000000000 --- a/sdk/python/examples/controls/button/icons.py +++ /dev/null @@ -1,16 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Button(content="Button with icon", icon=ft.Icons.WAVES_ROUNDED), - ft.Button( - content="Button with colorful icon", - icon=ft.Icons.PARK_ROUNDED, - icon_color=ft.Colors.GREEN_400, - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/button/icons/main.py b/sdk/python/examples/controls/button/icons/main.py new file mode 100644 index 0000000000..0476f6b5ac --- /dev/null +++ b/sdk/python/examples/controls/button/icons/main.py @@ -0,0 +1,22 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button(content="Button with icon", icon=ft.Icons.WAVES_ROUNDED), + ft.Button( + content="Button with colorful icon", + icon=ft.Icons.PARK_ROUNDED, + icon_color=ft.Colors.GREEN_400, + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/button/icons/pyproject.toml b/sdk/python/examples/controls/button/icons/pyproject.toml new file mode 100644 index 0000000000..b5d29b90e7 --- /dev/null +++ b/sdk/python/examples/controls/button/icons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-icons" +version = "1.0.0" +description = "Button examples with default and custom icon colors." +requires-python = ">=3.10" +keywords = ["button", "icon", "material", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Buttons with icons" +controls = ["SafeArea", "Column", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["button icons", "custom icon color"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/button/styling.py b/sdk/python/examples/controls/button/styling.py deleted file mode 100644 index 1c629d4951..0000000000 --- a/sdk/python/examples/controls/button/styling.py +++ /dev/null @@ -1,41 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Button( - content="Styled button 1", - style=ft.ButtonStyle( - color={ - ft.ControlState.HOVERED: ft.Colors.WHITE, - ft.ControlState.FOCUSED: ft.Colors.BLUE, - ft.ControlState.DEFAULT: ft.Colors.BLACK, - }, - bgcolor={ - ft.ControlState.FOCUSED: ft.Colors.PINK_200, - ft.ControlState.DEFAULT: ft.Colors.YELLOW, - }, - padding={ft.ControlState.HOVERED: 20}, - overlay_color=ft.Colors.TRANSPARENT, - elevation={ - ft.ControlState.DEFAULT: 0, - ft.ControlState.HOVERED: 5, - ft.ControlState.PRESSED: 10, - }, - animation_duration=500, - side={ - ft.ControlState.DEFAULT: ft.BorderSide(1, color=ft.Colors.BLUE_100), - ft.ControlState.HOVERED: ft.BorderSide(3, color=ft.Colors.BLUE_400), - ft.ControlState.PRESSED: ft.BorderSide(6, color=ft.Colors.BLUE_600), - }, - shape={ - ft.ControlState.HOVERED: ft.RoundedRectangleBorder(radius=20), - ft.ControlState.DEFAULT: ft.RoundedRectangleBorder(radius=2), - }, - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/button/styling/main.py b/sdk/python/examples/controls/button/styling/main.py new file mode 100644 index 0000000000..9af4e73372 --- /dev/null +++ b/sdk/python/examples/controls/button/styling/main.py @@ -0,0 +1,57 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Styled button 1", + style=ft.ButtonStyle( + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + bgcolor={ + ft.ControlState.FOCUSED: ft.Colors.PINK_200, + ft.ControlState.DEFAULT: ft.Colors.YELLOW, + }, + padding={ft.ControlState.HOVERED: 20}, + overlay_color=ft.Colors.TRANSPARENT, + elevation={ + ft.ControlState.DEFAULT: 0, + ft.ControlState.HOVERED: 5, + ft.ControlState.PRESSED: 10, + }, + animation_duration=500, + side={ + ft.ControlState.DEFAULT: ft.BorderSide( + 1, color=ft.Colors.BLUE_100 + ), + ft.ControlState.HOVERED: ft.BorderSide( + 3, color=ft.Colors.BLUE_400 + ), + ft.ControlState.PRESSED: ft.BorderSide( + 6, color=ft.Colors.BLUE_600 + ), + }, + shape={ + ft.ControlState.HOVERED: ft.RoundedRectangleBorder( + radius=20 + ), + ft.ControlState.DEFAULT: ft.RoundedRectangleBorder( + radius=2 + ), + }, + ), + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/button/styling/pyproject.toml b/sdk/python/examples/controls/button/styling/pyproject.toml new file mode 100644 index 0000000000..da5d934598 --- /dev/null +++ b/sdk/python/examples/controls/button/styling/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-styling" +version = "1.0.0" +description = "Button style customization by control states." +requires-python = ">=3.10" +keywords = ["button", "styling", "control state", "animation", "hover"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Button styling" +controls = ["SafeArea", "Column", "Button", "ButtonStyle", "BorderSide"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["state-based styling", "hover effects", "animated style transitions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/button.md b/sdk/python/packages/flet/docs/controls/button.md index 181b9a35e7..a42b40b218 100644 --- a/sdk/python/packages/flet/docs/controls/button.md +++ b/sdk/python/packages/flet/docs/controls/button.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/button ### Button ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="Basic button", width="50%") }} @@ -22,7 +22,7 @@ example_images: ../test-images/examples/material/golden/macos/button ### Icons ```python ---8<-- "{{ examples }}/icons.py" +--8<-- "{{ examples }}/icons/main.py" ``` {{ image(example_images + "/icons.png", alt="Basic button", width="50%") }} @@ -31,7 +31,7 @@ example_images: ../test-images/examples/material/golden/macos/button ### Handling clicks ```python ---8<-- "{{ examples }}/handling_clicks.py" +--8<-- "{{ examples }}/handling_clicks/main.py" ``` {{ image(example_images + "/handling_clicks.png", alt="Handling clicks", width="50%") }} @@ -40,7 +40,7 @@ example_images: ../test-images/examples/material/golden/macos/button ### Custom content ```python ---8<-- "{{ examples }}/custom_content.py" +--8<-- "{{ examples }}/custom_content/main.py" ``` {{ image(example_images + "/custom_content.png", alt="Buttons with custom content", width="50%") }} @@ -49,7 +49,7 @@ example_images: ../test-images/examples/material/golden/macos/button ### Shapes ```python ---8<-- "{{ examples }}/button_shapes.py" +--8<-- "{{ examples }}/button_shapes/main.py" ``` {{ image(example_images + "/button_shapes.png", alt="Buttons with different shapes", width="50%") }} @@ -58,7 +58,7 @@ example_images: ../test-images/examples/material/golden/macos/button ### Styling ```python ---8<-- "{{ examples }}/styling.py" +--8<-- "{{ examples }}/styling/main.py" ``` {{ image(example_images + "/styled_initial.png", alt="Styled button - default state", width="50%", caption="Default state") }} @@ -70,7 +70,7 @@ example_images: ../test-images/examples/material/golden/macos/button ### Animate on hover ```python ---8<-- "{{ examples }}/animate_on_hover.py" +--8<-- "{{ examples }}/animate_on_hover/main.py" ``` {{ image(example_images + "/animate_on_hover_initial.png", alt="Unhovered button", width="50%", caption="Normal button") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_button.py b/sdk/python/packages/flet/integration_tests/examples/material/test_button.py index 5f83cf38c6..9b467211cb 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_button.py @@ -1,16 +1,14 @@ import pytest +import examples.controls.button.animate_on_hover.main as animate_on_hover +import examples.controls.button.basic.main as basic +import examples.controls.button.button_shapes.main as button_shapes +import examples.controls.button.custom_content.main as custom_content +import examples.controls.button.handling_clicks.main as handling_clicks +import examples.controls.button.icons.main as icons +import examples.controls.button.styling.main as styling import flet as ft import flet.testing as ftt -from examples.controls.button import ( - animate_on_hover, - basic, - button_shapes, - custom_content, - handling_clicks, - icons, - styling, -) @pytest.mark.asyncio(loop_scope="function") From aca9f5aca6f2ef6f0e7c2a54596cbe72aa3855a1 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 09:27:43 -0700 Subject: [PATCH 27/96] Move examples to main.py and add pyproject Rename ads and camera example modules to example_1/main.py, add pyproject.toml metadata for both examples (gallery metadata, deps and platforms), and update docs to reference the new example paths. Also wrap ads example buttons in SafeArea and protect ft.run with an if __name__ == "__main__" guard. --- .../ads/{example_1.py => example_1/main.py} | 29 ++++++++++++------- .../controls/ads/example_1/pyproject.toml | 27 +++++++++++++++++ .../{example_1.py => example_1/main.py} | 0 .../controls/camera/example_1/pyproject.toml | 27 +++++++++++++++++ sdk/python/packages/flet/docs/ads/bannerad.md | 2 +- sdk/python/packages/flet/docs/ads/index.md | 2 +- .../packages/flet/docs/ads/interstitialad.md | 2 +- sdk/python/packages/flet/docs/camera/index.md | 2 +- 8 files changed, 77 insertions(+), 14 deletions(-) rename sdk/python/examples/controls/ads/{example_1.py => example_1/main.py} (71%) create mode 100644 sdk/python/examples/controls/ads/example_1/pyproject.toml rename sdk/python/examples/controls/camera/{example_1.py => example_1/main.py} (100%) create mode 100644 sdk/python/examples/controls/camera/example_1/pyproject.toml diff --git a/sdk/python/examples/controls/ads/example_1.py b/sdk/python/examples/controls/ads/example_1/main.py similarity index 71% rename from sdk/python/examples/controls/ads/example_1.py rename to sdk/python/examples/controls/ads/example_1/main.py index 4a5fdd5748..31f03032e5 100644 --- a/sdk/python/examples/controls/ads/example_1.py +++ b/sdk/python/examples/controls/ads/example_1/main.py @@ -52,17 +52,26 @@ def get_new_banner_ad() -> fta.BannerAd: ) page.add( - ft.OutlinedButton( - content="Show InterstitialAd", - on_click=show_new_interstitial_ad, - disabled=page.web or not page.platform.is_mobile(), # mobile only - ), - ft.OutlinedButton( - content="Show BannerAd", - on_click=lambda e: page.add(get_new_banner_ad()), - disabled=page.web or not page.platform.is_mobile(), # mobile only + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton( + content="Show InterstitialAd", + on_click=show_new_interstitial_ad, + disabled=page.web + or not page.platform.is_mobile(), # mobile only + ), + ft.OutlinedButton( + content="Show BannerAd", + on_click=lambda e: page.add(get_new_banner_ad()), + disabled=page.web + or not page.platform.is_mobile(), # mobile only + ), + ] + ) ), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/ads/example_1/pyproject.toml b/sdk/python/examples/controls/ads/example_1/pyproject.toml new file mode 100644 index 0000000000..33950f8d18 --- /dev/null +++ b/sdk/python/examples/controls/ads/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "ads-example-1" +version = "1.0.0" +description = "Mobile ads example with BannerAd and InterstitialAd." +requires-python = ">=3.10" +keywords = ["ads", "banner ad", "interstitial ad", "admob", "mobile"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-ads"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Ads"] + +[tool.flet.metadata] +title = "BannerAd and InterstitialAd" +controls = ["SafeArea", "Column", "OutlinedButton", "AppBar", "BannerAd", "InterstitialAd"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["banner ad loading", "interstitial ad loading", "ad lifecycle callbacks", "platform-specific ad units"] + +[tool.flet] +platforms = ["web", "ios", "android"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/camera/example_1.py b/sdk/python/examples/controls/camera/example_1/main.py similarity index 100% rename from sdk/python/examples/controls/camera/example_1.py rename to sdk/python/examples/controls/camera/example_1/main.py diff --git a/sdk/python/examples/controls/camera/example_1/pyproject.toml b/sdk/python/examples/controls/camera/example_1/pyproject.toml new file mode 100644 index 0000000000..fc60b189ef --- /dev/null +++ b/sdk/python/examples/controls/camera/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "camera-example-1" +version = "1.0.0" +description = "Comprehensive camera demo with preview, photos, video recording, and streaming." +requires-python = ">=3.10" +keywords = ["camera", "photo", "video", "streaming", "device orientation", "media"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-camera"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Camera"] + +[tool.flet.metadata] +title = "Camera playground" +controls = ["SafeArea", "Column", "Row", "Container", "IconButton", "Dropdown", "Text", "Image", "FilledIconButton", "FilledTonalIconButton", "OutlinedIconButton", "Camera"] +layout_pattern = "control-panel" +complexity = "advanced" +features = ["camera initialization", "photo capture", "video recording", "record pause/resume", "image streaming", "preview pause/resume", "camera state events"] + +[tool.flet] +platforms = ["web", "ios", "android"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/ads/bannerad.md b/sdk/python/packages/flet/docs/ads/bannerad.md index f0458af358..78c8cb9c7a 100644 --- a/sdk/python/packages/flet/docs/ads/bannerad.md +++ b/sdk/python/packages/flet/docs/ads/bannerad.md @@ -11,7 +11,7 @@ example_images: ../examples/controls/ads/media ### Example 1 ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.gif", width="80%") }} diff --git a/sdk/python/packages/flet/docs/ads/index.md b/sdk/python/packages/flet/docs/ads/index.md index 96e17dbf1d..5cd6abc047 100644 --- a/sdk/python/packages/flet/docs/ads/index.md +++ b/sdk/python/packages/flet/docs/ads/index.md @@ -101,7 +101,7 @@ testing purposes. ## Example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.gif", width="80%") }} diff --git a/sdk/python/packages/flet/docs/ads/interstitialad.md b/sdk/python/packages/flet/docs/ads/interstitialad.md index a97bf026ef..a7612db469 100644 --- a/sdk/python/packages/flet/docs/ads/interstitialad.md +++ b/sdk/python/packages/flet/docs/ads/interstitialad.md @@ -11,7 +11,7 @@ example_images: ../examples/controls/ads/media ### Example 1 ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.gif", width="80%") }} diff --git a/sdk/python/packages/flet/docs/camera/index.md b/sdk/python/packages/flet/docs/camera/index.md index f929353cc4..a0c39db05e 100644 --- a/sdk/python/packages/flet/docs/camera/index.md +++ b/sdk/python/packages/flet/docs/camera/index.md @@ -115,7 +115,7 @@ permissions = ["camera", "microphone"] ## Example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Description From 1d3b7a1788e584a9cf18b3c9fc806ce5e0721ebd Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 10:02:28 -0700 Subject: [PATCH 28/96] Move canvas examples into main.py and add metadata Refactor canvas example files into per-example packages: rename .py examples into /main.py, add pyproject.toml metadata for each example, and update docs references. Wrap example UIs in SafeArea, add proper if __name__ == "__main__" run guards, and make small layout tweaks (e.g. brush container -> Column + SafeArea, comment out disable_auto_update). Remove the old top-level example scripts and update the canvas docs to point to the new main.py paths. --- .../main.py} | 5 +- .../canvas/bezier_curves/pyproject.toml | 26 ++++ .../canvas/{brush.py => brush/main.py} | 26 ++-- .../controls/canvas/brush/pyproject.toml | 26 ++++ .../controls/canvas/brush_on_image.py | 60 ---------- .../controls/canvas/brush_on_image/main.py | 64 ++++++++++ .../canvas/brush_on_image/pyproject.toml | 26 ++++ .../{dash_strokes.py => dash_strokes/main.py} | 7 +- .../canvas/dash_strokes/pyproject.toml | 26 ++++ .../examples/controls/canvas/flet_logo.py | 44 ------- .../controls/canvas/flet_logo/main.py | 49 ++++++++ .../controls/canvas/flet_logo/pyproject.toml | 26 ++++ .../examples/controls/canvas/gradients.py | 71 ----------- .../controls/canvas/gradients/main.py | 74 ++++++++++++ .../controls/canvas/gradients/pyproject.toml | 26 ++++ sdk/python/examples/controls/canvas/resize.py | 32 ----- .../examples/controls/canvas/resize/main.py | 36 ++++++ .../controls/canvas/resize/pyproject.toml | 26 ++++ .../examples/controls/canvas/smiling_face.py | 35 ------ .../controls/canvas/smiling_face/main.py | 38 ++++++ .../canvas/smiling_face/pyproject.toml | 26 ++++ sdk/python/examples/controls/canvas/text.py | 95 --------------- .../examples/controls/canvas/text/main.py | 111 ++++++++++++++++++ .../controls/canvas/text/pyproject.toml | 26 ++++ .../examples/controls/canvas/triangles.py | 33 ------ .../controls/canvas/triangles/main.py | 36 ++++++ .../controls/canvas/triangles/pyproject.toml | 26 ++++ .../flet/docs/controls/canvas/index.md | 14 +-- 28 files changed, 701 insertions(+), 389 deletions(-) rename sdk/python/examples/controls/canvas/{bezier_curves.py => bezier_curves/main.py} (96%) create mode 100644 sdk/python/examples/controls/canvas/bezier_curves/pyproject.toml rename sdk/python/examples/controls/canvas/{brush.py => brush/main.py} (76%) create mode 100644 sdk/python/examples/controls/canvas/brush/pyproject.toml delete mode 100644 sdk/python/examples/controls/canvas/brush_on_image.py create mode 100644 sdk/python/examples/controls/canvas/brush_on_image/main.py create mode 100644 sdk/python/examples/controls/canvas/brush_on_image/pyproject.toml rename sdk/python/examples/controls/canvas/{dash_strokes.py => dash_strokes/main.py} (97%) create mode 100644 sdk/python/examples/controls/canvas/dash_strokes/pyproject.toml delete mode 100644 sdk/python/examples/controls/canvas/flet_logo.py create mode 100644 sdk/python/examples/controls/canvas/flet_logo/main.py create mode 100644 sdk/python/examples/controls/canvas/flet_logo/pyproject.toml delete mode 100644 sdk/python/examples/controls/canvas/gradients.py create mode 100644 sdk/python/examples/controls/canvas/gradients/main.py create mode 100644 sdk/python/examples/controls/canvas/gradients/pyproject.toml delete mode 100644 sdk/python/examples/controls/canvas/resize.py create mode 100644 sdk/python/examples/controls/canvas/resize/main.py create mode 100644 sdk/python/examples/controls/canvas/resize/pyproject.toml delete mode 100644 sdk/python/examples/controls/canvas/smiling_face.py create mode 100644 sdk/python/examples/controls/canvas/smiling_face/main.py create mode 100644 sdk/python/examples/controls/canvas/smiling_face/pyproject.toml delete mode 100644 sdk/python/examples/controls/canvas/text.py create mode 100644 sdk/python/examples/controls/canvas/text/main.py create mode 100644 sdk/python/examples/controls/canvas/text/pyproject.toml delete mode 100644 sdk/python/examples/controls/canvas/triangles.py create mode 100644 sdk/python/examples/controls/canvas/triangles/main.py create mode 100644 sdk/python/examples/controls/canvas/triangles/pyproject.toml diff --git a/sdk/python/examples/controls/canvas/bezier_curves.py b/sdk/python/examples/controls/canvas/bezier_curves/main.py similarity index 96% rename from sdk/python/examples/controls/canvas/bezier_curves.py rename to sdk/python/examples/controls/canvas/bezier_curves/main.py index 020c43fc9d..84c048382e 100644 --- a/sdk/python/examples/controls/canvas/bezier_curves.py +++ b/sdk/python/examples/controls/canvas/bezier_curves/main.py @@ -59,7 +59,8 @@ def main(page: ft.Page): ], ) - page.add(cp) + page.add(ft.SafeArea(content=cp)) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/bezier_curves/pyproject.toml b/sdk/python/examples/controls/canvas/bezier_curves/pyproject.toml new file mode 100644 index 0000000000..1a60ab3282 --- /dev/null +++ b/sdk/python/examples/controls/canvas/bezier_curves/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-bezier-curves" +version = "1.0.0" +description = "Canvas bezier curve drawing with gradient fills." +requires-python = ">=3.10" +keywords = ["canvas", "bezier", "path", "gradient"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Bezier curves" +controls = ["SafeArea", "Canvas", "Path"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["quadratic and cubic paths", "radial gradient fill"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/brush.py b/sdk/python/examples/controls/canvas/brush/main.py similarity index 76% rename from sdk/python/examples/controls/canvas/brush.py rename to sdk/python/examples/controls/canvas/brush/main.py index 0140b98cb5..52ef91dff7 100644 --- a/sdk/python/examples/controls/canvas/brush.py +++ b/sdk/python/examples/controls/canvas/brush/main.py @@ -26,7 +26,7 @@ def handle_pan_start(e: ft.DragStartEvent): state.y = e.local_position.y async def handle_pan_update(e: ft.DragUpdateEvent): - ft.context.disable_auto_update() + # ft.context.disable_auto_update() canvas.shapes.append( cv.Line( x1=state.x, @@ -76,16 +76,24 @@ async def save_image(): f.write(capture) page.add( - ft.Button("Save image", on_click=save_image), - ft.Container( - content=canvas, - border_radius=5, - border=ft.Border.all(2), - bgcolor=ft.Colors.WHITE, - width=float("inf"), + ft.SafeArea( expand=True, + content=ft.Column( + controls=[ + ft.Button("Save image", on_click=save_image), + ft.Container( + border_radius=5, + border=ft.Border.all(2), + bgcolor=ft.Colors.WHITE, + width=float("inf"), + expand=True, + content=canvas, + ), + ] + ), ), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/brush/pyproject.toml b/sdk/python/examples/controls/canvas/brush/pyproject.toml new file mode 100644 index 0000000000..dd044beb09 --- /dev/null +++ b/sdk/python/examples/controls/canvas/brush/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-brush" +version = "1.0.0" +description = "Free-hand canvas drawing with capture and save support." +requires-python = ">=3.10" +keywords = ["canvas", "brush", "gesture", "capture", "save"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Brush" +controls = ["SafeArea", "Column", "Button", "Container", "Canvas", "GestureDetector", "Line", "Fill"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["pan drawing", "canvas capture", "save to file"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/brush_on_image.py b/sdk/python/examples/controls/canvas/brush_on_image.py deleted file mode 100644 index cec24534d3..0000000000 --- a/sdk/python/examples/controls/canvas/brush_on_image.py +++ /dev/null @@ -1,60 +0,0 @@ -import flet as ft -import flet.canvas as cv - - -class State: - x: float - y: float - - -state = State() - - -def main(page: ft.Page): - page.title = "Flet Brush" - - def handle_pan_start(e: ft.DragStartEvent): - state.x = e.local_position.x - state.y = e.local_position.y - - def handle_pan_update(e: ft.DragUpdateEvent): - canvas.shapes.append( - cv.Line( - x1=state.x, - y1=state.y, - x2=e.local_position.x, - y2=e.local_position.y, - paint=ft.Paint(stroke_width=3), - ) - ) - canvas.update() - state.x = e.local_position.x - state.y = e.local_position.y - - page.add( - ft.Container( - border_radius=5, - expand=True, - content=ft.Stack( - expand=True, - controls=[ - ft.Image( - src="https://picsum.photos/200/300", - fit=ft.BoxFit.FILL, - width=float("inf"), - ), - canvas := cv.Canvas( - expand=False, - content=ft.GestureDetector( - on_pan_start=handle_pan_start, - on_pan_update=handle_pan_update, - drag_interval=10, - ), - ), - ], - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/canvas/brush_on_image/main.py b/sdk/python/examples/controls/canvas/brush_on_image/main.py new file mode 100644 index 0000000000..abbd2eacd7 --- /dev/null +++ b/sdk/python/examples/controls/canvas/brush_on_image/main.py @@ -0,0 +1,64 @@ +import flet as ft +import flet.canvas as cv + + +class State: + x: float + y: float + + +state = State() + + +def main(page: ft.Page): + page.title = "Flet Brush" + + def handle_pan_start(e: ft.DragStartEvent): + state.x = e.local_position.x + state.y = e.local_position.y + + def handle_pan_update(e: ft.DragUpdateEvent): + canvas.shapes.append( + cv.Line( + x1=state.x, + y1=state.y, + x2=e.local_position.x, + y2=e.local_position.y, + paint=ft.Paint(stroke_width=3), + ) + ) + canvas.update() + state.x = e.local_position.x + state.y = e.local_position.y + + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + border_radius=5, + expand=True, + content=ft.Stack( + expand=True, + controls=[ + ft.Image( + src="https://picsum.photos/200/300", + fit=ft.BoxFit.FILL, + width=float("inf"), + ), + canvas := cv.Canvas( + expand=False, + content=ft.GestureDetector( + on_pan_start=handle_pan_start, + on_pan_update=handle_pan_update, + drag_interval=10, + ), + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/brush_on_image/pyproject.toml b/sdk/python/examples/controls/canvas/brush_on_image/pyproject.toml new file mode 100644 index 0000000000..9873b3fefc --- /dev/null +++ b/sdk/python/examples/controls/canvas/brush_on_image/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-brush-on-image" +version = "1.0.0" +description = "Draw free-hand strokes over an image using Canvas." +requires-python = ">=3.10" +keywords = ["canvas", "brush", "image", "gesture", "overlay"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Brush on image" +controls = ["SafeArea", "Container", "Stack", "Image", "Canvas", "GestureDetector", "Line"] +layout_pattern = "overlay" +complexity = "basic" +features = ["drawing on image", "pan gesture handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/dash_strokes.py b/sdk/python/examples/controls/canvas/dash_strokes/main.py similarity index 97% rename from sdk/python/examples/controls/canvas/dash_strokes.py rename to sdk/python/examples/controls/canvas/dash_strokes/main.py index 51eb09e2fd..edcf4bdaf4 100644 --- a/sdk/python/examples/controls/canvas/dash_strokes.py +++ b/sdk/python/examples/controls/canvas/dash_strokes/main.py @@ -110,4 +110,9 @@ def App(): ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/dash_strokes/pyproject.toml b/sdk/python/examples/controls/canvas/dash_strokes/pyproject.toml new file mode 100644 index 0000000000..d2296c763d --- /dev/null +++ b/sdk/python/examples/controls/canvas/dash_strokes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-dash-strokes" +version = "1.0.0" +description = "Toggle dashed stroke patterns across multiple canvas shapes." +requires-python = ">=3.10" +keywords = ["canvas", "stroke", "dash", "reactive", "shapes"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Dash strokes" +controls = ["SafeArea", "Column", "Button", "Canvas", "Line", "Circle", "Oval", "Arc", "Rect"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["reactive state", "dash stroke toggle", "multiple shape styles"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/flet_logo.py b/sdk/python/examples/controls/canvas/flet_logo.py deleted file mode 100644 index 6d96d2202d..0000000000 --- a/sdk/python/examples/controls/canvas/flet_logo.py +++ /dev/null @@ -1,44 +0,0 @@ -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Path( - elements=[ - cv.Path.MoveTo(x=25, y=125), - cv.Path.QuadraticTo(cp1x=50, cp1y=25, x=135, y=35, w=0.35), - cv.Path.QuadraticTo(cp1x=75, cp1y=115, x=135, y=215, w=0.6), - cv.Path.QuadraticTo(cp1x=50, cp1y=225, x=25, y=125, w=0.35), - ], - paint=ft.Paint( - stroke_width=2, - style=ft.PaintingStyle.FILL, - color=ft.Colors.PINK_400, - ), - ), - cv.Path( - elements=[ - cv.Path.MoveTo(x=85, y=125), - cv.Path.QuadraticTo(cp1x=120, cp1y=85, x=165, y=75, w=0.5), - cv.Path.QuadraticTo(cp1x=120, cp1y=115, x=165, y=175, w=0.3), - cv.Path.QuadraticTo(cp1x=120, cp1y=165, x=85, y=125, w=0.5), - ], - paint=ft.Paint( - stroke_width=2, - style=ft.PaintingStyle.FILL, - color=ft.Colors.with_opacity(0.5, ft.Colors.BLUE_400), - ), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/canvas/flet_logo/main.py b/sdk/python/examples/controls/canvas/flet_logo/main.py new file mode 100644 index 0000000000..820c46011f --- /dev/null +++ b/sdk/python/examples/controls/canvas/flet_logo/main.py @@ -0,0 +1,49 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Path( + elements=[ + cv.Path.MoveTo(x=25, y=125), + cv.Path.QuadraticTo(cp1x=50, cp1y=25, x=135, y=35, w=0.35), + cv.Path.QuadraticTo(cp1x=75, cp1y=115, x=135, y=215, w=0.6), + cv.Path.QuadraticTo(cp1x=50, cp1y=225, x=25, y=125, w=0.35), + ], + paint=ft.Paint( + stroke_width=2, + style=ft.PaintingStyle.FILL, + color=ft.Colors.PINK_400, + ), + ), + cv.Path( + elements=[ + cv.Path.MoveTo(x=85, y=125), + cv.Path.QuadraticTo(cp1x=120, cp1y=85, x=165, y=75, w=0.5), + cv.Path.QuadraticTo( + cp1x=120, cp1y=115, x=165, y=175, w=0.3 + ), + cv.Path.QuadraticTo(cp1x=120, cp1y=165, x=85, y=125, w=0.5), + ], + paint=ft.Paint( + stroke_width=2, + style=ft.PaintingStyle.FILL, + color=ft.Colors.with_opacity(0.5, ft.Colors.BLUE_400), + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/flet_logo/pyproject.toml b/sdk/python/examples/controls/canvas/flet_logo/pyproject.toml new file mode 100644 index 0000000000..22a0b75e00 --- /dev/null +++ b/sdk/python/examples/controls/canvas/flet_logo/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-flet-logo" +version = "1.0.0" +description = "Canvas drawing of the Flet logo using quadratic paths." +requires-python = ">=3.10" +keywords = ["canvas", "logo", "path", "quadratic"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Flet logo" +controls = ["SafeArea", "Canvas", "Path"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["path drawing", "filled vector shapes"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/gradients.py b/sdk/python/examples/controls/canvas/gradients.py deleted file mode 100644 index fe2b161bda..0000000000 --- a/sdk/python/examples/controls/canvas/gradients.py +++ /dev/null @@ -1,71 +0,0 @@ -import math - -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Rect( - x=10, - y=10, - width=100, - height=100, - border_radius=5, - paint=ft.Paint( - style=ft.PaintingStyle.FILL, - gradient=ft.PaintLinearGradient( - begin=(0, 10), - end=(100, 50), - colors=[ft.Colors.BLUE, ft.Colors.YELLOW], - ), - ), - ), - cv.Circle( - x=60, - y=170, - radius=50, - paint=ft.Paint( - style=ft.PaintingStyle.FILL, - gradient=ft.PaintRadialGradient( - radius=50, - center=(60, 170), - colors=[ft.Colors.YELLOW, ft.Colors.BLUE], - ), - ), - ), - cv.Path( - elements=[ - cv.Path.Arc( - x=10, - y=230, - width=100, - height=100, - start_angle=3 * math.pi / 4, - sweep_angle=3 * math.pi / 2, - ), - ], - paint=ft.Paint( - stroke_width=15, - stroke_join=ft.StrokeJoin.ROUND, - style=ft.PaintingStyle.STROKE, - gradient=ft.PaintSweepGradient( - start_angle=0, - end_angle=math.pi * 2, - rotation=3 * math.pi / 4, - center=(60, 280), - colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], - color_stops=[0.0, 1.0], - ), - ), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/canvas/gradients/main.py b/sdk/python/examples/controls/canvas/gradients/main.py new file mode 100644 index 0000000000..744b7b2f91 --- /dev/null +++ b/sdk/python/examples/controls/canvas/gradients/main.py @@ -0,0 +1,74 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Rect( + x=10, + y=10, + width=100, + height=100, + border_radius=5, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintLinearGradient( + begin=(0, 10), + end=(100, 50), + colors=[ft.Colors.BLUE, ft.Colors.YELLOW], + ), + ), + ), + cv.Circle( + x=60, + y=170, + radius=50, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintRadialGradient( + radius=50, + center=(60, 170), + colors=[ft.Colors.YELLOW, ft.Colors.BLUE], + ), + ), + ), + cv.Path( + elements=[ + cv.Path.Arc( + x=10, + y=230, + width=100, + height=100, + start_angle=3 * math.pi / 4, + sweep_angle=3 * math.pi / 2, + ), + ], + paint=ft.Paint( + stroke_width=15, + stroke_join=ft.StrokeJoin.ROUND, + style=ft.PaintingStyle.STROKE, + gradient=ft.PaintSweepGradient( + start_angle=0, + end_angle=math.pi * 2, + rotation=3 * math.pi / 4, + center=(60, 280), + colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], + color_stops=[0.0, 1.0], + ), + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/gradients/pyproject.toml b/sdk/python/examples/controls/canvas/gradients/pyproject.toml new file mode 100644 index 0000000000..11ee8446f5 --- /dev/null +++ b/sdk/python/examples/controls/canvas/gradients/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-gradients" +version = "1.0.0" +description = "Canvas gradient fills with linear, radial, and sweep gradients." +requires-python = ">=3.10" +keywords = ["canvas", "gradients", "linear", "radial", "sweep"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Gradients" +controls = ["SafeArea", "Canvas", "Rect", "Circle", "Path"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["linear gradient", "radial gradient", "sweep gradient"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/resize.py b/sdk/python/examples/controls/canvas/resize.py deleted file mode 100644 index 0751942af9..0000000000 --- a/sdk/python/examples/controls/canvas/resize.py +++ /dev/null @@ -1,32 +0,0 @@ -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - def paint_resize(e: cv.CanvasResizeEvent): - print("On resize:", e.width, e.height) - canvas.shapes[0].x2 = e.width - canvas.shapes[0].y2 = e.height - canvas.shapes[1].y1 = e.height - canvas.shapes[1].x2 = e.width - canvas.update() - - page.add( - ft.Container( - width=float("inf"), - expand=True, - content=( - canvas := cv.Canvas( - resize_interval=10, - on_resize=paint_resize, - shapes=[ - cv.Line(x1=0, y1=0, x2=100, y2=100), - cv.Line(x1=0, y1=100, x2=100, y2=0), - ], - ) - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/canvas/resize/main.py b/sdk/python/examples/controls/canvas/resize/main.py new file mode 100644 index 0000000000..ec403efc6f --- /dev/null +++ b/sdk/python/examples/controls/canvas/resize/main.py @@ -0,0 +1,36 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + def paint_resize(e: cv.CanvasResizeEvent): + print("On resize:", e.width, e.height) + canvas.shapes[0].x2 = e.width + canvas.shapes[0].y2 = e.height + canvas.shapes[1].y1 = e.height + canvas.shapes[1].x2 = e.width + canvas.update() + + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + width=float("inf"), + expand=True, + content=( + canvas := cv.Canvas( + resize_interval=10, + on_resize=paint_resize, + shapes=[ + cv.Line(x1=0, y1=0, x2=100, y2=100), + cv.Line(x1=0, y1=100, x2=100, y2=0), + ], + ) + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/resize/pyproject.toml b/sdk/python/examples/controls/canvas/resize/pyproject.toml new file mode 100644 index 0000000000..eeb2e8e3c8 --- /dev/null +++ b/sdk/python/examples/controls/canvas/resize/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-resize" +version = "1.0.0" +description = "Canvas resize handling with dynamic shape updates." +requires-python = ">=3.10" +keywords = ["canvas", "resize", "events", "responsive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Canvas resize" +controls = ["SafeArea", "Container", "Canvas", "Line"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["on_resize event", "responsive line drawing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/smiling_face.py b/sdk/python/examples/controls/canvas/smiling_face.py deleted file mode 100644 index 68361350c2..0000000000 --- a/sdk/python/examples/controls/canvas/smiling_face.py +++ /dev/null @@ -1,35 +0,0 @@ -import math - -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - stroke_paint = ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE) - fill_paint = ft.Paint(style=ft.PaintingStyle.FILL) - - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Circle(x=100, y=100, radius=50, paint=stroke_paint), - cv.Circle(x=80, y=90, radius=10, paint=stroke_paint), - cv.Circle(x=84, y=87, radius=5, paint=fill_paint), - cv.Circle(x=120, y=90, radius=10, paint=stroke_paint), - cv.Circle(x=124, y=87, radius=5, paint=fill_paint), - cv.Arc( - x=70, - y=95, - width=60, - height=40, - start_angle=0, - sweep_angle=math.pi, - paint=stroke_paint, - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/canvas/smiling_face/main.py b/sdk/python/examples/controls/canvas/smiling_face/main.py new file mode 100644 index 0000000000..e7d6724cbc --- /dev/null +++ b/sdk/python/examples/controls/canvas/smiling_face/main.py @@ -0,0 +1,38 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + stroke_paint = ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE) + fill_paint = ft.Paint(style=ft.PaintingStyle.FILL) + + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Circle(x=100, y=100, radius=50, paint=stroke_paint), + cv.Circle(x=80, y=90, radius=10, paint=stroke_paint), + cv.Circle(x=84, y=87, radius=5, paint=fill_paint), + cv.Circle(x=120, y=90, radius=10, paint=stroke_paint), + cv.Circle(x=124, y=87, radius=5, paint=fill_paint), + cv.Arc( + x=70, + y=95, + width=60, + height=40, + start_angle=0, + sweep_angle=math.pi, + paint=stroke_paint, + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/smiling_face/pyproject.toml b/sdk/python/examples/controls/canvas/smiling_face/pyproject.toml new file mode 100644 index 0000000000..fa9778fffc --- /dev/null +++ b/sdk/python/examples/controls/canvas/smiling_face/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-smiling-face" +version = "1.0.0" +description = "Canvas drawing example of a smiling face." +requires-python = ">=3.10" +keywords = ["canvas", "drawing", "shapes", "arc", "circle"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Smiling face" +controls = ["SafeArea", "Canvas", "Circle", "Arc"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["shape drawing", "stroke and fill paints"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/text.py b/sdk/python/examples/controls/canvas/text.py deleted file mode 100644 index 8a8d69e0ab..0000000000 --- a/sdk/python/examples/controls/canvas/text.py +++ /dev/null @@ -1,95 +0,0 @@ -import math - -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Text(x=0, y=0, value="Just a text"), - cv.Circle(x=200, y=100, radius=2, paint=ft.Paint(color=ft.Colors.RED)), - cv.Text( - x=200, - y=100, - style=ft.TextStyle(weight=ft.FontWeight.BOLD, size=30), - alignment=ft.Alignment.TOP_CENTER, - rotate=math.pi * 0.15, - value="Rotated", - spans=[ - ft.TextSpan( - text="around top_center", - style=ft.TextStyle( - italic=True, color=ft.Colors.GREEN, size=20 - ), - ) - ], - ), - cv.Circle(x=400, y=100, radius=2, paint=ft.Paint(color=ft.Colors.RED)), - cv.Text( - x=400, - y=100, - value="Rotated around top_left", - style=ft.TextStyle(size=20), - alignment=ft.Alignment.TOP_LEFT, - rotate=math.pi * -0.15, - ), - cv.Circle(x=600, y=200, radius=2, paint=ft.Paint(color=ft.Colors.RED)), - cv.Text( - x=600, - y=200, - value="Rotated around center", - style=ft.TextStyle(size=20), - alignment=ft.Alignment.CENTER, - rotate=math.pi / 2, - ), - cv.Text( - x=300, - y=400, - value="Limited to max_width and right-aligned.\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", - text_align=ft.TextAlign.RIGHT, - max_width=400, - ), - cv.Text( - x=200, - y=200, - value="WOW!", - style=ft.TextStyle( - weight=ft.FontWeight.BOLD, - size=100, - foreground=ft.Paint( - color=ft.Colors.PINK, - stroke_width=6, - style=ft.PaintingStyle.STROKE, - stroke_join=ft.StrokeJoin.ROUND, - stroke_cap=ft.StrokeCap.ROUND, - ), - ), - ), - cv.Text( - x=200, - y=200, - value="WOW!", - style=ft.TextStyle( - weight=ft.FontWeight.BOLD, - size=100, - foreground=ft.Paint( - gradient=ft.PaintLinearGradient( - begin=(200, 200), - end=(300, 300), - colors=[ft.Colors.YELLOW, ft.Colors.RED], - ), - stroke_join=ft.StrokeJoin.ROUND, - stroke_cap=ft.StrokeCap.ROUND, - ), - ), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/canvas/text/main.py b/sdk/python/examples/controls/canvas/text/main.py new file mode 100644 index 0000000000..565910117a --- /dev/null +++ b/sdk/python/examples/controls/canvas/text/main.py @@ -0,0 +1,111 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Text(x=0, y=0, value="Just a text"), + cv.Circle( + x=200, y=100, radius=2, paint=ft.Paint(color=ft.Colors.RED) + ), + cv.Text( + x=200, + y=100, + style=ft.TextStyle(weight=ft.FontWeight.BOLD, size=30), + alignment=ft.Alignment.TOP_CENTER, + rotate=math.pi * 0.15, + value="Rotated", + spans=[ + ft.TextSpan( + text="around top_center", + style=ft.TextStyle( + italic=True, color=ft.Colors.GREEN, size=20 + ), + ) + ], + ), + cv.Circle( + x=400, y=100, radius=2, paint=ft.Paint(color=ft.Colors.RED) + ), + cv.Text( + x=400, + y=100, + value="Rotated around top_left", + style=ft.TextStyle(size=20), + alignment=ft.Alignment.TOP_LEFT, + rotate=math.pi * -0.15, + ), + cv.Circle( + x=600, y=200, radius=2, paint=ft.Paint(color=ft.Colors.RED) + ), + cv.Text( + x=600, + y=200, + value="Rotated around center", + style=ft.TextStyle(size=20), + alignment=ft.Alignment.CENTER, + rotate=math.pi / 2, + ), + cv.Text( + x=300, + y=400, + value=( + "Limited to max_width and right-aligned.\n" + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore " + "magna aliqua. Ut enim ad minim veniam, quis nostrud " + "exercitation " + "ullamco laboris nisi ut aliquip ex ea commodo consequat." + ), + text_align=ft.TextAlign.RIGHT, + max_width=400, + ), + cv.Text( + x=200, + y=200, + value="WOW!", + style=ft.TextStyle( + weight=ft.FontWeight.BOLD, + size=100, + foreground=ft.Paint( + color=ft.Colors.PINK, + stroke_width=6, + style=ft.PaintingStyle.STROKE, + stroke_join=ft.StrokeJoin.ROUND, + stroke_cap=ft.StrokeCap.ROUND, + ), + ), + ), + cv.Text( + x=200, + y=200, + value="WOW!", + style=ft.TextStyle( + weight=ft.FontWeight.BOLD, + size=100, + foreground=ft.Paint( + gradient=ft.PaintLinearGradient( + begin=(200, 200), + end=(300, 300), + colors=[ft.Colors.YELLOW, ft.Colors.RED], + ), + stroke_join=ft.StrokeJoin.ROUND, + stroke_cap=ft.StrokeCap.ROUND, + ), + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/text/pyproject.toml b/sdk/python/examples/controls/canvas/text/pyproject.toml new file mode 100644 index 0000000000..a706829050 --- /dev/null +++ b/sdk/python/examples/controls/canvas/text/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-text" +version = "1.0.0" +description = "Canvas text rendering with transforms, spans, and paint effects." +requires-python = ">=3.10" +keywords = ["canvas", "text", "rotation", "gradient", "spans"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Canvas text" +controls = ["SafeArea", "Canvas", "Text", "TextStyle", "TextSpan", "Circle"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["rotated text", "text spans", "stroke and gradient paint"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/canvas/triangles.py b/sdk/python/examples/controls/canvas/triangles.py deleted file mode 100644 index bb3c0d1092..0000000000 --- a/sdk/python/examples/controls/canvas/triangles.py +++ /dev/null @@ -1,33 +0,0 @@ -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Path( - paint=ft.Paint(style=ft.PaintingStyle.FILL), - elements=[ - cv.Path.MoveTo(x=25, y=25), - cv.Path.LineTo(x=105, y=25), - cv.Path.LineTo(x=25, y=105), - ], - ), - cv.Path( - paint=ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE), - elements=[ - cv.Path.MoveTo(x=125, y=125), - cv.Path.LineTo(x=125, y=45), - cv.Path.LineTo(x=45, y=125), - cv.Path.Close(), - ], - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/canvas/triangles/main.py b/sdk/python/examples/controls/canvas/triangles/main.py new file mode 100644 index 0000000000..ce074c4c58 --- /dev/null +++ b/sdk/python/examples/controls/canvas/triangles/main.py @@ -0,0 +1,36 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Path( + paint=ft.Paint(style=ft.PaintingStyle.FILL), + elements=[ + cv.Path.MoveTo(x=25, y=25), + cv.Path.LineTo(x=105, y=25), + cv.Path.LineTo(x=25, y=105), + ], + ), + cv.Path( + paint=ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE), + elements=[ + cv.Path.MoveTo(x=125, y=125), + cv.Path.LineTo(x=125, y=45), + cv.Path.LineTo(x=45, y=125), + cv.Path.Close(), + ], + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/canvas/triangles/pyproject.toml b/sdk/python/examples/controls/canvas/triangles/pyproject.toml new file mode 100644 index 0000000000..8167e855dd --- /dev/null +++ b/sdk/python/examples/controls/canvas/triangles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-triangles" +version = "1.0.0" +description = "Canvas triangles with fill and stroke path styles." +requires-python = ">=3.10" +keywords = ["canvas", "triangles", "path", "stroke", "fill"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Triangles" +controls = ["SafeArea", "Canvas", "Path"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["path drawing", "filled and outlined shapes"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/canvas/index.md b/sdk/python/packages/flet/docs/controls/canvas/index.md index cb5ce993a1..a20ec623ad 100644 --- a/sdk/python/packages/flet/docs/controls/canvas/index.md +++ b/sdk/python/packages/flet/docs/controls/canvas/index.md @@ -16,7 +16,7 @@ example_media: ../../examples/controls/canvas/media ### Smiling face ```python ---8<-- "{{ examples }}/smiling_face.py" +--8<-- "{{ examples }}/smiling_face/main.py" ``` {{ image(example_media + "/smiling_face.png", alt="smiling-face", width="80%") }} @@ -25,7 +25,7 @@ example_media: ../../examples/controls/canvas/media ### Flet logo ```python ---8<-- "{{ examples }}/flet_logo.py" +--8<-- "{{ examples }}/flet_logo/main.py" ``` {{ image(example_media + "/flet_logo.png", alt="flet-logo", width="80%") }} @@ -34,7 +34,7 @@ example_media: ../../examples/controls/canvas/media ### Triangles ```python ---8<-- "{{ examples }}/triangles.py" +--8<-- "{{ examples }}/triangles/main.py" ``` {{ image(example_media + "/triangles.png", alt="triangles", width="80%") }} @@ -43,7 +43,7 @@ example_media: ../../examples/controls/canvas/media ### Bezier curves ```python ---8<-- "{{ examples }}/bezier_curves.py" +--8<-- "{{ examples }}/bezier_curves/main.py" ``` {{ image(example_media + "/bezier_curves.png", alt="bezier-curves", width="80%") }} @@ -52,7 +52,7 @@ example_media: ../../examples/controls/canvas/media ### Text ```python ---8<-- "{{ examples }}/text.py" +--8<-- "{{ examples }}/text/main.py" ``` {{ image(example_media + "/text.png", alt="text", width="80%") }} @@ -61,13 +61,13 @@ example_media: ../../examples/controls/canvas/media ### Free-hand drawing with image capture ```python ---8<-- "{{ examples }}/brush.py" +--8<-- "{{ examples }}/brush/main.py" ``` ### Gradients ```python ---8<-- "{{ examples }}/gradients.py" +--8<-- "{{ examples }}/gradients/main.py" ``` {{ class_members(class_name) }} From 7e06a2c6bca1c12c9411012ee3c1e4a168db8cc6 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 10:05:19 -0700 Subject: [PATCH 29/96] Add ruff checks to example validation steps Add explicit instructions to run `uv run ruff check` on changed example files as part of the validation steps. The new lines instruct maintainers to fix Ruff violations until the check passes (respecting `[tool.ruff]` in `pyproject.toml`) and add a short command example in the discovery checklist. --- .codex/skills/create-flet-example-projects/SKILL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index dd405c9e76..76b435a28a 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -92,6 +92,7 @@ Ensure each runnable example is a standalone project containing: 11. Validate. - Run `python -m compileall` on changed `main.py` files. +- Run `uv run ruff check` on changed example files and fix violations until it passes (respecting repository `pyproject.toml` under `[tool.ruff]`). - Search for stale paths to old flat files. - Check `git status` to confirm expected moves and edits. - When integration tests exist for the touched control, run the targeted test file(s). @@ -110,6 +111,7 @@ Ensure each runnable example is a standalone project containing: - Discover files: `rg --files ` - Find docs links/imports: `rg -n "" packages examples` - Syntax check: `python -m compileall ` +- Ruff check: `uv run ruff check ` ## Output expectations From 8bdfec7015daac1966526c20cb267f67d2ad4a4c Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 11:53:56 -0700 Subject: [PATCH 30/96] Reorganize card music_info example Move the music_info Card example into its own subpackage. Removed legacy examples/controls/card/__init__.py and music_info.py, and added examples/controls/card/music_info/main.py (wraps the Card in a SafeArea) plus a pyproject.toml with package and gallery metadata. Updated the card docs to point to the new example path and adjusted the integration test to import the new module, use a fixed screenshot name "music_info", and remove the explicit similarity_threshold. --- sdk/python/examples/controls/card/__init__.py | 0 .../examples/controls/card/music_info.py | 39 ------------------ .../examples/controls/card/music_info/main.py | 41 +++++++++++++++++++ .../controls/card/music_info/pyproject.toml | 26 ++++++++++++ .../packages/flet/docs/controls/card.md | 2 +- .../examples/material/test_card.py | 5 +-- 6 files changed, 70 insertions(+), 43 deletions(-) delete mode 100644 sdk/python/examples/controls/card/__init__.py delete mode 100644 sdk/python/examples/controls/card/music_info.py create mode 100644 sdk/python/examples/controls/card/music_info/main.py create mode 100644 sdk/python/examples/controls/card/music_info/pyproject.toml diff --git a/sdk/python/examples/controls/card/__init__.py b/sdk/python/examples/controls/card/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/card/music_info.py b/sdk/python/examples/controls/card/music_info.py deleted file mode 100644 index 9a1442a9a0..0000000000 --- a/sdk/python/examples/controls/card/music_info.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Card Example" - page.theme_mode = ft.ThemeMode.LIGHT - - page.add( - ft.Card( - shadow_color=ft.Colors.ON_SURFACE_VARIANT, - content=ft.Container( - width=400, - padding=10, - content=ft.Column( - controls=[ - ft.ListTile( - bgcolor=ft.Colors.GREY_400, - leading=ft.Icon(ft.Icons.ALBUM), - title=ft.Text("The Enchanted Nightingale"), - subtitle=ft.Text( - "Music by Julie Gable. Lyrics by Sidney Stein." - ), - ), - ft.Row( - alignment=ft.MainAxisAlignment.END, - controls=[ - ft.TextButton("Buy tickets"), - ft.TextButton("Listen"), - ], - ), - ] - ), - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/card/music_info/main.py b/sdk/python/examples/controls/card/music_info/main.py new file mode 100644 index 0000000000..3996d62040 --- /dev/null +++ b/sdk/python/examples/controls/card/music_info/main.py @@ -0,0 +1,41 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Card Example" + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.Card( + shadow_color=ft.Colors.ON_SURFACE_VARIANT, + content=ft.Container( + width=400, + padding=10, + content=ft.Column( + controls=[ + ft.ListTile( + bgcolor=ft.Colors.GREY_400, + leading=ft.Icon(ft.Icons.ALBUM), + title=ft.Text("The Enchanted Nightingale"), + subtitle=ft.Text( + "Music by Julie Gable. Lyrics by Sidney Stein." + ), + ), + ft.Row( + alignment=ft.MainAxisAlignment.END, + controls=[ + ft.TextButton("Buy tickets"), + ft.TextButton("Listen"), + ], + ), + ] + ), + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/card/music_info/pyproject.toml b/sdk/python/examples/controls/card/music_info/pyproject.toml new file mode 100644 index 0000000000..3915c0af7c --- /dev/null +++ b/sdk/python/examples/controls/card/music_info/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "card-music-info" +version = "1.0.0" +description = "Card with music info and action buttons." +requires-python = ">=3.10" +keywords = ["card", "listtile", "actions", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Card"] + +[tool.flet.metadata] +title = "Music info" +controls = ["SafeArea", "Card", "Container", "Column", "ListTile", "Row", "TextButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["card layout", "action buttons"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/card.md b/sdk/python/packages/flet/docs/controls/card.md index bfa5caad0a..883ac92420 100644 --- a/sdk/python/packages/flet/docs/controls/card.md +++ b/sdk/python/packages/flet/docs/controls/card.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/material/golden/macos/card [Live example](https://flet-controls-gallery.fly.dev/layout/card) ```python ---8<-- "{{ examples }}/music_info.py" +--8<-- "{{ examples }}/music_info/main.py" ``` {{ image(example_images + "/music_info.png", alt="music-info", width="50%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_card.py b/sdk/python/packages/flet/integration_tests/examples/material/test_card.py index 908fef0629..7f5e64acf1 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_card.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_card.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.card.music_info.main as music_info import flet as ft import flet.testing as ftt -from examples.controls.card import music_info @pytest.mark.asyncio(loop_scope="function") @@ -34,7 +34,6 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.asyncio(loop_scope="function") async def test_music_info(flet_app_function: ftt.FletTestApp): flet_app_function.assert_screenshot( - test_music_info.__name__, + "music_info", await flet_app_function.take_page_controls_screenshot(), - similarity_threshold=98.4, ) From b692b59d61829470957cbfebd8e5d0c2e44d0361 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 12:02:24 -0700 Subject: [PATCH 31/96] Restructure chart examples and add pyproject files Move example scripts into example_x/main.py layout, remove legacy top-level example files and __init__.py placeholders, and add per-example pyproject.toml metadata for the Flet gallery. Wrap example UIs with ft.SafeArea and adjust small layout/import tweaks (reordered imports, updated page.render/ft.run entrypoints) to standardize examples. --- .../controls/charts/bar_chart/__init__.py | 0 .../controls/charts/bar_chart/example_1.py | 97 ----------------- .../charts/bar_chart/example_1/main.py | 100 ++++++++++++++++++ .../charts/bar_chart/example_1/pyproject.toml | 26 +++++ .../{example_2.py => example_2/main.py} | 17 +-- .../charts/bar_chart/example_2/pyproject.toml | 26 +++++ .../charts/candlestick_chart/__init__.py | 0 .../{example_1.py => example_1/main.py} | 32 +++--- .../example_1/pyproject.toml | 26 +++++ .../controls/charts/line_chart/__init__.py | 0 .../main.py} | 87 ++++++++------- .../dashboard_declarative/pyproject.toml | 26 +++++ .../{example_1.py => example_1/main.py} | 14 ++- .../line_chart/example_1/pyproject.toml | 26 +++++ .../{example_2.py => example_2/main.py} | 11 +- .../line_chart/example_2/pyproject.toml | 26 +++++ .../charts/matplotlib_chart/__init__.py | 0 .../{animate.py => animate/main.py} | 6 +- .../matplotlib_chart/animate/pyproject.toml | 26 +++++ .../{bar_chart.py => bar_chart/main.py} | 2 +- .../matplotlib_chart/bar_chart/pyproject.toml | 26 +++++ .../main.py} | 6 +- .../handle_events/pyproject.toml | 26 +++++ .../{three_d.py => three_d/main.py} | 2 +- .../matplotlib_chart/three_d/pyproject.toml | 26 +++++ .../{toolbar.py => toolbar/main.py} | 6 +- .../matplotlib_chart/toolbar/pyproject.toml | 26 +++++ .../controls/charts/pie_chart/__init__.py | 0 .../{example_1.py => example_1/main.py} | 5 +- .../charts/pie_chart/example_1/pyproject.toml | 26 +++++ .../{example_2.py => example_2/main.py} | 2 +- .../charts/pie_chart/example_2/pyproject.toml | 26 +++++ .../{example_3.py => example_3/main.py} | 2 +- .../charts/pie_chart/example_3/pyproject.toml | 26 +++++ .../controls/charts/plotly_chart/__init__.py | 0 .../{example_1.py => example_1/main.py} | 4 +- .../plotly_chart/example_1/pyproject.toml | 26 +++++ .../{example_2.py => example_2/main.py} | 4 +- .../plotly_chart/example_2/pyproject.toml | 26 +++++ .../{example_3.py => example_3/main.py} | 4 +- .../plotly_chart/example_3/pyproject.toml | 26 +++++ .../{example_4.py => example_4/main.py} | 4 +- .../plotly_chart/example_4/pyproject.toml | 26 +++++ .../controls/charts/radar_chart/__init__.py | 0 .../controls/charts/radar_chart/example_1.py | 61 ----------- .../charts/radar_chart/example_1/main.py | 63 +++++++++++ .../radar_chart/example_1/pyproject.toml | 26 +++++ .../controls/charts/scatter_chart/__init__.py | 0 .../{example_1.py => example_1/main.py} | 47 ++++---- .../scatter_chart/example_1/pyproject.toml | 26 +++++ .../packages/flet/docs/charts/barchart.md | 4 +- .../flet/docs/charts/candlestickchart.md | 2 +- .../packages/flet/docs/charts/linechart.md | 4 +- .../flet/docs/charts/matplotlibchart.md | 2 +- .../docs/charts/matplotlibchartwithtoolbar.md | 8 +- .../packages/flet/docs/charts/piechart.md | 6 +- .../packages/flet/docs/charts/plotlychart.md | 8 +- .../packages/flet/docs/charts/radarchart.md | 2 +- .../packages/flet/docs/charts/scatterchart.md | 2 +- 59 files changed, 852 insertions(+), 282 deletions(-) delete mode 100644 sdk/python/examples/controls/charts/bar_chart/__init__.py delete mode 100644 sdk/python/examples/controls/charts/bar_chart/example_1.py create mode 100644 sdk/python/examples/controls/charts/bar_chart/example_1/main.py create mode 100644 sdk/python/examples/controls/charts/bar_chart/example_1/pyproject.toml rename sdk/python/examples/controls/charts/bar_chart/{example_2.py => example_2/main.py} (91%) create mode 100644 sdk/python/examples/controls/charts/bar_chart/example_2/pyproject.toml delete mode 100644 sdk/python/examples/controls/charts/candlestick_chart/__init__.py rename sdk/python/examples/controls/charts/candlestick_chart/{example_1.py => example_1/main.py} (86%) create mode 100644 sdk/python/examples/controls/charts/candlestick_chart/example_1/pyproject.toml delete mode 100644 sdk/python/examples/controls/charts/line_chart/__init__.py rename sdk/python/examples/controls/charts/line_chart/{dashboard_declarative.py => dashboard_declarative/main.py} (60%) create mode 100644 sdk/python/examples/controls/charts/line_chart/dashboard_declarative/pyproject.toml rename sdk/python/examples/controls/charts/line_chart/{example_1.py => example_1/main.py} (96%) create mode 100644 sdk/python/examples/controls/charts/line_chart/example_1/pyproject.toml rename sdk/python/examples/controls/charts/line_chart/{example_2.py => example_2/main.py} (95%) create mode 100644 sdk/python/examples/controls/charts/line_chart/example_2/pyproject.toml delete mode 100644 sdk/python/examples/controls/charts/matplotlib_chart/__init__.py rename sdk/python/examples/controls/charts/matplotlib_chart/{animate.py => animate/main.py} (91%) create mode 100644 sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml rename sdk/python/examples/controls/charts/matplotlib_chart/{bar_chart.py => bar_chart/main.py} (87%) create mode 100644 sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/pyproject.toml rename sdk/python/examples/controls/charts/matplotlib_chart/{handle_events.py => handle_events/main.py} (95%) create mode 100644 sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml rename sdk/python/examples/controls/charts/matplotlib_chart/{three_d.py => three_d/main.py} (90%) create mode 100644 sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml rename sdk/python/examples/controls/charts/matplotlib_chart/{toolbar.py => toolbar/main.py} (86%) create mode 100644 sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml delete mode 100644 sdk/python/examples/controls/charts/pie_chart/__init__.py rename sdk/python/examples/controls/charts/pie_chart/{example_1.py => example_1/main.py} (97%) create mode 100644 sdk/python/examples/controls/charts/pie_chart/example_1/pyproject.toml rename sdk/python/examples/controls/charts/pie_chart/{example_2.py => example_2/main.py} (97%) create mode 100644 sdk/python/examples/controls/charts/pie_chart/example_2/pyproject.toml rename sdk/python/examples/controls/charts/pie_chart/{example_3.py => example_3/main.py} (98%) create mode 100644 sdk/python/examples/controls/charts/pie_chart/example_3/pyproject.toml delete mode 100644 sdk/python/examples/controls/charts/plotly_chart/__init__.py rename sdk/python/examples/controls/charts/plotly_chart/{example_1.py => example_1/main.py} (77%) create mode 100644 sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml rename sdk/python/examples/controls/charts/plotly_chart/{example_2.py => example_2/main.py} (84%) create mode 100644 sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml rename sdk/python/examples/controls/charts/plotly_chart/{example_3.py => example_3/main.py} (80%) create mode 100644 sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml rename sdk/python/examples/controls/charts/plotly_chart/{example_4.py => example_4/main.py} (93%) create mode 100644 sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml delete mode 100644 sdk/python/examples/controls/charts/radar_chart/__init__.py delete mode 100644 sdk/python/examples/controls/charts/radar_chart/example_1.py create mode 100644 sdk/python/examples/controls/charts/radar_chart/example_1/main.py create mode 100644 sdk/python/examples/controls/charts/radar_chart/example_1/pyproject.toml delete mode 100644 sdk/python/examples/controls/charts/scatter_chart/__init__.py rename sdk/python/examples/controls/charts/scatter_chart/{example_1.py => example_1/main.py} (70%) create mode 100644 sdk/python/examples/controls/charts/scatter_chart/example_1/pyproject.toml diff --git a/sdk/python/examples/controls/charts/bar_chart/__init__.py b/sdk/python/examples/controls/charts/bar_chart/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/charts/bar_chart/example_1.py b/sdk/python/examples/controls/charts/bar_chart/example_1.py deleted file mode 100644 index fb1c91fd98..0000000000 --- a/sdk/python/examples/controls/charts/bar_chart/example_1.py +++ /dev/null @@ -1,97 +0,0 @@ -import flet as ft -import flet_charts as fch - - -def main(page: ft.Page): - page.add( - fch.BarChart( - expand=True, - interactive=True, - max_y=110, - border=ft.Border.all(1, ft.Colors.GREY_400), - horizontal_grid_lines=fch.ChartGridLines( - color=ft.Colors.GREY_300, width=1, dash_pattern=[3, 3] - ), - tooltip=fch.BarChartTooltip( - bgcolor=ft.Colors.with_opacity(0.5, ft.Colors.GREY_300), - border_radius=ft.BorderRadius.all(20), - ), - left_axis=fch.ChartAxis( - label_size=40, title=ft.Text("Fruit supply"), title_size=40 - ), - right_axis=fch.ChartAxis(show_labels=False), - bottom_axis=fch.ChartAxis( - label_size=40, - labels=[ - fch.ChartAxisLabel( - value=0, label=ft.Container(ft.Text("Apple"), padding=10) - ), - fch.ChartAxisLabel( - value=1, label=ft.Container(ft.Text("Blueberry"), padding=10) - ), - fch.ChartAxisLabel( - value=2, label=ft.Container(ft.Text("Cherry"), padding=10) - ), - fch.ChartAxisLabel( - value=3, label=ft.Container(ft.Text("Orange"), padding=10) - ), - ], - ), - groups=[ - fch.BarChartGroup( - x=0, - rods=[ - fch.BarChartRod( - from_y=0, - to_y=40, - width=40, - color=ft.Colors.GREEN, - border_radius=0, - ), - ], - ), - fch.BarChartGroup( - x=1, - rods=[ - fch.BarChartRod( - from_y=0, - to_y=100, - width=40, - color=ft.Colors.BLUE, - tooltip=fch.BarChartRodTooltip("Blueberry"), - border_radius=0, - ), - ], - ), - fch.BarChartGroup( - x=2, - rods=[ - fch.BarChartRod( - from_y=0, - to_y=30, - width=40, - color=ft.Colors.RED, - border_radius=0, - ), - ], - ), - fch.BarChartGroup( - x=3, - rods=[ - fch.BarChartRod( - from_y=0, - to_y=60, - width=40, - color=ft.Colors.ORANGE, - tooltip=fch.BarChartRodTooltip("Orange"), - border_radius=0, - ), - ], - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/charts/bar_chart/example_1/main.py b/sdk/python/examples/controls/charts/bar_chart/example_1/main.py new file mode 100644 index 0000000000..36955504a3 --- /dev/null +++ b/sdk/python/examples/controls/charts/bar_chart/example_1/main.py @@ -0,0 +1,100 @@ +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=fch.BarChart( + expand=True, + interactive=True, + max_y=110, + border=ft.Border.all(1, ft.Colors.GREY_400), + horizontal_grid_lines=fch.ChartGridLines( + color=ft.Colors.GREY_300, width=1, dash_pattern=[3, 3] + ), + tooltip=fch.BarChartTooltip( + bgcolor=ft.Colors.with_opacity(0.5, ft.Colors.GREY_300), + border_radius=ft.BorderRadius.all(20), + ), + left_axis=fch.ChartAxis( + label_size=40, title=ft.Text("Fruit supply"), title_size=40 + ), + right_axis=fch.ChartAxis(show_labels=False), + bottom_axis=fch.ChartAxis( + label_size=40, + labels=[ + fch.ChartAxisLabel( + value=0, label=ft.Container(ft.Text("Apple"), padding=10) + ), + fch.ChartAxisLabel( + value=1, + label=ft.Container(ft.Text("Blueberry"), padding=10), + ), + fch.ChartAxisLabel( + value=2, label=ft.Container(ft.Text("Cherry"), padding=10) + ), + fch.ChartAxisLabel( + value=3, label=ft.Container(ft.Text("Orange"), padding=10) + ), + ], + ), + groups=[ + fch.BarChartGroup( + x=0, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=40, + width=40, + color=ft.Colors.GREEN, + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=1, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=100, + width=40, + color=ft.Colors.BLUE, + tooltip=fch.BarChartRodTooltip("Blueberry"), + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=2, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=30, + width=40, + color=ft.Colors.RED, + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=3, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=60, + width=40, + color=ft.Colors.ORANGE, + tooltip=fch.BarChartRodTooltip("Orange"), + border_radius=0, + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/charts/bar_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/bar_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..8f76340010 --- /dev/null +++ b/sdk/python/examples/controls/charts/bar_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-bar-chart-example-1" +version = "1.0.0" +description = "Example 1 example for bar chart." +requires-python = ">=3.10" +keywords = ["charts", "bar-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/BarChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "BarChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/bar_chart/example_2.py b/sdk/python/examples/controls/charts/bar_chart/example_2/main.py similarity index 91% rename from sdk/python/examples/controls/charts/bar_chart/example_2.py rename to sdk/python/examples/controls/charts/bar_chart/example_2/main.py index 56f275005f..c03f535fd5 100644 --- a/sdk/python/examples/controls/charts/bar_chart/example_2.py +++ b/sdk/python/examples/controls/charts/bar_chart/example_2/main.py @@ -1,6 +1,5 @@ -import flet_charts as fch - import flet as ft +import flet_charts as fch class CustomRod(fch.BarChartRod): @@ -60,12 +59,14 @@ def on_chart_event(e: fch.BarChartEvent): ) page.add( - ft.Container( - content=chart, - bgcolor=ft.Colors.GREEN_200, - padding=10, - border_radius=5, - expand=True, + ft.SafeArea( + content=ft.Container( + bgcolor=ft.Colors.GREEN_200, + padding=10, + border_radius=5, + expand=True, + content=chart, + ), ) ) diff --git a/sdk/python/examples/controls/charts/bar_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/bar_chart/example_2/pyproject.toml new file mode 100644 index 0000000000..57fa23cd64 --- /dev/null +++ b/sdk/python/examples/controls/charts/bar_chart/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-bar-chart-example-2" +version = "1.0.0" +description = "Example 2 example for bar chart." +requires-python = ">=3.10" +keywords = ["charts", "bar-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/BarChart"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "BarChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/candlestick_chart/__init__.py b/sdk/python/examples/controls/charts/candlestick_chart/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/charts/candlestick_chart/example_1.py b/sdk/python/examples/controls/charts/candlestick_chart/example_1/main.py similarity index 86% rename from sdk/python/examples/controls/charts/candlestick_chart/example_1.py rename to sdk/python/examples/controls/charts/candlestick_chart/example_1/main.py index 21e631dd81..342be7df31 100644 --- a/sdk/python/examples/controls/charts/candlestick_chart/example_1.py +++ b/sdk/python/examples/controls/charts/candlestick_chart/example_1/main.py @@ -103,22 +103,24 @@ def handle_event(e: fch.CandlestickChartEvent): ) page.add( - ft.Container( - expand=True, - border_radius=16, - padding=20, - content=ft.Column( + ft.SafeArea( + content=ft.Container( expand=True, - spacing=20, - controls=[ - ft.Text( - "Weekly OHLC snapshot (demo data)", - size=20, - weight=ft.FontWeight.BOLD, - ), - chart, - info, - ], + border_radius=16, + padding=20, + content=ft.Column( + expand=True, + spacing=20, + controls=[ + ft.Text( + "Weekly OHLC snapshot (demo data)", + size=20, + weight=ft.FontWeight.BOLD, + ), + chart, + info, + ], + ), ), ) ) diff --git a/sdk/python/examples/controls/charts/candlestick_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/candlestick_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..e45e36c6e8 --- /dev/null +++ b/sdk/python/examples/controls/charts/candlestick_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-candlestick-chart-example-1" +version = "1.0.0" +description = "Example 1 example for candlestick chart." +requires-python = ">=3.10" +keywords = ["charts", "candlestick-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/CandlestickChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "CandlestickChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/line_chart/__init__.py b/sdk/python/examples/controls/charts/line_chart/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/charts/line_chart/dashboard_declarative.py b/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/main.py similarity index 60% rename from sdk/python/examples/controls/charts/line_chart/dashboard_declarative.py rename to sdk/python/examples/controls/charts/line_chart/dashboard_declarative/main.py index 20f7481e19..88dda9002d 100644 --- a/sdk/python/examples/controls/charts/line_chart/dashboard_declarative.py +++ b/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/main.py @@ -92,46 +92,53 @@ async def generate_chart_data(): @ft.component def App(): - return ft.Row( - controls=[ - ft.Column( - [ - ft.Text("CPU Usage"), - Gauge( - min_y=0.3, - max_y=1.0, - line_color=ft.Colors.BLUE, - bgcolor=ft.Colors.BLUE_100, - ), - ], - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - ), - ft.Column( - [ - ft.Text("Memory Usage"), - Gauge( - min_y=0.2, - max_y=0.5, - line_color=ft.Colors.GREEN, - bgcolor=ft.Colors.GREEN_100, - ), - ], - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - ), - ft.Column( - [ - ft.Text("Disk Usage"), - Gauge( - min_y=0.7, - max_y=0.9, - line_color=ft.Colors.ORANGE, - bgcolor=ft.Colors.ORANGE_100, - ), - ], - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - ), - ] + return ft.SafeArea( + content=ft.Row( + controls=[ + ft.Column( + [ + ft.Text("CPU Usage"), + Gauge( + min_y=0.3, + max_y=1.0, + line_color=ft.Colors.BLUE, + bgcolor=ft.Colors.BLUE_100, + ), + ], + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ), + ft.Column( + [ + ft.Text("Memory Usage"), + Gauge( + min_y=0.2, + max_y=0.5, + line_color=ft.Colors.GREEN, + bgcolor=ft.Colors.GREEN_100, + ), + ], + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ), + ft.Column( + [ + ft.Text("Disk Usage"), + Gauge( + min_y=0.7, + max_y=0.9, + line_color=ft.Colors.ORANGE, + bgcolor=ft.Colors.ORANGE_100, + ), + ], + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ), + ] + ), ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/pyproject.toml b/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/pyproject.toml new file mode 100644 index 0000000000..bdf3dac8dc --- /dev/null +++ b/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-line-chart-dashboard-declarative" +version = "1.0.0" +description = "Dashboard Declarative example for line chart." +requires-python = ">=3.10" +keywords = ["charts", "line-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/LineChart"] + +[tool.flet.metadata] +title = "Dashboard Declarative" +controls = ["SafeArea", "LineChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/line_chart/example_1.py b/sdk/python/examples/controls/charts/line_chart/example_1/main.py similarity index 96% rename from sdk/python/examples/controls/charts/line_chart/example_1.py rename to sdk/python/examples/controls/charts/line_chart/example_1/main.py index 9a4734c203..5721e35204 100644 --- a/sdk/python/examples/controls/charts/line_chart/example_1.py +++ b/sdk/python/examples/controls/charts/line_chart/example_1/main.py @@ -1,6 +1,5 @@ -import flet_charts as fch - import flet as ft +import flet_charts as fch class State: @@ -200,7 +199,16 @@ def toggle_data(e: ft.Event[ft.IconButton]): state.toggled = not state.toggled chart.update() - page.add(ft.IconButton(ft.Icons.REFRESH, on_click=toggle_data), chart) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.IconButton(ft.Icons.REFRESH, on_click=toggle_data), + chart, + ] + ), + ) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/line_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/line_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..9bfd936080 --- /dev/null +++ b/sdk/python/examples/controls/charts/line_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-line-chart-example-1" +version = "1.0.0" +description = "Example 1 example for line chart." +requires-python = ">=3.10" +keywords = ["charts", "line-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/LineChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "LineChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/line_chart/example_2.py b/sdk/python/examples/controls/charts/line_chart/example_2/main.py similarity index 95% rename from sdk/python/examples/controls/charts/line_chart/example_2.py rename to sdk/python/examples/controls/charts/line_chart/example_2/main.py index e541023cc2..e4dffef422 100644 --- a/sdk/python/examples/controls/charts/line_chart/example_2.py +++ b/sdk/python/examples/controls/charts/line_chart/example_2/main.py @@ -133,7 +133,16 @@ def toggle_data(e: ft.Event[ft.ElevatedButton]): state.toggled = not state.toggled chart.update() - page.add(ft.Button("avg", on_click=toggle_data), chart) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button("avg", on_click=toggle_data), + chart, + ] + ), + ) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/line_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/line_chart/example_2/pyproject.toml new file mode 100644 index 0000000000..921a1b979a --- /dev/null +++ b/sdk/python/examples/controls/charts/line_chart/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-line-chart-example-2" +version = "1.0.0" +description = "Example 2 example for line chart." +requires-python = ">=3.10" +keywords = ["charts", "line-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/LineChart"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "LineChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/__init__.py b/sdk/python/examples/controls/charts/matplotlib_chart/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/animate.py b/sdk/python/examples/controls/charts/matplotlib_chart/animate/main.py similarity index 91% rename from sdk/python/examples/controls/charts/matplotlib_chart/animate.py rename to sdk/python/examples/controls/charts/matplotlib_chart/animate/main.py index 87cdebeb8d..c13eb2ab9a 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/animate.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/animate/main.py @@ -50,7 +50,11 @@ def update_lines(num, walks, lines): fig, update_lines, num_steps, fargs=(walks, lines), interval=100 ) - page.add(flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True)) + page.add( + ft.SafeArea( + content=flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True), + ) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml new file mode 100644 index 0000000000..b14be396eb --- /dev/null +++ b/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-animate" +version = "1.0.0" +description = "Animate example for matplotlib chart." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Animate" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart.py b/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/main.py similarity index 87% rename from sdk/python/examples/controls/charts/matplotlib_chart/bar_chart.py rename to sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/main.py index b0fb23e225..4ba83e805a 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/main.py @@ -18,7 +18,7 @@ def main(page: ft.Page): ax.set_title("Fruit supply by kind and color") ax.legend(title="Fruit color") - page.add(fch.MatplotlibChart(figure=fig, expand=True)) + page.add(ft.SafeArea(content=fch.MatplotlibChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/pyproject.toml new file mode 100644 index 0000000000..9fcf495fb6 --- /dev/null +++ b/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-bar-chart" +version = "1.0.0" +description = "Bar Chart example for matplotlib chart." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Bar Chart" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events.py b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/main.py similarity index 95% rename from sdk/python/examples/controls/charts/matplotlib_chart/handle_events.py rename to sdk/python/examples/controls/charts/matplotlib_chart/handle_events/main.py index 499d645f7f..312f439ab9 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/main.py @@ -97,7 +97,11 @@ def update(self): # plt.show() - page.add(fch.MatplotlibChartWithToolbar(figure=fig, expand=True)) + page.add( + ft.SafeArea( + content=fch.MatplotlibChartWithToolbar(figure=fig, expand=True), + ) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml new file mode 100644 index 0000000000..363e078c54 --- /dev/null +++ b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-handle-events" +version = "1.0.0" +description = "Handle Events example for matplotlib chart." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Handle Events" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/three_d.py b/sdk/python/examples/controls/charts/matplotlib_chart/three_d/main.py similarity index 90% rename from sdk/python/examples/controls/charts/matplotlib_chart/three_d.py rename to sdk/python/examples/controls/charts/matplotlib_chart/three_d/main.py index 214318b08f..402c6e6e76 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/three_d.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/three_d/main.py @@ -30,7 +30,7 @@ def main(page: ft.Page): ax.set(xticklabels=[], yticklabels=[], zticklabels=[]) - page.add(flet_charts.MatplotlibChartWithToolbar(figure=fig)) + page.add(ft.SafeArea(content=flet_charts.MatplotlibChartWithToolbar(figure=fig))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml new file mode 100644 index 0000000000..6e7d598a36 --- /dev/null +++ b/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-three-d" +version = "1.0.0" +description = "Three D example for matplotlib chart." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Three D" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar.py b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/main.py similarity index 86% rename from sdk/python/examples/controls/charts/matplotlib_chart/toolbar.py rename to sdk/python/examples/controls/charts/matplotlib_chart/toolbar/main.py index d58c1ead61..8df1482594 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/main.py @@ -30,7 +30,11 @@ def main(page: ft.Page): fig.tight_layout() - page.add(fch.MatplotlibChartWithToolbar(figure=fig, expand=True)) + page.add( + ft.SafeArea( + content=fch.MatplotlibChartWithToolbar(figure=fig, expand=True), + ) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml new file mode 100644 index 0000000000..b2757cefdd --- /dev/null +++ b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-toolbar" +version = "1.0.0" +description = "Toolbar example for matplotlib chart." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Toolbar" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/pie_chart/__init__.py b/sdk/python/examples/controls/charts/pie_chart/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/charts/pie_chart/example_1.py b/sdk/python/examples/controls/charts/pie_chart/example_1/main.py similarity index 97% rename from sdk/python/examples/controls/charts/pie_chart/example_1.py rename to sdk/python/examples/controls/charts/pie_chart/example_1/main.py index 8f84c472b0..dd909aa49b 100644 --- a/sdk/python/examples/controls/charts/pie_chart/example_1.py +++ b/sdk/python/examples/controls/charts/pie_chart/example_1/main.py @@ -1,6 +1,5 @@ -import flet_charts as fch - import flet as ft +import flet_charts as fch def main(page: ft.Page): @@ -47,7 +46,7 @@ def on_chart_event(e: fch.PieChartEvent): ], ) - page.add(chart) + page.add(ft.SafeArea(content=chart)) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/pie_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/pie_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..d91af3d01c --- /dev/null +++ b/sdk/python/examples/controls/charts/pie_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-pie-chart-example-1" +version = "1.0.0" +description = "Example 1 example for pie chart." +requires-python = ">=3.10" +keywords = ["charts", "pie-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PieChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "PieChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/pie_chart/example_2.py b/sdk/python/examples/controls/charts/pie_chart/example_2/main.py similarity index 97% rename from sdk/python/examples/controls/charts/pie_chart/example_2.py rename to sdk/python/examples/controls/charts/pie_chart/example_2/main.py index 97701fb3ac..fc58e9be39 100644 --- a/sdk/python/examples/controls/charts/pie_chart/example_2.py +++ b/sdk/python/examples/controls/charts/pie_chart/example_2/main.py @@ -62,7 +62,7 @@ def on_chart_event(e: fch.PieChartEvent): ], ) - page.add(chart) + page.add(ft.SafeArea(content=chart)) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/pie_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/pie_chart/example_2/pyproject.toml new file mode 100644 index 0000000000..43259d6eee --- /dev/null +++ b/sdk/python/examples/controls/charts/pie_chart/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-pie-chart-example-2" +version = "1.0.0" +description = "Example 2 example for pie chart." +requires-python = ">=3.10" +keywords = ["charts", "pie-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PieChart"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "PieChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/pie_chart/example_3.py b/sdk/python/examples/controls/charts/pie_chart/example_3/main.py similarity index 98% rename from sdk/python/examples/controls/charts/pie_chart/example_3.py rename to sdk/python/examples/controls/charts/pie_chart/example_3/main.py index 38d649e74a..6f4c0b204c 100644 --- a/sdk/python/examples/controls/charts/pie_chart/example_3.py +++ b/sdk/python/examples/controls/charts/pie_chart/example_3/main.py @@ -84,7 +84,7 @@ def on_chart_event(e: fch.PieChartEvent): ], ) - page.add(chart) + page.add(ft.SafeArea(content=chart)) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/pie_chart/example_3/pyproject.toml b/sdk/python/examples/controls/charts/pie_chart/example_3/pyproject.toml new file mode 100644 index 0000000000..7cb9b249e7 --- /dev/null +++ b/sdk/python/examples/controls/charts/pie_chart/example_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-pie-chart-example-3" +version = "1.0.0" +description = "Example 3 example for pie chart." +requires-python = ">=3.10" +keywords = ["charts", "pie-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PieChart"] + +[tool.flet.metadata] +title = "Example 3" +controls = ["SafeArea", "PieChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/plotly_chart/__init__.py b/sdk/python/examples/controls/charts/plotly_chart/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_1.py b/sdk/python/examples/controls/charts/plotly_chart/example_1/main.py similarity index 77% rename from sdk/python/examples/controls/charts/plotly_chart/example_1.py rename to sdk/python/examples/controls/charts/plotly_chart/example_1/main.py index 1ac3d9ad1e..2354419df0 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_1.py +++ b/sdk/python/examples/controls/charts/plotly_chart/example_1/main.py @@ -1,14 +1,14 @@ -import flet_charts as fch import plotly.express as px import flet as ft +import flet_charts as fch def main(page: ft.Page): df = px.data.gapminder().query("continent=='Oceania'") fig = px.line(df, x="year", y="lifeExp", color="country") - page.add(fch.PlotlyChart(figure=fig, expand=True)) + page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..28a353be47 --- /dev/null +++ b/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-plotly-chart-example-1" +version = "1.0.0" +description = "Example 1 example for plotly chart." +requires-python = ">=3.10" +keywords = ["charts", "plotly-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "plotly"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PlotlyChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "PlotlyChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_2.py b/sdk/python/examples/controls/charts/plotly_chart/example_2/main.py similarity index 84% rename from sdk/python/examples/controls/charts/plotly_chart/example_2.py rename to sdk/python/examples/controls/charts/plotly_chart/example_2/main.py index 0060b1b67b..663b3c9099 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_2.py +++ b/sdk/python/examples/controls/charts/plotly_chart/example_2/main.py @@ -1,7 +1,7 @@ -import flet_charts as fch import plotly.express as px import flet as ft +import flet_charts as fch def main(page: ft.Page): @@ -16,7 +16,7 @@ def main(page: ft.Page): height=400, ) - page.add(fch.PlotlyChart(figure=fig, expand=True)) + page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml new file mode 100644 index 0000000000..cdba52b77f --- /dev/null +++ b/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-plotly-chart-example-2" +version = "1.0.0" +description = "Example 2 example for plotly chart." +requires-python = ">=3.10" +keywords = ["charts", "plotly-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "plotly"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PlotlyChart"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "PlotlyChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_3.py b/sdk/python/examples/controls/charts/plotly_chart/example_3/main.py similarity index 80% rename from sdk/python/examples/controls/charts/plotly_chart/example_3.py rename to sdk/python/examples/controls/charts/plotly_chart/example_3/main.py index 436bf87f24..0f28b067fd 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_3.py +++ b/sdk/python/examples/controls/charts/plotly_chart/example_3/main.py @@ -1,7 +1,7 @@ -import flet_charts as fch import plotly.graph_objects as go import flet as ft +import flet_charts as fch def main(page: ft.Page): @@ -10,7 +10,7 @@ def main(page: ft.Page): fig = go.Figure(data=[go.Pie(labels=labels, values=values)]) - page.add(fch.PlotlyChart(figure=fig, expand=True)) + page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml new file mode 100644 index 0000000000..a0c4b5bb4c --- /dev/null +++ b/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-plotly-chart-example-3" +version = "1.0.0" +description = "Example 3 example for plotly chart." +requires-python = ">=3.10" +keywords = ["charts", "plotly-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "plotly"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PlotlyChart"] + +[tool.flet.metadata] +title = "Example 3" +controls = ["SafeArea", "PlotlyChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_4.py b/sdk/python/examples/controls/charts/plotly_chart/example_4/main.py similarity index 93% rename from sdk/python/examples/controls/charts/plotly_chart/example_4.py rename to sdk/python/examples/controls/charts/plotly_chart/example_4/main.py index 9fdf998721..9f50698e45 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_4.py +++ b/sdk/python/examples/controls/charts/plotly_chart/example_4/main.py @@ -1,7 +1,7 @@ -import flet_charts as fch import plotly.graph_objects as go import flet as ft +import flet_charts as fch def main(page: ft.Page): @@ -52,7 +52,7 @@ def main(page: ft.Page): boxmode="group", # group together boxes of the different traces ) - page.add(fch.PlotlyChart(figure=fig, expand=True)) + page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml new file mode 100644 index 0000000000..7bb4ad12db --- /dev/null +++ b/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-plotly-chart-example-4" +version = "1.0.0" +description = "Example 4 example for plotly chart." +requires-python = ">=3.10" +keywords = ["charts", "plotly-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "plotly"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PlotlyChart"] + +[tool.flet.metadata] +title = "Example 4" +controls = ["SafeArea", "PlotlyChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/radar_chart/__init__.py b/sdk/python/examples/controls/charts/radar_chart/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/charts/radar_chart/example_1.py b/sdk/python/examples/controls/charts/radar_chart/example_1.py deleted file mode 100644 index 454c15b844..0000000000 --- a/sdk/python/examples/controls/charts/radar_chart/example_1.py +++ /dev/null @@ -1,61 +0,0 @@ -import flet as ft -import flet_charts as fch - - -def main(page: ft.Page): - page.title = "Radar chart" - page.padding = 20 - # page.vertical_alignment = page.horizontal_alignment = "center" - page.theme_mode = ft.ThemeMode.LIGHT - - categories = ["macOS", "Linux", "Windows"] - - page.add( - fch.RadarChart( - expand=True, - titles=[fch.RadarChartTitle(text=label) for label in categories], - center_min_value=True, - tick_count=4, - ticks_text_style=ft.TextStyle(size=20, color=ft.Colors.ON_SURFACE), - title_text_style=ft.TextStyle( - size=24, weight=ft.FontWeight.BOLD, color=ft.Colors.ON_SURFACE - ), - on_event=lambda e: print(e.type), - data_sets=[ - fch.RadarDataSet( - fill_color=ft.Colors.with_opacity(0.2, ft.Colors.DEEP_PURPLE), - border_color=ft.Colors.DEEP_PURPLE, - entry_radius=4, - entries=[ - fch.RadarDataSetEntry(300), - fch.RadarDataSetEntry(50), - fch.RadarDataSetEntry(250), - ], - ), - fch.RadarDataSet( - fill_color=ft.Colors.with_opacity(0.15, ft.Colors.PINK), - border_color=ft.Colors.PINK, - entry_radius=4, - entries=[ - fch.RadarDataSetEntry(250), - fch.RadarDataSetEntry(100), - fch.RadarDataSetEntry(200), - ], - ), - fch.RadarDataSet( - fill_color=ft.Colors.with_opacity(0.12, ft.Colors.CYAN), - border_color=ft.Colors.CYAN, - entry_radius=4, - entries=[ - fch.RadarDataSetEntry(200), - fch.RadarDataSetEntry(150), - fch.RadarDataSetEntry(50), - ], - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/charts/radar_chart/example_1/main.py b/sdk/python/examples/controls/charts/radar_chart/example_1/main.py new file mode 100644 index 0000000000..4cefb9815a --- /dev/null +++ b/sdk/python/examples/controls/charts/radar_chart/example_1/main.py @@ -0,0 +1,63 @@ +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + page.title = "Radar chart" + page.padding = 20 + # page.vertical_alignment = page.horizontal_alignment = "center" + page.theme_mode = ft.ThemeMode.LIGHT + + categories = ["macOS", "Linux", "Windows"] + + page.add( + ft.SafeArea( + content=fch.RadarChart( + expand=True, + titles=[fch.RadarChartTitle(text=label) for label in categories], + center_min_value=True, + tick_count=4, + ticks_text_style=ft.TextStyle(size=20, color=ft.Colors.ON_SURFACE), + title_text_style=ft.TextStyle( + size=24, weight=ft.FontWeight.BOLD, color=ft.Colors.ON_SURFACE + ), + on_event=lambda e: print(e.type), + data_sets=[ + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.2, ft.Colors.DEEP_PURPLE), + border_color=ft.Colors.DEEP_PURPLE, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(300), + fch.RadarDataSetEntry(50), + fch.RadarDataSetEntry(250), + ], + ), + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.15, ft.Colors.PINK), + border_color=ft.Colors.PINK, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(250), + fch.RadarDataSetEntry(100), + fch.RadarDataSetEntry(200), + ], + ), + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.12, ft.Colors.CYAN), + border_color=ft.Colors.CYAN, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(200), + fch.RadarDataSetEntry(150), + fch.RadarDataSetEntry(50), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/charts/radar_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/radar_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..c67a9e9179 --- /dev/null +++ b/sdk/python/examples/controls/charts/radar_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-radar-chart-example-1" +version = "1.0.0" +description = "Example 1 example for radar chart." +requires-python = ">=3.10" +keywords = ["charts", "radar-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/RadarChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "RadarChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/charts/scatter_chart/__init__.py b/sdk/python/examples/controls/charts/scatter_chart/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/charts/scatter_chart/example_1.py b/sdk/python/examples/controls/charts/scatter_chart/example_1/main.py similarity index 70% rename from sdk/python/examples/controls/charts/scatter_chart/example_1.py rename to sdk/python/examples/controls/charts/scatter_chart/example_1/main.py index e3ed0c76cc..8b6faa3d45 100644 --- a/sdk/python/examples/controls/charts/scatter_chart/example_1.py +++ b/sdk/python/examples/controls/charts/scatter_chart/example_1/main.py @@ -132,27 +132,34 @@ def handle_event(e: fch.ScatterChartEvent): ) page.add( - ft.Text( - "Tap on the chart to toggle between random spots and Flutter logo spots." - ), - fch.ScatterChart( - expand=True, - aspect_ratio=1.0, - min_x=0.0, - max_x=50.0, - min_y=0.0, - max_y=50.0, - left_axis=fch.ChartAxis(show_labels=False), - right_axis=fch.ChartAxis(show_labels=False), - top_axis=fch.ChartAxis(show_labels=False), - bottom_axis=fch.ChartAxis(show_labels=False), - show_tooltips_for_selected_spots_only=False, - on_event=handle_event, - animation=ft.Animation( - duration=ft.Duration(milliseconds=600), - curve=ft.AnimationCurve.FAST_OUT_SLOWIN, + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Tap on the chart to toggle between random spots and Flutter " + "logo spots." + ), + fch.ScatterChart( + expand=True, + aspect_ratio=1.0, + min_x=0.0, + max_x=50.0, + min_y=0.0, + max_y=50.0, + left_axis=fch.ChartAxis(show_labels=False), + right_axis=fch.ChartAxis(show_labels=False), + top_axis=fch.ChartAxis(show_labels=False), + bottom_axis=fch.ChartAxis(show_labels=False), + show_tooltips_for_selected_spots_only=False, + on_event=handle_event, + animation=ft.Animation( + duration=ft.Duration(milliseconds=600), + curve=ft.AnimationCurve.FAST_OUT_SLOWIN, + ), + spots=flutter_logo_spots, + ), + ], ), - spots=flutter_logo_spots, ), ) diff --git a/sdk/python/examples/controls/charts/scatter_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/scatter_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..287a01048f --- /dev/null +++ b/sdk/python/examples/controls/charts/scatter_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-scatter-chart-example-1" +version = "1.0.0" +description = "Example 1 example for scatter chart." +requires-python = ">=3.10" +keywords = ["charts", "scatter-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/ScatterChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "ScatterChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/charts/barchart.md b/sdk/python/packages/flet/docs/charts/barchart.md index 015d390ec1..d09db6f1a7 100644 --- a/sdk/python/packages/flet/docs/charts/barchart.md +++ b/sdk/python/packages/flet/docs/charts/barchart.md @@ -12,7 +12,7 @@ diagram: assets/bar-chart-diagram.svg ### Example 1 ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.png", width="80%") }} @@ -20,7 +20,7 @@ diagram: assets/bar-chart-diagram.svg ### Example 2 ```python ---8<-- "{{ examples }}/example_2.py" +--8<-- "{{ examples }}/example_2/main.py" ``` {{ image(example_images + "/example_2.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/charts/candlestickchart.md b/sdk/python/packages/flet/docs/charts/candlestickchart.md index 1784c561f2..a74ae51e93 100644 --- a/sdk/python/packages/flet/docs/charts/candlestickchart.md +++ b/sdk/python/packages/flet/docs/charts/candlestickchart.md @@ -11,7 +11,7 @@ example_images: ../test-images-charts/examples/golden/macos/candlestick_chart ### Basic Candlestick Chart ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/charts/linechart.md b/sdk/python/packages/flet/docs/charts/linechart.md index f8bfbd0205..5418b48e38 100644 --- a/sdk/python/packages/flet/docs/charts/linechart.md +++ b/sdk/python/packages/flet/docs/charts/linechart.md @@ -12,7 +12,7 @@ diagram: assets/line-chart-diagram.svg ### Example 1 ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.png", width="80%") }} @@ -20,7 +20,7 @@ diagram: assets/line-chart-diagram.svg ### Example 2 ```python ---8<-- "{{ examples }}/example_2.py" +--8<-- "{{ examples }}/example_2/main.py" ``` {{ image(example_images + "/example_2.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/charts/matplotlibchart.md b/sdk/python/packages/flet/docs/charts/matplotlibchart.md index 5a295172b0..fe75709286 100644 --- a/sdk/python/packages/flet/docs/charts/matplotlibchart.md +++ b/sdk/python/packages/flet/docs/charts/matplotlibchart.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/charts/matplotlib_chart/media Based on an official [Matplotlib example](https://matplotlib.org/stable/gallery/lines_bars_and_markers/bar_colors.html#sphx-glr-gallery-lines-bars-and-markers-bar-colors-py). ```python ---8<-- "{{ examples }}/bar_chart.py" +--8<-- "{{ examples }}/bar_chart/main.py" ``` {{ image(example_images + "/bar_chart.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/charts/matplotlibchartwithtoolbar.md b/sdk/python/packages/flet/docs/charts/matplotlibchartwithtoolbar.md index 13759dc822..262ad9ed9c 100644 --- a/sdk/python/packages/flet/docs/charts/matplotlibchartwithtoolbar.md +++ b/sdk/python/packages/flet/docs/charts/matplotlibchartwithtoolbar.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/charts/matplotlib_chart/media Based on an official [Matplotlib example](https://matplotlib.org/stable/gallery/lines_bars_and_markers/cohere.html#sphx-glr-gallery-lines-bars-and-markers-cohere-py). ```python ---8<-- "{{ examples }}/toolbar.py" +--8<-- "{{ examples }}/toolbar/main.py" ``` {{ image(example_images + "/toolbar.png", width="80%") }} @@ -22,7 +22,7 @@ Based on an official [Matplotlib example](https://matplotlib.org/stable/gallery/ ### 3D chart ```python ---8<-- "{{ examples }}/three_d.py" +--8<-- "{{ examples }}/three_d/main.py" ``` {{ image(example_images + "/three_d.png", width="80%") }} @@ -30,7 +30,7 @@ Based on an official [Matplotlib example](https://matplotlib.org/stable/gallery/ ### Handle events ```python ---8<-- "{{ examples }}/handle_events.py" +--8<-- "{{ examples }}/handle_events/main.py" ``` {{ image(example_images + "/handle_events.png", width="80%") }} @@ -38,7 +38,7 @@ Based on an official [Matplotlib example](https://matplotlib.org/stable/gallery/ ### Animated chart ```python ---8<-- "{{ examples }}/animate.py" +--8<-- "{{ examples }}/animate/main.py" ``` {{ image(example_media + "/animate.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/charts/piechart.md b/sdk/python/packages/flet/docs/charts/piechart.md index d0976a1356..bc4a849c73 100644 --- a/sdk/python/packages/flet/docs/charts/piechart.md +++ b/sdk/python/packages/flet/docs/charts/piechart.md @@ -12,7 +12,7 @@ diagram: assets/pie-chart-diagram.svg ### Example 1 ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.png", width="80%") }} @@ -20,7 +20,7 @@ diagram: assets/pie-chart-diagram.svg ### Example 2 ```python ---8<-- "{{ examples }}/example_2.py" +--8<-- "{{ examples }}/example_2/main.py" ``` {{ image(example_images + "/example_2.png", width="80%") }} @@ -28,7 +28,7 @@ diagram: assets/pie-chart-diagram.svg ### Example 3 ```python ---8<-- "{{ examples }}/example_3.py" +--8<-- "{{ examples }}/example_3/main.py" ``` {{ image(example_images + "/example_3.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/charts/plotlychart.md b/sdk/python/packages/flet/docs/charts/plotlychart.md index ee67751676..99a2849704 100644 --- a/sdk/python/packages/flet/docs/charts/plotlychart.md +++ b/sdk/python/packages/flet/docs/charts/plotlychart.md @@ -13,7 +13,7 @@ example_images: ../test-images-charts/examples/golden/macos/plotly_chart Based on an official [Plotly example](https://plotly.com/python/line-charts). ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.png", width="80%") }} @@ -23,7 +23,7 @@ Based on an official [Plotly example](https://plotly.com/python/line-charts). Based on an official [Plotly example](https://plotly.com/python/bar-charts). ```python ---8<-- "{{ examples }}/example_2.py" +--8<-- "{{ examples }}/example_2/main.py" ``` {{ image(example_images + "/example_2.png", width="80%") }} @@ -33,7 +33,7 @@ Based on an official [Plotly example](https://plotly.com/python/bar-charts). Based on an official [Plotly example](https://plotly.com/python/pie-charts). ```python ---8<-- "{{ examples }}/example_3.py" +--8<-- "{{ examples }}/example_3/main.py" ``` {{ image(example_images + "/example_3.png", width="80%") }} @@ -43,7 +43,7 @@ Based on an official [Plotly example](https://plotly.com/python/pie-charts). Based on an official [Plotly example](https://plotly.com/python/box-plots). ```python ---8<-- "{{ examples }}/example_4.py" +--8<-- "{{ examples }}/example_4/main.py" ``` {{ image(example_images + "/example_4.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/charts/radarchart.md b/sdk/python/packages/flet/docs/charts/radarchart.md index 04c50c3d90..2c615cc8b4 100644 --- a/sdk/python/packages/flet/docs/charts/radarchart.md +++ b/sdk/python/packages/flet/docs/charts/radarchart.md @@ -11,7 +11,7 @@ example_images: ../test-images-charts/examples/golden/macos/radar_chart ### Example 1 ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/charts/scatterchart.md b/sdk/python/packages/flet/docs/charts/scatterchart.md index 4f29b1a9dd..704d61b952 100644 --- a/sdk/python/packages/flet/docs/charts/scatterchart.md +++ b/sdk/python/packages/flet/docs/charts/scatterchart.md @@ -11,7 +11,7 @@ example_images: ../test-images-charts/examples/golden/macos/scatter_chart ### Basic Scatter Chart ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.png", width="80%") }} From 0210de9cd09b860552cd46f365f64123ada0a959 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 12:04:14 -0700 Subject: [PATCH 32/96] Update chart example pyproject descriptions Replace generic placeholder descriptions in multiple sdk/python/examples/*/pyproject.toml files with detailed, example-specific summaries (bar, candlestick, line, matplotlib variants, pie, plotly, radar, scatter). This improves package metadata and discoverability for the example packages; no functional changes to code. --- .../examples/controls/charts/bar_chart/example_1/pyproject.toml | 2 +- .../examples/controls/charts/bar_chart/example_2/pyproject.toml | 2 +- .../controls/charts/candlestick_chart/example_1/pyproject.toml | 2 +- .../charts/line_chart/dashboard_declarative/pyproject.toml | 2 +- .../controls/charts/line_chart/example_1/pyproject.toml | 2 +- .../controls/charts/line_chart/example_2/pyproject.toml | 2 +- .../controls/charts/matplotlib_chart/animate/pyproject.toml | 2 +- .../controls/charts/matplotlib_chart/bar_chart/pyproject.toml | 2 +- .../charts/matplotlib_chart/handle_events/pyproject.toml | 2 +- .../controls/charts/matplotlib_chart/three_d/pyproject.toml | 2 +- .../controls/charts/matplotlib_chart/toolbar/pyproject.toml | 2 +- .../examples/controls/charts/pie_chart/example_1/pyproject.toml | 2 +- .../examples/controls/charts/pie_chart/example_2/pyproject.toml | 2 +- .../examples/controls/charts/pie_chart/example_3/pyproject.toml | 2 +- .../controls/charts/plotly_chart/example_1/pyproject.toml | 2 +- .../controls/charts/plotly_chart/example_2/pyproject.toml | 2 +- .../controls/charts/plotly_chart/example_3/pyproject.toml | 2 +- .../controls/charts/plotly_chart/example_4/pyproject.toml | 2 +- .../controls/charts/radar_chart/example_1/pyproject.toml | 2 +- .../controls/charts/scatter_chart/example_1/pyproject.toml | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sdk/python/examples/controls/charts/bar_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/bar_chart/example_1/pyproject.toml index 8f76340010..4514c98701 100644 --- a/sdk/python/examples/controls/charts/bar_chart/example_1/pyproject.toml +++ b/sdk/python/examples/controls/charts/bar_chart/example_1/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-bar-chart-example-1" version = "1.0.0" -description = "Example 1 example for bar chart." +description = "Interactive bar chart showing fruit supply with custom axes, tooltips, and grid lines." requires-python = ">=3.10" keywords = ["charts", "bar-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/bar_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/bar_chart/example_2/pyproject.toml index 57fa23cd64..4a3b548b99 100644 --- a/sdk/python/examples/controls/charts/bar_chart/example_2/pyproject.toml +++ b/sdk/python/examples/controls/charts/bar_chart/example_2/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-bar-chart-example-2" version = "1.0.0" -description = "Example 2 example for bar chart." +description = "Bar chart with pointer-hover interaction that highlights individual rods dynamically." requires-python = ">=3.10" keywords = ["charts", "bar-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/candlestick_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/candlestick_chart/example_1/pyproject.toml index e45e36c6e8..cc4fe18069 100644 --- a/sdk/python/examples/controls/charts/candlestick_chart/example_1/pyproject.toml +++ b/sdk/python/examples/controls/charts/candlestick_chart/example_1/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-candlestick-chart-example-1" version = "1.0.0" -description = "Example 1 example for candlestick chart." +description = "Candlestick chart visualizing weekly OHLC data with labeled axes and event-driven tooltips." requires-python = ">=3.10" keywords = ["charts", "candlestick-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/pyproject.toml b/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/pyproject.toml index bdf3dac8dc..d73af835b5 100644 --- a/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/pyproject.toml +++ b/sdk/python/examples/controls/charts/line_chart/dashboard_declarative/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-line-chart-dashboard-declarative" version = "1.0.0" -description = "Dashboard Declarative example for line chart." +description = "Declarative dashboard with live-updating line chart gauges for CPU, memory, and disk usage." requires-python = ">=3.10" keywords = ["charts", "line-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/line_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/line_chart/example_1/pyproject.toml index 9bfd936080..54d4d14a4f 100644 --- a/sdk/python/examples/controls/charts/line_chart/example_1/pyproject.toml +++ b/sdk/python/examples/controls/charts/line_chart/example_1/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-line-chart-example-1" version = "1.0.0" -description = "Example 1 example for line chart." +description = "Interactive multi-series line chart that toggles between detailed and simplified datasets." requires-python = ">=3.10" keywords = ["charts", "line-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/line_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/line_chart/example_2/pyproject.toml index 921a1b979a..4cf6bc1838 100644 --- a/sdk/python/examples/controls/charts/line_chart/example_2/pyproject.toml +++ b/sdk/python/examples/controls/charts/line_chart/example_2/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-line-chart-example-2" version = "1.0.0" -description = "Example 2 example for line chart." +description = "Line chart with custom axis labels and button-triggered switching between trend and average views." requires-python = ">=3.10" keywords = ["charts", "line-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml index b14be396eb..de34e5d9ad 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-matplotlib-chart-animate" version = "1.0.0" -description = "Animate example for matplotlib chart." +description = "Animated 3D random-walk Matplotlib chart embedded in a Flet application." requires-python = ">=3.10" keywords = ["charts", "matplotlib-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/pyproject.toml index 9fcf495fb6..e926721e7c 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-matplotlib-chart-bar-chart" version = "1.0.0" -description = "Bar Chart example for matplotlib chart." +description = "Matplotlib bar chart example with categorical data, labels, and legend integration." requires-python = ">=3.10" keywords = ["charts", "matplotlib-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml index 363e078c54..ed925fe9cc 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-matplotlib-chart-handle-events" version = "1.0.0" -description = "Handle Events example for matplotlib chart." +description = "Matplotlib chart demonstrating pick and keyboard events to inspect selected data points." requires-python = ">=3.10" keywords = ["charts", "matplotlib-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml index 6e7d598a36..83a246a5b0 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-matplotlib-chart-three-d" version = "1.0.0" -description = "Three D example for matplotlib chart." +description = "Matplotlib 3D chart rendering a double-helix-style surface and line composition." requires-python = ">=3.10" keywords = ["charts", "matplotlib-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml index b2757cefdd..96d4384f29 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-matplotlib-chart-toolbar" version = "1.0.0" -description = "Toolbar example for matplotlib chart." +description = "Matplotlib chart with built-in toolbar for panning, zooming, and data exploration." requires-python = ">=3.10" keywords = ["charts", "matplotlib-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/pie_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/pie_chart/example_1/pyproject.toml index d91af3d01c..f47f2d8d92 100644 --- a/sdk/python/examples/controls/charts/pie_chart/example_1/pyproject.toml +++ b/sdk/python/examples/controls/charts/pie_chart/example_1/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-pie-chart-example-1" version = "1.0.0" -description = "Example 1 example for pie chart." +description = "Pie chart with hover-sensitive section borders for interactive emphasis." requires-python = ">=3.10" keywords = ["charts", "pie-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/pie_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/pie_chart/example_2/pyproject.toml index 43259d6eee..caa7187d66 100644 --- a/sdk/python/examples/controls/charts/pie_chart/example_2/pyproject.toml +++ b/sdk/python/examples/controls/charts/pie_chart/example_2/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-pie-chart-example-2" version = "1.0.0" -description = "Example 2 example for pie chart." +description = "Pie chart with interactive section radius and title styling on hover." requires-python = ">=3.10" keywords = ["charts", "pie-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/pie_chart/example_3/pyproject.toml b/sdk/python/examples/controls/charts/pie_chart/example_3/pyproject.toml index 7cb9b249e7..7501160de0 100644 --- a/sdk/python/examples/controls/charts/pie_chart/example_3/pyproject.toml +++ b/sdk/python/examples/controls/charts/pie_chart/example_3/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-pie-chart-example-3" version = "1.0.0" -description = "Example 3 example for pie chart." +description = "Pie chart with icon badges and animated section highlighting based on pointer events." requires-python = ">=3.10" keywords = ["charts", "pie-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml index 28a353be47..21d87632b8 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml +++ b/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-plotly-chart-example-1" version = "1.0.0" -description = "Example 1 example for plotly chart." +description = "Plotly line chart showing life expectancy trends by country in Oceania." requires-python = ">=3.10" keywords = ["charts", "plotly-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml index cdba52b77f..7312c55bd9 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml +++ b/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-plotly-chart-example-2" version = "1.0.0" -description = "Example 2 example for plotly chart." +description = "Plotly bar chart comparing population with additional hover metrics by country and year." requires-python = ">=3.10" keywords = ["charts", "plotly-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml index a0c4b5bb4c..d7e04aff90 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml +++ b/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-plotly-chart-example-3" version = "1.0.0" -description = "Example 3 example for plotly chart." +description = "Plotly pie chart example for categorical distribution visualization." requires-python = ">=3.10" keywords = ["charts", "plotly-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml index 7bb4ad12db..c50ba380ff 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml +++ b/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-plotly-chart-example-4" version = "1.0.0" -description = "Example 4 example for plotly chart." +description = "Plotly grouped box plot comparing moisture distributions across categories." requires-python = ">=3.10" keywords = ["charts", "plotly-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/radar_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/radar_chart/example_1/pyproject.toml index c67a9e9179..cafd659afa 100644 --- a/sdk/python/examples/controls/charts/radar_chart/example_1/pyproject.toml +++ b/sdk/python/examples/controls/charts/radar_chart/example_1/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-radar-chart-example-1" version = "1.0.0" -description = "Example 1 example for radar chart." +description = "Radar chart comparing platform values across multiple datasets with styled titles and ticks." requires-python = ">=3.10" keywords = ["charts", "radar-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] diff --git a/sdk/python/examples/controls/charts/scatter_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/scatter_chart/example_1/pyproject.toml index 287a01048f..a3478064b4 100644 --- a/sdk/python/examples/controls/charts/scatter_chart/example_1/pyproject.toml +++ b/sdk/python/examples/controls/charts/scatter_chart/example_1/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "charts-scatter-chart-example-1" version = "1.0.0" -description = "Example 1 example for scatter chart." +description = "Scatter chart that toggles between random spots and a Flutter-logo point pattern on tap." requires-python = ">=3.10" keywords = ["charts", "scatter-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] From 2449af054142536ffec995f76e8c85b1feb086a6 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 12:06:19 -0700 Subject: [PATCH 33/96] Require meaningful example project descriptions Update example guidelines to mandate that each example's [project].description is specific and meaningful (avoid placeholders like "Example N" or " example"). Clarify that descriptions should state the concrete behavior or interaction demonstrated (e.g., hover highlight, live updates) and add a note to verify pyproject.toml contains such an example-specific description. --- .codex/skills/create-flet-example-projects/SKILL.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 76b435a28a..7284f52ef1 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -50,6 +50,8 @@ Ensure each runnable example is a standalone project containing: 4. Infer metadata. - Title: readable version of file/folder intent. - Short description: one line of what the example demonstrates. +- `[project].description` must be meaningful and example-specific; avoid generic placeholders like "Example N" or " example for ". +- Description should mention the concrete behavior or interaction shown (for example: hover highlight, live updates, custom axes, event handling). - Categories: typically control-based, e.g. `Input/Chip`, plus optional `Apps/Basic controls`. - Tags: from control/topic/behavior words. - Controls used: list key controls from code. @@ -99,6 +101,7 @@ Ensure each runnable example is a standalone project containing: - Confirm all in-scope `main.py` files include both top-level `ft.SafeArea` wrapping and the `if __name__ == "__main__": ft.run(main)` entrypoint. - Confirm there are no unnecessary `page.update()` calls in in-scope examples (unless explicitly required by isolated-control or non-auto-update behavior). - Confirm no in-scope examples use `use_material3`. +- Confirm each in-scope `pyproject.toml` has a meaningful, example-specific `[project].description` (not generic or templated text). ## Code style From 4ffe63ef0829d43142944fc99281f4b4be100c85 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 14:13:39 -0700 Subject: [PATCH 34/96] Use SafeArea expand and add save-to-file feature Update docs and examples to use SafeArea expand only when needed and mark examples that support exporting. - .codex skill doc: mention adding "save to file" to [tool.flet.metadata].features when export is supported and advise using ft.SafeArea expand=True only when required for correct sizing. - Examples: add expand=True to top-level ft.SafeArea in matplotlib chart examples (animate, bar_chart, handle_events) to avoid layout/Infinity sizing issues. - Metadata: add "save to file" to pyproject.toml features for animate and handle_events examples. --- .codex/skills/create-flet-example-projects/SKILL.md | 8 ++++++++ .../controls/charts/matplotlib_chart/animate/main.py | 1 + .../charts/matplotlib_chart/animate/pyproject.toml | 2 +- .../controls/charts/matplotlib_chart/bar_chart/main.py | 7 ++++++- .../charts/matplotlib_chart/handle_events/main.py | 1 + .../charts/matplotlib_chart/handle_events/pyproject.toml | 2 +- 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 7284f52ef1..c6cf5c3357 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -58,6 +58,8 @@ Ensure each runnable example is a standalone project containing: - Layout pattern: choose closest practical value (e.g. `filter-bar`, `inline-actions`, `dashboard`, `list-detail`). - Complexity: `basic` unless logic/state/architecture is non-trivial. - Features: notable behaviors only (click handling, selection, async loading, drag-and-drop, etc.). +- If an example supports exporting or downloading output, include `"save to file"` in `[tool.flet.metadata].features`. + 5. Infer dependencies from imports. - Always include `flet` for standard examples. @@ -68,6 +70,8 @@ Ensure each runnable example is a standalone project containing: - If `ft.context.disable_auto_update()` is not used, do not add explicit `page.update()` unless strictly necessary. - Apply this `page.update()` rule to all examples in the touched folder (new, migrated, and already converted). - Wrap app content in `ft.SafeArea` so example renders correctly on mobile. +- Add `expand=True` to `ft.SafeArea` only when needed for correct layout/sizing (for example to avoid Infinity/NaN sizing issues), and avoid adding it when not necessary. + - Apply this to all examples in the touched folder (new, migrated, and already converted), not only files changed by moves. - During validation, confirm every `/main.py` in scope includes a top-level `ft.SafeArea` around rendered content. @@ -99,9 +103,13 @@ Ensure each runnable example is a standalone project containing: - Check `git status` to confirm expected moves and edits. - When integration tests exist for the touched control, run the targeted test file(s). - Confirm all in-scope `main.py` files include both top-level `ft.SafeArea` wrapping and the `if __name__ == "__main__": ft.run(main)` entrypoint. +- Confirm in-scope `ft.SafeArea` wrappers use `expand=True` only where needed for correct behavior and sizing; avoid forcing it by default. + - Confirm there are no unnecessary `page.update()` calls in in-scope examples (unless explicitly required by isolated-control or non-auto-update behavior). - Confirm no in-scope examples use `use_material3`. - Confirm each in-scope `pyproject.toml` has a meaningful, example-specific `[project].description` (not generic or templated text). +- Confirm metadata features include `"save to file"` when the example code supports file export/save behavior. + ## Code style diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/animate/main.py b/sdk/python/examples/controls/charts/matplotlib_chart/animate/main.py index c13eb2ab9a..24c820419a 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/animate/main.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/animate/main.py @@ -52,6 +52,7 @@ def update_lines(num, walks, lines): page.add( ft.SafeArea( + expand=True, content=flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True), ) ) diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml index de34e5d9ad..6f85b24086 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/animate/pyproject.toml @@ -18,7 +18,7 @@ title = "Animate" controls = ["SafeArea", "MatplotlibChart"] layout_pattern = "single-chart" complexity = "basic" -features = ["chart visualization"] +features = ["animated chart", "save to file"] [tool.flet] org = "dev.flet" diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/main.py b/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/main.py index 4ba83e805a..edd9252dc8 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/main.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/bar_chart/main.py @@ -18,7 +18,12 @@ def main(page: ft.Page): ax.set_title("Fruit supply by kind and color") ax.legend(title="Fruit color") - page.add(ft.SafeArea(content=fch.MatplotlibChart(figure=fig, expand=True))) + page.add( + ft.SafeArea( + expand=True, + content=fch.MatplotlibChart(figure=fig, expand=True), + ) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/main.py b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/main.py index 312f439ab9..2c0541ae5b 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/main.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/main.py @@ -99,6 +99,7 @@ def update(self): page.add( ft.SafeArea( + expand=True, content=fch.MatplotlibChartWithToolbar(figure=fig, expand=True), ) ) diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml index ed925fe9cc..9e577cecfa 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/handle_events/pyproject.toml @@ -18,7 +18,7 @@ title = "Handle Events" controls = ["SafeArea", "MatplotlibChart"] layout_pattern = "single-chart" complexity = "basic" -features = ["chart visualization"] +features = ["event handling", "save to file"] [tool.flet] org = "dev.flet" From 5e272f3aa82b602bfb9a6c4e782aa62d79067066 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 12 Mar 2026 14:22:35 -0700 Subject: [PATCH 35/96] Enable save-to-file and expand SafeArea Add "save to file" feature flags to matplotlib_chart examples and label the three_d example with "3d chart" and the toolbar example with "interactive toolbar". Also set SafeArea(expand=True) in the toolbar example so the MatplotlibChart can grow to fill available space. --- .../controls/charts/matplotlib_chart/three_d/pyproject.toml | 2 +- .../examples/controls/charts/matplotlib_chart/toolbar/main.py | 1 + .../controls/charts/matplotlib_chart/toolbar/pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml index 83a246a5b0..252c4b2eb2 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/three_d/pyproject.toml @@ -18,7 +18,7 @@ title = "Three D" controls = ["SafeArea", "MatplotlibChart"] layout_pattern = "single-chart" complexity = "basic" -features = ["chart visualization"] +features = ["3d chart", "save to file"] [tool.flet] org = "dev.flet" diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/main.py b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/main.py index 8df1482594..b27ca768fd 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/main.py +++ b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/main.py @@ -32,6 +32,7 @@ def main(page: ft.Page): page.add( ft.SafeArea( + expand=True, content=fch.MatplotlibChartWithToolbar(figure=fig, expand=True), ) ) diff --git a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml index 96d4384f29..d2ba114e9e 100644 --- a/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml +++ b/sdk/python/examples/controls/charts/matplotlib_chart/toolbar/pyproject.toml @@ -18,7 +18,7 @@ title = "Toolbar" controls = ["SafeArea", "MatplotlibChart"] layout_pattern = "single-chart" complexity = "basic" -features = ["chart visualization"] +features = ["chart visualization", "interactive toolbar", "save to file"] [tool.flet] org = "dev.flet" From 114a127ee6c37817f24f6b2ce0064777e02e41b2 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 10:48:08 -0700 Subject: [PATCH 36/96] Expand plotly deps for plotly_chart examples Update pyproject.toml for plotly_chart example_1..4 to replace plain `plotly` with `plotly[express]` and add `kaleido`, `numpy`, and `pandas`. These additions support Plotly Express usage, data manipulation with pandas/numpy, and static image export via kaleido required by the examples. --- .../controls/charts/plotly_chart/example_1/pyproject.toml | 2 +- .../controls/charts/plotly_chart/example_2/pyproject.toml | 2 +- .../controls/charts/plotly_chart/example_3/pyproject.toml | 2 +- .../controls/charts/plotly_chart/example_4/pyproject.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml index 21d87632b8..0539d01dac 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml +++ b/sdk/python/examples/controls/charts/plotly_chart/example_1/pyproject.toml @@ -5,7 +5,7 @@ description = "Plotly line chart showing life expectancy trends by country in Oc requires-python = ">=3.10" keywords = ["charts", "plotly-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] -dependencies = ["flet", "flet-charts", "plotly"] +dependencies = ["flet", "flet-charts", "kaleido", "numpy", "pandas", "plotly[express]"] [dependency-groups] dev = ["flet-cli", "flet-desktop", "flet-web"] diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml index 7312c55bd9..7b02618a0a 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml +++ b/sdk/python/examples/controls/charts/plotly_chart/example_2/pyproject.toml @@ -5,7 +5,7 @@ description = "Plotly bar chart comparing population with additional hover metri requires-python = ">=3.10" keywords = ["charts", "plotly-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] -dependencies = ["flet", "flet-charts", "plotly"] +dependencies = ["flet", "flet-charts", "kaleido", "numpy", "pandas", "plotly[express]"] [dependency-groups] dev = ["flet-cli", "flet-desktop", "flet-web"] diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml index d7e04aff90..4bbd7ce492 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml +++ b/sdk/python/examples/controls/charts/plotly_chart/example_3/pyproject.toml @@ -5,7 +5,7 @@ description = "Plotly pie chart example for categorical distribution visualizati requires-python = ">=3.10" keywords = ["charts", "plotly-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] -dependencies = ["flet", "flet-charts", "plotly"] +dependencies = ["flet", "flet-charts", "kaleido", "numpy", "pandas", "plotly[express]"] [dependency-groups] dev = ["flet-cli", "flet-desktop", "flet-web"] diff --git a/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml b/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml index c50ba380ff..e8b2498577 100644 --- a/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml +++ b/sdk/python/examples/controls/charts/plotly_chart/example_4/pyproject.toml @@ -5,7 +5,7 @@ description = "Plotly grouped box plot comparing moisture distributions across c requires-python = ">=3.10" keywords = ["charts", "plotly-chart", "flet"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] -dependencies = ["flet", "flet-charts", "plotly"] +dependencies = ["flet", "flet-charts", "kaleido", "numpy", "pandas", "plotly[express]"] [dependency-groups] dev = ["flet-cli", "flet-desktop", "flet-web"] From d32776941cad5448e0a12312d1ca57dc3e257cb0 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 10:53:15 -0700 Subject: [PATCH 37/96] Reorganize CircleAvatar example into user_avatars Remove the top-level user_avatars.py example and replace it with a packaged example layout: add user_avatars/main.py with the same CircleAvatar showcase wrapped in SafeArea/Column, and add pyproject.toml metadata for the example. Update the CircleAvatar docs to reference the new examples path (user_avatars/main.py). This restructures the example into a discoverable example package and updates documentation accordingly. --- .../controls/circle_avatar/user_avatars.py | 41 --------------- .../circle_avatar/user_avatars/main.py | 50 +++++++++++++++++++ .../circle_avatar/user_avatars/pyproject.toml | 26 ++++++++++ .../flet/docs/controls/circleavatar.md | 2 +- 4 files changed, 77 insertions(+), 42 deletions(-) delete mode 100644 sdk/python/examples/controls/circle_avatar/user_avatars.py create mode 100644 sdk/python/examples/controls/circle_avatar/user_avatars/main.py create mode 100644 sdk/python/examples/controls/circle_avatar/user_avatars/pyproject.toml diff --git a/sdk/python/examples/controls/circle_avatar/user_avatars.py b/sdk/python/examples/controls/circle_avatar/user_avatars.py deleted file mode 100644 index 8841c52d23..0000000000 --- a/sdk/python/examples/controls/circle_avatar/user_avatars.py +++ /dev/null @@ -1,41 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - # a "normal" avatar with background image - ft.CircleAvatar( - foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4", - content=ft.Text("FF"), - ), - # avatar with failing foreground image and fallback text - ft.CircleAvatar( - foreground_image_src="https://avatars.githubusercontent.com/u/_5041459?s=88&v=4", - content=ft.Text("FF"), - ), - # avatar with icon, aka icon with inverse background - ft.CircleAvatar(content=ft.Icon(ft.Icons.ABC)), - # avatar with icon and custom colors - ft.CircleAvatar( - content=ft.Icon(ft.Icons.WARNING_ROUNDED), - color=ft.Colors.YELLOW_200, - bgcolor=ft.Colors.AMBER_700, - ), - # avatar with online status - ft.Stack( - width=40, - height=40, - controls=[ - ft.CircleAvatar( - foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" - ), - ft.Container( - content=ft.CircleAvatar(bgcolor=ft.Colors.GREEN, radius=5), - alignment=ft.Alignment.BOTTOM_LEFT, - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/circle_avatar/user_avatars/main.py b/sdk/python/examples/controls/circle_avatar/user_avatars/main.py new file mode 100644 index 0000000000..e05a253f24 --- /dev/null +++ b/sdk/python/examples/controls/circle_avatar/user_avatars/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + # a "normal" avatar with background image + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4", + content=ft.Text("FF"), + ), + # avatar with failing foreground image and fallback text + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/_5041459?s=88&v=4", + content=ft.Text("FF"), + ), + # avatar with icon, aka icon with inverse background + ft.CircleAvatar(content=ft.Icon(ft.Icons.ABC)), + # avatar with icon and custom colors + ft.CircleAvatar( + content=ft.Icon(ft.Icons.WARNING_ROUNDED), + color=ft.Colors.YELLOW_200, + bgcolor=ft.Colors.AMBER_700, + ), + # avatar with online status + ft.Stack( + width=40, + height=40, + controls=[ + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" + ), + ft.Container( + alignment=ft.Alignment.BOTTOM_LEFT, + content=ft.CircleAvatar( + bgcolor=ft.Colors.GREEN, radius=5 + ), + ), + ], + ), + ] + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/circle_avatar/user_avatars/pyproject.toml b/sdk/python/examples/controls/circle_avatar/user_avatars/pyproject.toml new file mode 100644 index 0000000000..4a35a23979 --- /dev/null +++ b/sdk/python/examples/controls/circle_avatar/user_avatars/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "circle-avatar-user-avatars" +version = "1.0.0" +description = "CircleAvatar showcase with images, icons, fallback content, and online status badge." +requires-python = ">=3.10" +keywords = ["circleavatar", "avatar", "image", "icon", "status"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/CircleAvatar"] + +[tool.flet.metadata] +title = "User avatars" +controls = ["SafeArea", "CircleAvatar", "Text", "Icon", "Stack", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["image avatar", "fallback content", "online status indicator"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/circleavatar.md b/sdk/python/packages/flet/docs/controls/circleavatar.md index 3578e912e8..b06b9237a2 100644 --- a/sdk/python/packages/flet/docs/controls/circleavatar.md +++ b/sdk/python/packages/flet/docs/controls/circleavatar.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/circle_avatar/media ### User avatars ```python ---8<-- "{{ examples }}/user_avatars.py" +--8<-- "{{ examples }}/user_avatars/main.py" ``` {{ image(example_media + "/user_avatars.png", alt="user-avatars", width="80%") }} From 65fc7a5961d3f4ba901da0380e1a3ecfb0376b34 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 11:31:06 -0700 Subject: [PATCH 38/96] Restructure examples; add pyproject files Move example scripts into per-example packages (example_N/main.py) for code_editor and color_pickers, remove example package __init__ files, and add pyproject.toml metadata for each example. Wrap example UIs in ft.SafeArea and adjust layout nesting; replace direct ft.run(main) calls with a __main__ guard. Update docs to reference new example paths and update integration test imports to the new module locations. These changes standardize example structure and provide metadata for the Flet gallery. --- .../examples/controls/code_editor/__init__.py | 0 .../{example_1.py => example_1/main.py} | 13 ++-- .../code_editor/example_1/pyproject.toml | 26 +++++++ .../{example_2.py => example_2/main.py} | 70 ++++++++++--------- .../code_editor/example_2/pyproject.toml | 26 +++++++ .../{example_3.py => example_3/main.py} | 21 ++++-- .../code_editor/example_3/pyproject.toml | 26 +++++++ .../controls/color_pickers/__init__.py | 0 .../{example_1.py => example_1/main.py} | 5 +- .../color_pickers/example_1/pyproject.toml | 26 +++++++ .../{example_2.py => example_2/main.py} | 5 +- .../color_pickers/example_2/pyproject.toml | 26 +++++++ .../{example_3.py => example_3/main.py} | 5 +- .../color_pickers/example_3/pyproject.toml | 26 +++++++ .../{example_4.py => example_4/main.py} | 5 +- .../color_pickers/example_4/pyproject.toml | 26 +++++++ .../{example_5.py => example_5/main.py} | 10 ++- .../color_pickers/example_5/pyproject.toml | 26 +++++++ .../{example_6.py => example_6/main.py} | 10 ++- .../color_pickers/example_6/pyproject.toml | 26 +++++++ .../packages/flet/docs/codeeditor/index.md | 6 +- .../flet/docs/colorpickers/blockpicker.md | 2 +- .../flet/docs/colorpickers/colorpicker.md | 2 +- .../flet/docs/colorpickers/hueringpicker.md | 2 +- .../flet/docs/colorpickers/materialpicker.md | 2 +- .../colorpickers/multiplechoiceblockpicker.md | 2 +- .../flet/docs/colorpickers/slidepicker.md | 2 +- .../code_editor/test_code_editor.py | 4 +- 28 files changed, 334 insertions(+), 66 deletions(-) delete mode 100644 sdk/python/examples/controls/code_editor/__init__.py rename sdk/python/examples/controls/code_editor/{example_1.py => example_1/main.py} (71%) create mode 100644 sdk/python/examples/controls/code_editor/example_1/pyproject.toml rename sdk/python/examples/controls/code_editor/{example_2.py => example_2/main.py} (63%) create mode 100644 sdk/python/examples/controls/code_editor/example_2/pyproject.toml rename sdk/python/examples/controls/code_editor/{example_3.py => example_3/main.py} (59%) create mode 100644 sdk/python/examples/controls/code_editor/example_3/pyproject.toml delete mode 100644 sdk/python/examples/controls/color_pickers/__init__.py rename sdk/python/examples/controls/color_pickers/{example_1.py => example_1/main.py} (92%) create mode 100644 sdk/python/examples/controls/color_pickers/example_1/pyproject.toml rename sdk/python/examples/controls/color_pickers/{example_2.py => example_2/main.py} (83%) create mode 100644 sdk/python/examples/controls/color_pickers/example_2/pyproject.toml rename sdk/python/examples/controls/color_pickers/{example_3.py => example_3/main.py} (83%) create mode 100644 sdk/python/examples/controls/color_pickers/example_3/pyproject.toml rename sdk/python/examples/controls/color_pickers/{example_4.py => example_4/main.py} (84%) create mode 100644 sdk/python/examples/controls/color_pickers/example_4/pyproject.toml rename sdk/python/examples/controls/color_pickers/{example_5.py => example_5/main.py} (78%) create mode 100644 sdk/python/examples/controls/color_pickers/example_5/pyproject.toml rename sdk/python/examples/controls/color_pickers/{example_6.py => example_6/main.py} (80%) create mode 100644 sdk/python/examples/controls/color_pickers/example_6/pyproject.toml diff --git a/sdk/python/examples/controls/code_editor/__init__.py b/sdk/python/examples/controls/code_editor/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/code_editor/example_1.py b/sdk/python/examples/controls/code_editor/example_1/main.py similarity index 71% rename from sdk/python/examples/controls/code_editor/example_1.py rename to sdk/python/examples/controls/code_editor/example_1/main.py index 44d0fc7648..48f89f9b1b 100644 --- a/sdk/python/examples/controls/code_editor/example_1.py +++ b/sdk/python/examples/controls/code_editor/example_1/main.py @@ -32,12 +32,15 @@ def btn_click(e): def main(page: ft.Page): page.add( - fce.CodeEditor( - language=fce.CodeLanguage.PYTHON, - code_theme=fce.CodeTheme.ATOM_ONE_LIGHT, - value=CODE, + ft.SafeArea( expand=True, - on_change=lambda e: print("Changed:", e.data), + content=fce.CodeEditor( + language=fce.CodeLanguage.PYTHON, + code_theme=fce.CodeTheme.ATOM_ONE_LIGHT, + value=CODE, + expand=True, + on_change=lambda e: print("Changed:", e.data), + ), ) ) diff --git a/sdk/python/examples/controls/code_editor/example_1/pyproject.toml b/sdk/python/examples/controls/code_editor/example_1/pyproject.toml new file mode 100644 index 0000000000..7eb53007c9 --- /dev/null +++ b/sdk/python/examples/controls/code_editor/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "code-editor-example-1" +version = "1.0.0" +description = "Basic CodeEditor setup with Python syntax highlighting and change callbacks." +requires-python = ">=3.10" +keywords = ["code editor", "syntax highlighting", "python", "editor"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-code-editor"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utilities/CodeEditor"] + +[tool.flet.metadata] +title = "Basic example" +controls = ["SafeArea", "CodeEditor"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["syntax highlighting", "change events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/code_editor/example_2.py b/sdk/python/examples/controls/code_editor/example_2/main.py similarity index 63% rename from sdk/python/examples/controls/code_editor/example_2.py rename to sdk/python/examples/controls/code_editor/example_2/main.py index 9d7e8753bc..a39af8be1b 100644 --- a/sdk/python/examples/controls/code_editor/example_2.py +++ b/sdk/python/examples/controls/code_editor/example_2/main.py @@ -92,39 +92,45 @@ async def move_caret_to_start(e: ft.Event[ft.Button]): editor.selection = ft.TextSelection(base_offset=0, extent_offset=0) page.add( - ft.Column( + ft.SafeArea( expand=True, - spacing=10, - controls=[ - editor := fce.CodeEditor( - language=fce.CodeLanguage.PYTHON, - code_theme=theme, - autocomplete=True, - autocomplete_words=[ - "Container", - "Button", - "Text", - "Row", - "Column", - ], - value=CODE, - text_style=text_style, - gutter_style=gutter_style, - padding=10, - on_selection_change=handle_selection_change, - expand=True, - ), - selection := ft.Text("Select some text from the editor."), - selection_details := ft.Text(), - caret := ft.Text("Caret position: -"), - ft.Row( - spacing=10, - controls=[ - ft.Button("Select all text", on_click=select_all), - ft.Button("Move caret to start", on_click=move_caret_to_start), - ], - ), - ], + content=ft.Column( + expand=True, + spacing=10, + controls=[ + editor := fce.CodeEditor( + language=fce.CodeLanguage.PYTHON, + code_theme=theme, + autocomplete=True, + autocomplete_words=[ + "Container", + "Button", + "Text", + "Row", + "Column", + ], + value=CODE, + text_style=text_style, + gutter_style=gutter_style, + padding=10, + on_selection_change=handle_selection_change, + expand=True, + ), + selection := ft.Text("Select some text from the editor."), + selection_details := ft.Text(), + caret := ft.Text("Caret position: -"), + ft.Row( + spacing=10, + controls=[ + ft.Button("Select all text", on_click=select_all), + ft.Button( + "Move caret to start", + on_click=move_caret_to_start, + ), + ], + ), + ], + ), ) ) diff --git a/sdk/python/examples/controls/code_editor/example_2/pyproject.toml b/sdk/python/examples/controls/code_editor/example_2/pyproject.toml new file mode 100644 index 0000000000..072abaaddf --- /dev/null +++ b/sdk/python/examples/controls/code_editor/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "code-editor-example-2" +version = "1.0.0" +description = "CodeEditor selection demo with custom theme, gutter styling, and caret/selection controls." +requires-python = ">=3.10" +keywords = ["code editor", "selection", "caret", "theme", "gutter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-code-editor"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utilities/CodeEditor"] + +[tool.flet.metadata] +title = "Selection handling" +controls = ["SafeArea", "Column", "CodeEditor", "Text", "Row", "Button"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["selection change handling", "programmatic caret movement", "custom code theme"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/code_editor/example_3.py b/sdk/python/examples/controls/code_editor/example_3/main.py similarity index 59% rename from sdk/python/examples/controls/code_editor/example_3.py rename to sdk/python/examples/controls/code_editor/example_3/main.py index 61351923cb..f0a61d7399 100644 --- a/sdk/python/examples/controls/code_editor/example_3.py +++ b/sdk/python/examples/controls/code_editor/example_3/main.py @@ -29,13 +29,20 @@ async def fold_comment(): await editor.fold_comment_at_line_zero() page.add( - ft.Row( - [ - ft.Button("Fold imports", on_click=fold_imports), - ft.Button("Fold comment", on_click=fold_comment), - ] - ), - editor, + ft.SafeArea( + expand=True, + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Button("Fold imports", on_click=fold_imports), + ft.Button("Fold comment", on_click=fold_comment), + ] + ), + editor, + ] + ), + ) ) diff --git a/sdk/python/examples/controls/code_editor/example_3/pyproject.toml b/sdk/python/examples/controls/code_editor/example_3/pyproject.toml new file mode 100644 index 0000000000..e129a5ba4a --- /dev/null +++ b/sdk/python/examples/controls/code_editor/example_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "code-editor-example-3" +version = "1.0.0" +description = "CodeEditor folding demo with predefined selection and toolbar actions for folding code blocks." +requires-python = ">=3.10" +keywords = ["code editor", "folding", "selection", "toolbar", "python"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-code-editor"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utilities/CodeEditor"] + +[tool.flet.metadata] +title = "Folding and initial selection" +controls = ["SafeArea", "Column", "Row", "Button", "CodeEditor"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["code folding", "initial text selection", "selection change events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/color_pickers/__init__.py b/sdk/python/examples/controls/color_pickers/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/color_pickers/example_1.py b/sdk/python/examples/controls/color_pickers/example_1/main.py similarity index 92% rename from sdk/python/examples/controls/color_pickers/example_1.py rename to sdk/python/examples/controls/color_pickers/example_1/main.py index 29dd016f5b..72627c2702 100644 --- a/sdk/python/examples/controls/color_pickers/example_1.py +++ b/sdk/python/examples/controls/color_pickers/example_1/main.py @@ -38,7 +38,8 @@ def on_hsv_color_change(e: ft.ControlEvent): picker_area_border_radius=ft.BorderRadius.all(20), ) - page.add(picker) + page.add(ft.SafeArea(content=picker)) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/color_pickers/example_1/pyproject.toml b/sdk/python/examples/controls/color_pickers/example_1/pyproject.toml new file mode 100644 index 0000000000..9d330ed917 --- /dev/null +++ b/sdk/python/examples/controls/color_pickers/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-1" +version = "1.0.0" +description = "ColorPicker example with RGB palette mode, color history, and HSV/history change callbacks." +requires-python = ">=3.10" +keywords = ["color picker", "rgb", "hsv", "history", "palette"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/ColorPickers"] + +[tool.flet.metadata] +title = "ColorPicker" +controls = ["SafeArea", "ColorPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["color change callback", "color history", "hsv updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/color_pickers/example_2.py b/sdk/python/examples/controls/color_pickers/example_2/main.py similarity index 83% rename from sdk/python/examples/controls/color_pickers/example_2.py rename to sdk/python/examples/controls/color_pickers/example_2/main.py index b4477cae08..088be69b20 100644 --- a/sdk/python/examples/controls/color_pickers/example_2.py +++ b/sdk/python/examples/controls/color_pickers/example_2/main.py @@ -16,7 +16,8 @@ def on_color_change(e: ft.ControlEvent): on_color_change=on_color_change, ) - page.add(picker) + page.add(ft.SafeArea(content=picker)) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/color_pickers/example_2/pyproject.toml b/sdk/python/examples/controls/color_pickers/example_2/pyproject.toml new file mode 100644 index 0000000000..d6a7eafa2f --- /dev/null +++ b/sdk/python/examples/controls/color_pickers/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-2" +version = "1.0.0" +description = "HueRingPicker example with custom ring stroke width and color change callback." +requires-python = ">=3.10" +keywords = ["color picker", "hue ring", "color selection", "callback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/ColorPickers"] + +[tool.flet.metadata] +title = "HueRingPicker" +controls = ["SafeArea", "HueRingPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["color change callback", "hue ring customization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/color_pickers/example_3.py b/sdk/python/examples/controls/color_pickers/example_3/main.py similarity index 83% rename from sdk/python/examples/controls/color_pickers/example_3.py rename to sdk/python/examples/controls/color_pickers/example_3/main.py index 595c0f7da8..9f74c16144 100644 --- a/sdk/python/examples/controls/color_pickers/example_3.py +++ b/sdk/python/examples/controls/color_pickers/example_3/main.py @@ -16,7 +16,8 @@ def on_color_change(e: ft.ControlEvent): on_color_change=on_color_change, ) - page.add(picker) + page.add(ft.SafeArea(content=picker)) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/color_pickers/example_3/pyproject.toml b/sdk/python/examples/controls/color_pickers/example_3/pyproject.toml new file mode 100644 index 0000000000..0753398272 --- /dev/null +++ b/sdk/python/examples/controls/color_pickers/example_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-3" +version = "1.0.0" +description = "SlidePicker example using RGB color model with styled indicator and color change callback." +requires-python = ">=3.10" +keywords = ["color picker", "slide picker", "rgb", "callback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/ColorPickers"] + +[tool.flet.metadata] +title = "SlidePicker" +controls = ["SafeArea", "SlidePicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["color change callback", "rgb color model", "indicator styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/color_pickers/example_4.py b/sdk/python/examples/controls/color_pickers/example_4/main.py similarity index 84% rename from sdk/python/examples/controls/color_pickers/example_4.py rename to sdk/python/examples/controls/color_pickers/example_4/main.py index 63ec12dee8..d52aaf43b4 100644 --- a/sdk/python/examples/controls/color_pickers/example_4.py +++ b/sdk/python/examples/controls/color_pickers/example_4/main.py @@ -18,7 +18,8 @@ def on_primary_change(e: ft.ControlEvent): on_primary_change=on_primary_change, ) - page.add(picker) + page.add(ft.SafeArea(content=picker)) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/color_pickers/example_4/pyproject.toml b/sdk/python/examples/controls/color_pickers/example_4/pyproject.toml new file mode 100644 index 0000000000..fc6a856a5f --- /dev/null +++ b/sdk/python/examples/controls/color_pickers/example_4/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-4" +version = "1.0.0" +description = "MaterialPicker example with callbacks for both selected color and primary swatch changes." +requires-python = ">=3.10" +keywords = ["color picker", "material picker", "swatch", "callback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/ColorPickers"] + +[tool.flet.metadata] +title = "MaterialPicker" +controls = ["SafeArea", "MaterialPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["color change callback", "primary swatch callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/color_pickers/example_5.py b/sdk/python/examples/controls/color_pickers/example_5/main.py similarity index 78% rename from sdk/python/examples/controls/color_pickers/example_5.py rename to sdk/python/examples/controls/color_pickers/example_5/main.py index 05cc6c80b7..a6d9a5faa1 100644 --- a/sdk/python/examples/controls/color_pickers/example_5.py +++ b/sdk/python/examples/controls/color_pickers/example_5/main.py @@ -34,8 +34,14 @@ def on_color_change(e: ft.ControlEvent): ) page.add( - ft.IconButton(icon=ft.Icons.BRUSH, on_click=lambda e: page.show_dialog(dialog)), + ft.SafeArea( + content=ft.IconButton( + icon=ft.Icons.BRUSH, + on_click=lambda e: page.show_dialog(dialog), + ) + ), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/color_pickers/example_5/pyproject.toml b/sdk/python/examples/controls/color_pickers/example_5/pyproject.toml new file mode 100644 index 0000000000..0603df1f09 --- /dev/null +++ b/sdk/python/examples/controls/color_pickers/example_5/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-5" +version = "1.0.0" +description = "BlockPicker dialog example with curated color palette and icon-triggered modal launch." +requires-python = ">=3.10" +keywords = ["color picker", "block picker", "dialog", "palette", "modal"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/ColorPickers"] + +[tool.flet.metadata] +title = "BlockPicker" +controls = ["SafeArea", "IconButton", "AlertDialog", "TextButton", "BlockPicker"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dialog picker", "color change callback", "custom color palette"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/color_pickers/example_6.py b/sdk/python/examples/controls/color_pickers/example_6/main.py similarity index 80% rename from sdk/python/examples/controls/color_pickers/example_6.py rename to sdk/python/examples/controls/color_pickers/example_6/main.py index 3d8f196ed5..c3cf95d121 100644 --- a/sdk/python/examples/controls/color_pickers/example_6.py +++ b/sdk/python/examples/controls/color_pickers/example_6/main.py @@ -36,8 +36,14 @@ def on_colors_change(e: ft.ControlEvent): ) page.add( - ft.IconButton(icon=ft.Icons.BRUSH, on_click=lambda e: page.show_dialog(dialog)), + ft.SafeArea( + content=ft.IconButton( + icon=ft.Icons.BRUSH, + on_click=lambda e: page.show_dialog(dialog), + ) + ), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/color_pickers/example_6/pyproject.toml b/sdk/python/examples/controls/color_pickers/example_6/pyproject.toml new file mode 100644 index 0000000000..c6f5212d51 --- /dev/null +++ b/sdk/python/examples/controls/color_pickers/example_6/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-6" +version = "1.0.0" +description = "MultipleChoiceBlockPicker dialog with multi-select colors and icon-triggered modal launch." +requires-python = ">=3.10" +keywords = ["color picker", "multi-select", "block picker", "dialog", "palette"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/ColorPickers"] + +[tool.flet.metadata] +title = "MultipleChoiceBlockPicker" +controls = ["SafeArea", "IconButton", "AlertDialog", "TextButton", "MultipleChoiceBlockPicker"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dialog picker", "multiple color selection", "colors change callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/codeeditor/index.md b/sdk/python/packages/flet/docs/codeeditor/index.md index 4b97006ed8..3be94accae 100644 --- a/sdk/python/packages/flet/docs/codeeditor/index.md +++ b/sdk/python/packages/flet/docs/codeeditor/index.md @@ -28,7 +28,7 @@ pip install flet-code-editor # (1)! ### Basic example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ image(example_images + "/example_1.png", alt="code-editor-example-1", width="80%") }} @@ -36,7 +36,7 @@ pip install flet-code-editor # (1)! ### Selection handling ```python ---8<-- "{{ examples }}/example_2.py" +--8<-- "{{ examples }}/example_2/main.py" ``` {{ image(example_images + "/example_2.png", alt="code-editor-example-2", width="80%") }} @@ -44,7 +44,7 @@ pip install flet-code-editor # (1)! ### Folding and initial selection ```python ---8<-- "{{ examples }}/example_3.py" +--8<-- "{{ examples }}/example_3/main.py" ``` {{ image(example_images + "/example_3.png", alt="code-editor-example-3", width="80%") }} diff --git a/sdk/python/packages/flet/docs/colorpickers/blockpicker.md b/sdk/python/packages/flet/docs/colorpickers/blockpicker.md index e1d87a53a5..71b6f36f38 100644 --- a/sdk/python/packages/flet/docs/colorpickers/blockpicker.md +++ b/sdk/python/packages/flet/docs/colorpickers/blockpicker.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/extensions/color_pickers/golden/macos/co ## Example ```python ---8<-- "{{ examples }}/example_5.py" +--8<-- "{{ examples }}/example_5/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/colorpickers/colorpicker.md b/sdk/python/packages/flet/docs/colorpickers/colorpicker.md index ea716db5f9..79e2136e59 100644 --- a/sdk/python/packages/flet/docs/colorpickers/colorpicker.md +++ b/sdk/python/packages/flet/docs/colorpickers/colorpicker.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/extensions/color_pickers/golden/macos/co ## Example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/colorpickers/hueringpicker.md b/sdk/python/packages/flet/docs/colorpickers/hueringpicker.md index 8ec1983b3d..953b34fbe6 100644 --- a/sdk/python/packages/flet/docs/colorpickers/hueringpicker.md +++ b/sdk/python/packages/flet/docs/colorpickers/hueringpicker.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/extensions/color_pickers/golden/macos/co ## Example ```python ---8<-- "{{ examples }}/example_2.py" +--8<-- "{{ examples }}/example_2/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/colorpickers/materialpicker.md b/sdk/python/packages/flet/docs/colorpickers/materialpicker.md index 810f31be64..9b7a996891 100644 --- a/sdk/python/packages/flet/docs/colorpickers/materialpicker.md +++ b/sdk/python/packages/flet/docs/colorpickers/materialpicker.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/extensions/color_pickers/golden/macos/co ## Example ```python ---8<-- "{{ examples }}/example_4.py" +--8<-- "{{ examples }}/example_4/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/colorpickers/multiplechoiceblockpicker.md b/sdk/python/packages/flet/docs/colorpickers/multiplechoiceblockpicker.md index df323be40e..5e57efc3b1 100644 --- a/sdk/python/packages/flet/docs/colorpickers/multiplechoiceblockpicker.md +++ b/sdk/python/packages/flet/docs/colorpickers/multiplechoiceblockpicker.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/extensions/color_pickers/golden/macos/co ## Example ```python ---8<-- "{{ examples }}/example_6.py" +--8<-- "{{ examples }}/example_6/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/colorpickers/slidepicker.md b/sdk/python/packages/flet/docs/colorpickers/slidepicker.md index 83388f24bb..c0432cb7b9 100644 --- a/sdk/python/packages/flet/docs/colorpickers/slidepicker.md +++ b/sdk/python/packages/flet/docs/colorpickers/slidepicker.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/extensions/color_pickers/golden/macos/co ## Example ```python ---8<-- "{{ examples }}/example_3.py" +--8<-- "{{ examples }}/example_3/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py index 10904d80b6..5f7068114a 100644 --- a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py +++ b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py @@ -1,7 +1,9 @@ import pytest +import examples.controls.code_editor.example_1.main as example_1 +import examples.controls.code_editor.example_2.main as example_2 +import examples.controls.code_editor.example_3.main as example_3 import flet.testing as ftt -from examples.controls.code_editor import example_1, example_2, example_3 @pytest.mark.parametrize( From fd8cf76e3545f625168f94e739595fcfd320db19 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 12:02:22 -0700 Subject: [PATCH 39/96] Restructure container examples and add metadata Move container example scripts into per-example directories (main.py) and remove the old top-level .py files. Add pyproject.toml metadata for each example, wrap example UIs with SafeArea/Column where appropriate, and adjust example imports/usages. Update documentation references to point at the new example paths and rename integration test/golden assets to their new locations. --- .../examples/controls/container/__init__.py | 0 .../examples/controls/container/animate_1.py | 24 ----- .../controls/container/animate_1/main.py | 33 +++++++ .../container/animate_1/pyproject.toml | 26 ++++++ .../{animate_2.py => animate_2/main.py} | 33 ++++--- .../container/animate_2/pyproject.toml | 26 ++++++ .../examples/controls/container/animate_3.py | 24 ----- .../{animate_4.py => animate_3/main.py} | 5 +- .../container/animate_3/pyproject.toml | 26 ++++++ .../examples/controls/container/clickable.py | 63 ------------- .../controls/container/clickable/main.py | 68 ++++++++++++++ .../container/clickable/pyproject.toml | 26 ++++++ .../main.py} | 11 +-- .../container/handling_clicks/pyproject.toml | 26 ++++++ .../controls/container/handling_hovers.py | 20 ----- .../container/handling_hovers/main.py | 23 +++++ .../container/handling_hovers/pyproject.toml | 26 ++++++ .../controls/container/nested_themes_1.py | 39 -------- .../container/nested_themes_1/main.py | 47 ++++++++++ .../container/nested_themes_1/pyproject.toml | 26 ++++++ .../controls/container/nested_themes_2.py | 73 --------------- .../container/nested_themes_2/main.py | 85 ++++++++++++++++++ .../container/nested_themes_2/pyproject.toml | 26 ++++++ .../controls/container/nested_themes_3.py | 59 ------------ .../container/nested_themes_3/main.py | 68 ++++++++++++++ .../container/nested_themes_3/pyproject.toml | 26 ++++++ .../examples/controls/container/size_aware.py | 21 ----- .../controls/container/size_aware/main.py | 24 +++++ .../container/size_aware/pyproject.toml | 26 ++++++ .../packages/flet/docs/controls/container.md | 26 +++--- .../macos/container/nested_themes_1.png | Bin .../macos/container/nested_themes_2.png | Bin .../golden/macos/container/size_aware.png | Bin .../{material => core}/test_container.py | 8 +- 34 files changed, 651 insertions(+), 363 deletions(-) delete mode 100644 sdk/python/examples/controls/container/__init__.py delete mode 100644 sdk/python/examples/controls/container/animate_1.py create mode 100644 sdk/python/examples/controls/container/animate_1/main.py create mode 100644 sdk/python/examples/controls/container/animate_1/pyproject.toml rename sdk/python/examples/controls/container/{animate_2.py => animate_2/main.py} (63%) create mode 100644 sdk/python/examples/controls/container/animate_2/pyproject.toml delete mode 100644 sdk/python/examples/controls/container/animate_3.py rename sdk/python/examples/controls/container/{animate_4.py => animate_3/main.py} (91%) create mode 100644 sdk/python/examples/controls/container/animate_3/pyproject.toml delete mode 100644 sdk/python/examples/controls/container/clickable.py create mode 100644 sdk/python/examples/controls/container/clickable/main.py create mode 100644 sdk/python/examples/controls/container/clickable/pyproject.toml rename sdk/python/examples/controls/container/{handling_clicks.py => handling_clicks/main.py} (94%) create mode 100644 sdk/python/examples/controls/container/handling_clicks/pyproject.toml delete mode 100644 sdk/python/examples/controls/container/handling_hovers.py create mode 100644 sdk/python/examples/controls/container/handling_hovers/main.py create mode 100644 sdk/python/examples/controls/container/handling_hovers/pyproject.toml delete mode 100644 sdk/python/examples/controls/container/nested_themes_1.py create mode 100644 sdk/python/examples/controls/container/nested_themes_1/main.py create mode 100644 sdk/python/examples/controls/container/nested_themes_1/pyproject.toml delete mode 100644 sdk/python/examples/controls/container/nested_themes_2.py create mode 100644 sdk/python/examples/controls/container/nested_themes_2/main.py create mode 100644 sdk/python/examples/controls/container/nested_themes_2/pyproject.toml delete mode 100644 sdk/python/examples/controls/container/nested_themes_3.py create mode 100644 sdk/python/examples/controls/container/nested_themes_3/main.py create mode 100644 sdk/python/examples/controls/container/nested_themes_3/pyproject.toml delete mode 100644 sdk/python/examples/controls/container/size_aware.py create mode 100644 sdk/python/examples/controls/container/size_aware/main.py create mode 100644 sdk/python/examples/controls/container/size_aware/pyproject.toml rename sdk/python/packages/flet/integration_tests/examples/{material => core}/golden/macos/container/nested_themes_1.png (100%) rename sdk/python/packages/flet/integration_tests/examples/{material => core}/golden/macos/container/nested_themes_2.png (100%) rename sdk/python/packages/flet/integration_tests/examples/{material => core}/golden/macos/container/size_aware.png (100%) rename sdk/python/packages/flet/integration_tests/examples/{material => core}/test_container.py (89%) diff --git a/sdk/python/examples/controls/container/__init__.py b/sdk/python/examples/controls/container/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/container/animate_1.py b/sdk/python/examples/controls/container/animate_1.py deleted file mode 100644 index 46a5389955..0000000000 --- a/sdk/python/examples/controls/container/animate_1.py +++ /dev/null @@ -1,24 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate_container(e: ft.Event[ft.Button]): - container.width = 100 if container.width == 150 else 150 - container.height = 50 if container.height == 150 else 150 - container.bgcolor = ( - ft.Colors.BLUE if container.bgcolor == ft.Colors.RED else ft.Colors.RED - ) - container.update() - - page.add( - container := ft.Container( - width=150, - height=150, - bgcolor=ft.Colors.RED, - animate=ft.Animation(duration=1000, curve=ft.AnimationCurve.BOUNCE_OUT), - ), - ft.Button("Animate container", on_click=animate_container), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/container/animate_1/main.py b/sdk/python/examples/controls/container/animate_1/main.py new file mode 100644 index 0000000000..561c987a34 --- /dev/null +++ b/sdk/python/examples/controls/container/animate_1/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_container(e: ft.Event[ft.Button]): + container.width = 100 if container.width == 150 else 150 + container.height = 50 if container.height == 150 else 150 + container.bgcolor = ( + ft.Colors.BLUE if container.bgcolor == ft.Colors.RED else ft.Colors.RED + ) + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + container := ft.Container( + width=150, + height=150, + bgcolor=ft.Colors.RED, + animate=ft.Animation( + duration=1000, curve=ft.AnimationCurve.BOUNCE_OUT + ), + ), + ft.Button("Animate container", on_click=animate_container), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/animate_1/pyproject.toml b/sdk/python/examples/controls/container/animate_1/pyproject.toml new file mode 100644 index 0000000000..699896a5b5 --- /dev/null +++ b/sdk/python/examples/controls/container/animate_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-animate-1" +version = "1.0.0" +description = "Animated container size and color transitions triggered by button clicks." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Animate 1" +controls = ["SafeArea", "Column", "Container", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["size animation", "color animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/animate_2.py b/sdk/python/examples/controls/container/animate_2/main.py similarity index 63% rename from sdk/python/examples/controls/container/animate_2.py rename to sdk/python/examples/controls/container/animate_2/main.py index d891b03259..558639d188 100644 --- a/sdk/python/examples/controls/container/animate_2.py +++ b/sdk/python/examples/controls/container/animate_2/main.py @@ -37,19 +37,28 @@ def animate_container(e: ft.Event[ft.Button]): container.update() page.add( - container := ft.Container( - content=message, - width=250, - height=250, - gradient=gradient2, - alignment=ft.Alignment.TOP_LEFT, - animate=ft.Animation(duration=1000, curve=ft.AnimationCurve.BOUNCE_OUT), - border=ft.Border.all(width=2, color=ft.Colors.BLUE), - border_radius=10, - padding=10, + ft.SafeArea( + content=ft.Column( + controls=[ + container := ft.Container( + width=250, + height=250, + gradient=gradient2, + alignment=ft.Alignment.TOP_LEFT, + animate=ft.Animation( + duration=1000, curve=ft.AnimationCurve.BOUNCE_OUT + ), + border=ft.Border.all(width=2, color=ft.Colors.BLUE), + border_radius=10, + padding=10, + content=message, + ), + ft.Button("Animate container", on_click=animate_container), + ] + ) ), - ft.Button("Animate container", on_click=animate_container), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/animate_2/pyproject.toml b/sdk/python/examples/controls/container/animate_2/pyproject.toml new file mode 100644 index 0000000000..299edf9de9 --- /dev/null +++ b/sdk/python/examples/controls/container/animate_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-animate-2" +version = "1.0.0" +description = "Animated container with gradient, border, alignment, and shape transitions." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Animate 2" +controls = ["SafeArea", "Column", "Container", "Button", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["gradient animation", "border animation", "alignment animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/animate_3.py b/sdk/python/examples/controls/container/animate_3.py deleted file mode 100644 index cbcf1e1145..0000000000 --- a/sdk/python/examples/controls/container/animate_3.py +++ /dev/null @@ -1,24 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate(e: ft.Event[ft.Button]): - container.width = 100 if container.width == 150 else 150 - container.height = 50 if container.height == 150 else 150 - container.bgcolor = ( - ft.Colors.BLUE if container.bgcolor == ft.Colors.RED else ft.Colors.RED - ) - container.update() - - page.add( - container := ft.Container( - width=150, - height=150, - bgcolor=ft.Colors.RED, - animate=ft.Animation(1000, ft.AnimationCurve.BOUNCE_OUT), - ), - ft.Button("Animate container", on_click=animate), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/container/animate_4.py b/sdk/python/examples/controls/container/animate_3/main.py similarity index 91% rename from sdk/python/examples/controls/container/animate_4.py rename to sdk/python/examples/controls/container/animate_3/main.py index 8d95d1ea5d..56ab86c552 100644 --- a/sdk/python/examples/controls/container/animate_4.py +++ b/sdk/python/examples/controls/container/animate_3/main.py @@ -41,7 +41,8 @@ def hide_menu(e: ft.Event[ft.IconButton]): ) ) - page.add(ft.Button("Show menu", on_click=show_menu)) + page.add(ft.SafeArea(content=ft.Button("Show menu", on_click=show_menu))) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/animate_3/pyproject.toml b/sdk/python/examples/controls/container/animate_3/pyproject.toml new file mode 100644 index 0000000000..a93d8a6de2 --- /dev/null +++ b/sdk/python/examples/controls/container/animate_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-animate-3" +version = "1.0.0" +description = "Slide-in side menu built with animated container offset and overlay controls." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Animate 3" +controls = ["SafeArea", "Button", "Container", "Column", "Row", "IconButton", "ListTile"] +layout_pattern = "overlay" +complexity = "basic" +features = ["overlay menu", "offset animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/clickable.py b/sdk/python/examples/controls/container/clickable.py deleted file mode 100644 index 793199cb2e..0000000000 --- a/sdk/python/examples/controls/container/clickable.py +++ /dev/null @@ -1,63 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Container Example" - page.theme_mode = ft.ThemeMode.LIGHT - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - page.add( - ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - ft.Container( - content=ft.Text("Non clickable"), - margin=10, - padding=10, - alignment=ft.Alignment.CENTER, - bgcolor=ft.Colors.AMBER, - width=150, - height=150, - border_radius=10, - ), - ft.Container( - content=ft.Text("Clickable without Ink"), - margin=10, - padding=10, - alignment=ft.Alignment.CENTER, - bgcolor=ft.Colors.GREEN_200, - width=150, - height=150, - border_radius=10, - on_click=lambda e: print("Clickable without Ink clicked!"), - ), - ft.Container( - content=ft.Text("Clickable with Ink"), - margin=10, - padding=10, - alignment=ft.Alignment.CENTER, - bgcolor=ft.Colors.CYAN_200, - width=150, - height=150, - border_radius=10, - ink=True, - on_click=lambda e: print("Clickable with Ink clicked!"), - ), - ft.Container( - content=ft.Text("Clickable transparent with Ink"), - margin=10, - padding=10, - alignment=ft.Alignment.CENTER, - width=150, - height=150, - border_radius=10, - ink=True, - on_click=lambda e: print("Clickable transparent with Ink clicked!"), - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/container/clickable/main.py b/sdk/python/examples/controls/container/clickable/main.py new file mode 100644 index 0000000000..9fa4d0824c --- /dev/null +++ b/sdk/python/examples/controls/container/clickable/main.py @@ -0,0 +1,68 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Container Example" + page.theme_mode = ft.ThemeMode.LIGHT + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Container( + margin=10, + padding=10, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.AMBER, + width=150, + height=150, + border_radius=10, + content=ft.Text("Non clickable"), + ), + ft.Container( + margin=10, + padding=10, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.GREEN_200, + width=150, + height=150, + border_radius=10, + on_click=lambda e: print("Clickable without Ink clicked!"), + content=ft.Text("Clickable without Ink"), + ), + ft.Container( + margin=10, + padding=10, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.CYAN_200, + width=150, + height=150, + border_radius=10, + ink=True, + on_click=lambda e: print("Clickable with Ink clicked!"), + content=ft.Text("Clickable with Ink"), + ), + ft.Container( + margin=10, + padding=10, + alignment=ft.Alignment.CENTER, + width=150, + height=150, + border_radius=10, + ink=True, + on_click=lambda e: print( + "Clickable transparent with Ink clicked!" + ), + content=ft.Text("Clickable transparent with Ink"), + ), + ], + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/clickable/pyproject.toml b/sdk/python/examples/controls/container/clickable/pyproject.toml new file mode 100644 index 0000000000..8152121403 --- /dev/null +++ b/sdk/python/examples/controls/container/clickable/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-clickable" +version = "1.0.0" +description = "Container clickability showcase with non-clickable, clickable, and ink-enabled variants." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Clickable" +controls = ["SafeArea", "Row", "Container", "Text"] +layout_pattern = "row-showcase" +complexity = "basic" +features = ["click handling", "ink effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/handling_clicks.py b/sdk/python/examples/controls/container/handling_clicks/main.py similarity index 94% rename from sdk/python/examples/controls/container/handling_clicks.py rename to sdk/python/examples/controls/container/handling_clicks/main.py index 8e0cfe6d54..97eff47a73 100644 --- a/sdk/python/examples/controls/container/handling_clicks.py +++ b/sdk/python/examples/controls/container/handling_clicks/main.py @@ -16,7 +16,7 @@ def on_click(e): text=f" {cl_counter} ", style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), ) - page.update() + t1.update() def on_long_press(e): nonlocal lp_counter @@ -25,7 +25,7 @@ def on_long_press(e): text=f" {lp_counter} ", style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), ) - page.update() + t3.update() def on_tap_down(e): nonlocal td_counter @@ -34,7 +34,7 @@ def on_tap_down(e): text=f" {td_counter} ", style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), ) - page.update() + t2.update() c = ft.Container( bgcolor=ft.Colors.PINK_900, @@ -100,7 +100,8 @@ def on_tap_down(e): ] ) - page.add(c, t1, t3, t2) + page.add(ft.SafeArea(content=ft.Column(controls=[c, t1, t3, t2]))) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/handling_clicks/pyproject.toml b/sdk/python/examples/controls/container/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..221a4caddb --- /dev/null +++ b/sdk/python/examples/controls/container/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-handling-clicks" +version = "1.0.0" +description = "Container gesture handling demo with click, tap-down, and long-press counters." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "Container", "Text", "TextSpan"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["on_click", "on_tap_down", "on_long_press"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/handling_hovers.py b/sdk/python/examples/controls/container/handling_hovers.py deleted file mode 100644 index a53015a4ef..0000000000 --- a/sdk/python/examples/controls/container/handling_hovers.py +++ /dev/null @@ -1,20 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_hover(e: ft.Event[ft.Container]): - e.control.bgcolor = ft.Colors.BLUE if e.data else ft.Colors.RED - e.control.update() - - page.add( - ft.Container( - width=200, - height=200, - bgcolor=ft.Colors.RED, - ink=False, - on_hover=handle_hover, - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/container/handling_hovers/main.py b/sdk/python/examples/controls/container/handling_hovers/main.py new file mode 100644 index 0000000000..f054fb970a --- /dev/null +++ b/sdk/python/examples/controls/container/handling_hovers/main.py @@ -0,0 +1,23 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_hover(e: ft.Event[ft.Container]): + e.control.bgcolor = ft.Colors.BLUE if e.data else ft.Colors.RED + e.control.update() + + page.add( + ft.SafeArea( + content=ft.Container( + width=200, + height=200, + bgcolor=ft.Colors.RED, + ink=False, + on_hover=handle_hover, + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/handling_hovers/pyproject.toml b/sdk/python/examples/controls/container/handling_hovers/pyproject.toml new file mode 100644 index 0000000000..2c34612d4d --- /dev/null +++ b/sdk/python/examples/controls/container/handling_hovers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-handling-hovers" +version = "1.0.0" +description = "Container hover example that changes background color on pointer enter and leave." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Handling hovers" +controls = ["SafeArea", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["hover handling", "dynamic styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/nested_themes_1.py b/sdk/python/examples/controls/container/nested_themes_1.py deleted file mode 100644 index 53dc21bb79..0000000000 --- a/sdk/python/examples/controls/container/nested_themes_1.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - # Yellow page theme with SYSTEM (default) mode - page.theme = ft.Theme( - color_scheme_seed=ft.Colors.YELLOW, - ) - - page.add( - # Page theme - ft.Container( - content=ft.Button("Page theme button"), - bgcolor=ft.Colors.SURFACE_TINT, - padding=20, - width=300, - ), - # Inherited theme with primary color overridden - ft.Container( - theme=ft.Theme(color_scheme=ft.ColorScheme(primary=ft.Colors.PINK)), - content=ft.Button("Inherited theme button"), - bgcolor=ft.Colors.SURFACE_TINT, - padding=20, - width=300, - ), - # Unique always DARK theme - ft.Container( - theme=ft.Theme(color_scheme_seed=ft.Colors.INDIGO), - theme_mode=ft.ThemeMode.DARK, - content=ft.Button("Unique theme button"), - bgcolor=ft.Colors.SURFACE_TINT, - padding=20, - width=300, - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/container/nested_themes_1/main.py b/sdk/python/examples/controls/container/nested_themes_1/main.py new file mode 100644 index 0000000000..18669a08c7 --- /dev/null +++ b/sdk/python/examples/controls/container/nested_themes_1/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + # Yellow page theme with SYSTEM (default) mode + page.theme = ft.Theme( + color_scheme_seed=ft.Colors.YELLOW, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + # Page theme + ft.Container( + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Page theme button"), + ), + # Inherited theme with primary color overridden + ft.Container( + theme=ft.Theme( + color_scheme=ft.ColorScheme(primary=ft.Colors.PINK) + ), + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Inherited theme button"), + ), + # Unique always DARK theme + ft.Container( + theme=ft.Theme(color_scheme_seed=ft.Colors.INDIGO), + theme_mode=ft.ThemeMode.DARK, + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Unique theme button"), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/nested_themes_1/pyproject.toml b/sdk/python/examples/controls/container/nested_themes_1/pyproject.toml new file mode 100644 index 0000000000..73c0393525 --- /dev/null +++ b/sdk/python/examples/controls/container/nested_themes_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-nested-themes-1" +version = "1.0.0" +description = "Nested theme containers demonstrating inherited and overridden button color schemes." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Nested themes 1" +controls = ["SafeArea", "Column", "Container", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["nested themes", "theme override"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/nested_themes_2.py b/sdk/python/examples/controls/container/nested_themes_2.py deleted file mode 100644 index dc5fcfa828..0000000000 --- a/sdk/python/examples/controls/container/nested_themes_2.py +++ /dev/null @@ -1,73 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - # page.theme = ft.Theme( - # color_scheme_seed=ft.Colors.YELLOW, - # color_scheme=ft.ColorScheme( - # primary=ft.Colors.GREEN, primary_container=ft.Colors.GREEN_200 - # ), - # ) - - page.add( - ft.Row( - controls=[ - ft.Button("Page theme"), - ft.TextButton("Page theme text button"), - ft.Text( - "Text in primary container color", - color=ft.Colors.PRIMARY_CONTAINER, - ), - ] - ), - ft.Container( - height=100, - theme=ft.Theme(color_scheme=ft.ColorScheme(primary=ft.Colors.PINK)), - content=ft.Row( - controls=[ - ft.Button("Inherited theme with primary color overridden"), - ft.TextButton("Button 2"), - ] - ), - ), - ft.Container( - padding=20, - bgcolor=ft.Colors.SURFACE_TINT, - theme_mode=ft.ThemeMode.DARK, - theme=ft.Theme( - color_scheme_seed=ft.Colors.GREEN, - color_scheme=ft.ColorScheme(primary_container=ft.Colors.BLUE), - ), - content=ft.Row( - controls=[ - ft.Button("Always DARK theme"), - ft.TextButton("Text button"), - ft.Text( - "Text in primary container color", - color=ft.Colors.PRIMARY_CONTAINER, - ), - ] - ), - ), - ft.Container( - padding=20, - bgcolor=ft.Colors.SURFACE_TINT, - border=ft.Border.all(3, ft.Colors.OUTLINE), - theme_mode=ft.ThemeMode.LIGHT, - theme=ft.Theme(), - content=ft.Row( - controls=[ - ft.Button("Always LIGHT theme"), - ft.TextButton("Text button"), - ft.Text( - "Text in primary container color", - color=ft.Colors.PRIMARY_CONTAINER, - ), - ] - ), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/container/nested_themes_2/main.py b/sdk/python/examples/controls/container/nested_themes_2/main.py new file mode 100644 index 0000000000..e32cf9ad85 --- /dev/null +++ b/sdk/python/examples/controls/container/nested_themes_2/main.py @@ -0,0 +1,85 @@ +import flet as ft + + +def main(page: ft.Page): + # page.theme = ft.Theme( + # color_scheme_seed=ft.Colors.YELLOW, + # color_scheme=ft.ColorScheme( + # primary=ft.Colors.GREEN, primary_container=ft.Colors.GREEN_200 + # ), + # ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Button("Page theme"), + ft.TextButton("Page theme text button"), + ft.Text( + "Text in primary container color", + color=ft.Colors.PRIMARY_CONTAINER, + ), + ] + ), + ft.Container( + height=100, + theme=ft.Theme( + color_scheme=ft.ColorScheme(primary=ft.Colors.PINK) + ), + content=ft.Row( + controls=[ + ft.Button( + "Inherited theme with primary color overridden" + ), + ft.TextButton("Button 2"), + ] + ), + ), + ft.Container( + padding=20, + bgcolor=ft.Colors.SURFACE_TINT, + theme_mode=ft.ThemeMode.DARK, + theme=ft.Theme( + color_scheme_seed=ft.Colors.GREEN, + color_scheme=ft.ColorScheme( + primary_container=ft.Colors.BLUE + ), + ), + content=ft.Row( + controls=[ + ft.Button("Always DARK theme"), + ft.TextButton("Text button"), + ft.Text( + "Text in primary container color", + color=ft.Colors.PRIMARY_CONTAINER, + ), + ] + ), + ), + ft.Container( + padding=20, + bgcolor=ft.Colors.SURFACE_TINT, + border=ft.Border.all(3, ft.Colors.OUTLINE), + theme_mode=ft.ThemeMode.LIGHT, + theme=ft.Theme(), + content=ft.Row( + controls=[ + ft.Button("Always LIGHT theme"), + ft.TextButton("Text button"), + ft.Text( + "Text in primary container color", + color=ft.Colors.PRIMARY_CONTAINER, + ), + ] + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/nested_themes_2/pyproject.toml b/sdk/python/examples/controls/container/nested_themes_2/pyproject.toml new file mode 100644 index 0000000000..9ff856560c --- /dev/null +++ b/sdk/python/examples/controls/container/nested_themes_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-nested-themes-2" +version = "1.0.0" +description = "Multiple nested containers comparing page, dark, and light theme behaviors." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Nested themes 2" +controls = ["SafeArea", "Column", "Row", "Container", "Button", "TextButton", "Text"] +layout_pattern = "stacked-sections" +complexity = "basic" +features = ["nested themes", "theme mode override"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/nested_themes_3.py b/sdk/python/examples/controls/container/nested_themes_3.py deleted file mode 100644 index 42f191ce57..0000000000 --- a/sdk/python/examples/controls/container/nested_themes_3.py +++ /dev/null @@ -1,59 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.DARK - - def handle_switch_change(e: ft.Event[ft.Switch]): - if page.theme_mode == ft.ThemeMode.DARK: - page.theme_mode = ft.ThemeMode.LIGHT - switch.thumb_icon = ft.Icons.LIGHT_MODE - else: - switch.thumb_icon = ft.Icons.DARK_MODE - page.theme_mode = ft.ThemeMode.DARK - page.update() - - # Yellow page theme with SYSTEM (default) mode - page.theme = ft.Theme(color_scheme_seed=ft.Colors.YELLOW) - - switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=handle_switch_change) - - page.add( - # Page theme - ft.Row( - alignment=ft.MainAxisAlignment.SPACE_BETWEEN, - controls=[ - ft.Container( - content=ft.Button("Page theme button"), - bgcolor=ft.Colors.SURFACE_TINT, - padding=20, - width=300, - ), - ft.Container( - content=switch, - padding=ft.Padding.only(bottom=50), - alignment=ft.Alignment.TOP_RIGHT, - ), - ], - ), - # Inherited theme with primary color overridden - ft.Container( - theme=ft.Theme(color_scheme=ft.ColorScheme(primary=ft.Colors.PINK)), - content=ft.Button("Inherited theme button"), - bgcolor=ft.Colors.SURFACE_TINT, - padding=20, - width=300, - ), - # Unique always DARK theme - ft.Container( - theme=ft.Theme(color_scheme_seed=ft.Colors.INDIGO), - theme_mode=ft.ThemeMode.DARK, - content=ft.Button("Unique theme button"), - bgcolor=ft.Colors.SURFACE_TINT, - padding=20, - width=300, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/container/nested_themes_3/main.py b/sdk/python/examples/controls/container/nested_themes_3/main.py new file mode 100644 index 0000000000..a10153dc68 --- /dev/null +++ b/sdk/python/examples/controls/container/nested_themes_3/main.py @@ -0,0 +1,68 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.DARK + + def handle_switch_change(e: ft.Event[ft.Switch]): + if page.theme_mode == ft.ThemeMode.DARK: + page.theme_mode = ft.ThemeMode.LIGHT + switch.thumb_icon = ft.Icons.LIGHT_MODE + else: + switch.thumb_icon = ft.Icons.DARK_MODE + page.theme_mode = ft.ThemeMode.DARK + page.update() + + # Yellow page theme with SYSTEM (default) mode + page.theme = ft.Theme(color_scheme_seed=ft.Colors.YELLOW) + + switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=handle_switch_change) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + # Page theme + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Container( + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Page theme button"), + ), + ft.Container( + padding=ft.Padding.only(bottom=50), + alignment=ft.Alignment.TOP_RIGHT, + content=switch, + ), + ], + ), + # Inherited theme with primary color overridden + ft.Container( + theme=ft.Theme( + color_scheme=ft.ColorScheme(primary=ft.Colors.PINK) + ), + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Inherited theme button"), + ), + # Unique always DARK theme + ft.Container( + theme=ft.Theme(color_scheme_seed=ft.Colors.INDIGO), + theme_mode=ft.ThemeMode.DARK, + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Unique theme button"), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/nested_themes_3/pyproject.toml b/sdk/python/examples/controls/container/nested_themes_3/pyproject.toml new file mode 100644 index 0000000000..78d8336e09 --- /dev/null +++ b/sdk/python/examples/controls/container/nested_themes_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-nested-themes-3" +version = "1.0.0" +description = "Theme toggle example using a switch to change page mode across nested containers." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Nested themes 3" +controls = ["SafeArea", "Column", "Row", "Container", "Button", "Switch"] +layout_pattern = "stacked-sections" +complexity = "basic" +features = ["theme mode toggle", "nested themes"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/container/size_aware.py b/sdk/python/examples/controls/container/size_aware.py deleted file mode 100644 index 5268c3f786..0000000000 --- a/sdk/python/examples/controls/container/size_aware.py +++ /dev/null @@ -1,21 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_size_change(e: ft.LayoutSizeChangeEvent[ft.Container]): - e.control.content.value = f"{int(e.width)} x {int(e.height)}" - - page.add( - ft.Container( - expand=True, - alignment=ft.Alignment.CENTER, - bgcolor=ft.Colors.BLUE_ACCENT, - content=ft.Text(color=ft.Colors.WHITE, weight=ft.FontWeight.BOLD), - size_change_interval=100, - on_size_change=handle_size_change, - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/container/size_aware/main.py b/sdk/python/examples/controls/container/size_aware/main.py new file mode 100644 index 0000000000..3be1915288 --- /dev/null +++ b/sdk/python/examples/controls/container/size_aware/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_size_change(e: ft.LayoutSizeChangeEvent[ft.Container]): + e.control.content.value = f"{int(e.width)} x {int(e.height)}" + + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.BLUE_ACCENT, + size_change_interval=100, + on_size_change=handle_size_change, + content=ft.Text(color=ft.Colors.WHITE, weight=ft.FontWeight.BOLD), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/container/size_aware/pyproject.toml b/sdk/python/examples/controls/container/size_aware/pyproject.toml new file mode 100644 index 0000000000..3f543b3ea3 --- /dev/null +++ b/sdk/python/examples/controls/container/size_aware/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-size-aware" +version = "1.0.0" +description = "Size-aware container displaying live width and height updates on resize events." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Size aware" +controls = ["SafeArea", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["on_size_change", "responsive text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/container.md b/sdk/python/packages/flet/docs/controls/container.md index fbc8b479a5..8c76c1e07e 100644 --- a/sdk/python/packages/flet/docs/controls/container.md +++ b/sdk/python/packages/flet/docs/controls/container.md @@ -14,7 +14,7 @@ example_images: ../test-images/examples/material/golden/macos/container ### Clickable container ```python ---8<-- "{{ examples }}/clickable.py" +--8<-- "{{ examples }}/clickable/main.py" ``` {{ image(example_media + "/clickable.gif", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../test-images/examples/material/golden/macos/container ### Handling clicks ```python ---8<-- "{{ examples }}/handling_clicks.py" +--8<-- "{{ examples }}/handling_clicks/main.py" ``` {{ image(example_media + "/handling_clicks.gif", width="80%") }} @@ -31,7 +31,7 @@ example_images: ../test-images/examples/material/golden/macos/container ### Handling hovers ```python ---8<-- "{{ examples }}/handling_hovers.py" +--8<-- "{{ examples }}/handling_hovers/main.py" ``` {{ image(example_media + "/handling_hovers.gif", width="80%") }} @@ -40,7 +40,7 @@ example_images: ../test-images/examples/material/golden/macos/container ### Animate 1 ```python ---8<-- "{{ examples }}/animate_1.py" +--8<-- "{{ examples }}/animate_1/main.py" ``` {{ image(example_media + "/animate_1.gif", width="80%") }} @@ -49,25 +49,19 @@ example_images: ../test-images/examples/material/golden/macos/container ### Animate 2 ```python ---8<-- "{{ examples }}/animate_2.py" +--8<-- "{{ examples }}/animate_2/main.py" ``` ### Animate 3 ```python ---8<-- "{{ examples }}/animate_3.py" -``` - -### Animate 4 - -```python ---8<-- "{{ examples }}/animate_4.py" +--8<-- "{{ examples }}/animate_3/main.py" ``` ### Nested themes 1 ```python ---8<-- "{{ examples }}/nested_themes_1.py" +--8<-- "{{ examples }}/nested_themes_1/main.py" ``` {{ image(example_images + "/nested_themes_1.png", width="80%") }} @@ -75,7 +69,7 @@ example_images: ../test-images/examples/material/golden/macos/container ### Nested themes 2 ```python ---8<-- "{{ examples }}/nested_themes_2.py" +--8<-- "{{ examples }}/nested_themes_2/main.py" ``` {{ image(example_images + "/nested_themes_2.png", width="80%") }} @@ -83,7 +77,7 @@ example_images: ../test-images/examples/material/golden/macos/container ### Nested themes 3 ```python ---8<-- "{{ examples }}/nested_themes_3.py" +--8<-- "{{ examples }}/nested_themes_3/main.py" ``` {{ image(example_media + "/nested_themes_3.gif", width="80%") }} @@ -92,7 +86,7 @@ example_images: ../test-images/examples/material/golden/macos/container ### Size aware ```python ---8<-- "{{ examples }}/size_aware.py" +--8<-- "{{ examples }}/size_aware/main.py" ``` {{ image(example_images + "/size_aware.png", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/container/nested_themes_1.png b/sdk/python/packages/flet/integration_tests/examples/core/golden/macos/container/nested_themes_1.png similarity index 100% rename from sdk/python/packages/flet/integration_tests/examples/material/golden/macos/container/nested_themes_1.png rename to sdk/python/packages/flet/integration_tests/examples/core/golden/macos/container/nested_themes_1.png diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/container/nested_themes_2.png b/sdk/python/packages/flet/integration_tests/examples/core/golden/macos/container/nested_themes_2.png similarity index 100% rename from sdk/python/packages/flet/integration_tests/examples/material/golden/macos/container/nested_themes_2.png rename to sdk/python/packages/flet/integration_tests/examples/core/golden/macos/container/nested_themes_2.png diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/container/size_aware.png b/sdk/python/packages/flet/integration_tests/examples/core/golden/macos/container/size_aware.png similarity index 100% rename from sdk/python/packages/flet/integration_tests/examples/material/golden/macos/container/size_aware.png rename to sdk/python/packages/flet/integration_tests/examples/core/golden/macos/container/size_aware.png diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_container.py b/sdk/python/packages/flet/integration_tests/examples/core/test_container.py similarity index 89% rename from sdk/python/packages/flet/integration_tests/examples/material/test_container.py rename to sdk/python/packages/flet/integration_tests/examples/core/test_container.py index 0a03ddbba3..cb3b4fe70f 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_container.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_container.py @@ -1,11 +1,9 @@ import pytest +import examples.controls.container.nested_themes_1.main as nested_themes_1 +import examples.controls.container.nested_themes_2.main as nested_themes_2 +import examples.controls.container.size_aware.main as size_aware import flet.testing as ftt -from examples.controls.container import ( - nested_themes_1, - nested_themes_2, - size_aware, -) @pytest.mark.parametrize( From 70d983d149cf496a0bdad41996d7b49eb1850d85 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 12:11:34 -0700 Subject: [PATCH 40/96] Reorganize context_menu examples into subdirs Move context_menu example scripts into per-example directories (custom_trigger, programmatic_open, triggers) and add pyproject.toml metadata for each example. Deleted the old top-level example files and replaced them with examples/*/main.py, added SafeArea wrappers in the examples, updated docs to reference the new paths, and adjusted the integration test import to the new module location. --- .../controls/context_menu/__init__.py | 0 .../controls/context_menu/custom_trigger.py | 42 ---------------- .../context_menu/custom_trigger/main.py | 47 ++++++++++++++++++ .../custom_trigger/pyproject.toml | 26 ++++++++++ .../context_menu/programmatic_open.py | 38 --------------- .../context_menu/programmatic_open/main.py | 42 ++++++++++++++++ .../programmatic_open/pyproject.toml | 26 ++++++++++ .../controls/context_menu/triggers.py | 45 ----------------- .../controls/context_menu/triggers/main.py | 48 +++++++++++++++++++ .../context_menu/triggers/pyproject.toml | 26 ++++++++++ .../flet/docs/controls/contextmenu.md | 6 +-- .../examples/material/test_context_menu.py | 2 +- 12 files changed, 219 insertions(+), 129 deletions(-) delete mode 100644 sdk/python/examples/controls/context_menu/__init__.py delete mode 100644 sdk/python/examples/controls/context_menu/custom_trigger.py create mode 100644 sdk/python/examples/controls/context_menu/custom_trigger/main.py create mode 100644 sdk/python/examples/controls/context_menu/custom_trigger/pyproject.toml delete mode 100644 sdk/python/examples/controls/context_menu/programmatic_open.py create mode 100644 sdk/python/examples/controls/context_menu/programmatic_open/main.py create mode 100644 sdk/python/examples/controls/context_menu/programmatic_open/pyproject.toml delete mode 100644 sdk/python/examples/controls/context_menu/triggers.py create mode 100644 sdk/python/examples/controls/context_menu/triggers/main.py create mode 100644 sdk/python/examples/controls/context_menu/triggers/pyproject.toml diff --git a/sdk/python/examples/controls/context_menu/__init__.py b/sdk/python/examples/controls/context_menu/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/context_menu/custom_trigger.py b/sdk/python/examples/controls/context_menu/custom_trigger.py deleted file mode 100644 index e433df487b..0000000000 --- a/sdk/python/examples/controls/context_menu/custom_trigger.py +++ /dev/null @@ -1,42 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - async def open_menu(e: ft.TapEvent[ft.GestureDetector]): - await menu.open( - local_position=e.local_position, - global_position=e.global_position, - ) - - page.add( - menu := ft.ContextMenu( - expand=True, - items=[ - ft.PopupMenuItem( - content="Cut", - on_click=lambda e: print(f"{e.control.content}"), - ), - ft.PopupMenuItem( - content="Copy", - on_click=lambda e: print(f"{e.control.content}"), - ), - ft.PopupMenuItem( - content="Paste", - on_click=lambda e: print(f"{e.control.content}"), - ), - ], - content=ft.GestureDetector( - expand=True, - on_double_tap_down=open_menu, - content=ft.Container( - content=ft.Text("Double-click to open the context menu."), - bgcolor=ft.Colors.BLUE, - alignment=ft.Alignment.CENTER, - ), - ), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/context_menu/custom_trigger/main.py b/sdk/python/examples/controls/context_menu/custom_trigger/main.py new file mode 100644 index 0000000000..92cae28bf2 --- /dev/null +++ b/sdk/python/examples/controls/context_menu/custom_trigger/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + async def open_menu(e: ft.TapEvent[ft.GestureDetector]): + await menu.open( + local_position=e.local_position, + global_position=e.global_position, + ) + + menu = ft.ContextMenu( + expand=True, + items=[ + ft.PopupMenuItem( + content="Cut", + on_click=lambda e: print(f"{e.control.content}"), + ), + ft.PopupMenuItem( + content="Copy", + on_click=lambda e: print(f"{e.control.content}"), + ), + ft.PopupMenuItem( + content="Paste", + on_click=lambda e: print(f"{e.control.content}"), + ), + ], + content=ft.GestureDetector( + expand=True, + on_double_tap_down=open_menu, + content=ft.Container( + bgcolor=ft.Colors.BLUE, + alignment=ft.Alignment.CENTER, + content=ft.Text("Double-click to open the context menu."), + ), + ), + ) + + page.add( + ft.SafeArea( + expand=True, + content=menu, + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/context_menu/custom_trigger/pyproject.toml b/sdk/python/examples/controls/context_menu/custom_trigger/pyproject.toml new file mode 100644 index 0000000000..9ef4f4a086 --- /dev/null +++ b/sdk/python/examples/controls/context_menu/custom_trigger/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "context-menu-custom-trigger" +version = "1.0.0" +description = "Opens ContextMenu from a custom double-tap gesture with precise pointer position." +requires-python = ">=3.10" +keywords = ["context menu", "custom trigger", "gesture", "double tap"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/ContextMenu"] + +[tool.flet.metadata] +title = "Custom trigger" +controls = ["SafeArea", "ContextMenu", "PopupMenuItem", "GestureDetector", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom open trigger", "position-based menu opening"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/context_menu/programmatic_open.py b/sdk/python/examples/controls/context_menu/programmatic_open.py deleted file mode 100644 index 62e63e266c..0000000000 --- a/sdk/python/examples/controls/context_menu/programmatic_open.py +++ /dev/null @@ -1,38 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - def handle_select(e: ft.ContextMenuSelectEvent): - action = e.item.content - page.show_dialog(ft.SnackBar(f"Item '{action}' selected.")) - - async def open_menu(e: ft.Event[ft.Button]): - await menu.open() - - page.add( - menu := ft.ContextMenu( - on_select=handle_select, - content=ft.Button("Click to open menu", on_click=open_menu), - items=[ - ft.PopupMenuItem( - content="Item 1", - on_click=lambda e: print(f"{e.control.content}"), - ), - ft.PopupMenuItem( - content="Item 2", - on_click=lambda e: print(f"{e.control.content}"), - ), - ft.PopupMenuItem( - content="Item 3", - on_click=lambda e: print(f"{e.control.content}"), - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/context_menu/programmatic_open/main.py b/sdk/python/examples/controls/context_menu/programmatic_open/main.py new file mode 100644 index 0000000000..a9c02c06cf --- /dev/null +++ b/sdk/python/examples/controls/context_menu/programmatic_open/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + def handle_select(e: ft.ContextMenuSelectEvent): + action = e.item.content + page.show_dialog(ft.SnackBar(f"Item '{action}' selected.")) + + async def open_menu(e: ft.Event[ft.Button]): + await menu.open() + + menu = ft.ContextMenu( + on_select=handle_select, + items=[ + ft.PopupMenuItem( + content="Item 1", + on_click=lambda e: print(f"{e.control.content}"), + ), + ft.PopupMenuItem( + content="Item 2", + on_click=lambda e: print(f"{e.control.content}"), + ), + ft.PopupMenuItem( + content="Item 3", + on_click=lambda e: print(f"{e.control.content}"), + ), + ], + content=ft.Button("Click to open menu", on_click=open_menu), + ) + + page.add( + ft.SafeArea( + content=menu, + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/context_menu/programmatic_open/pyproject.toml b/sdk/python/examples/controls/context_menu/programmatic_open/pyproject.toml new file mode 100644 index 0000000000..d879bdad71 --- /dev/null +++ b/sdk/python/examples/controls/context_menu/programmatic_open/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "context-menu-programmatic-open" +version = "1.0.0" +description = "Programmatically opens ContextMenu from a button and handles selected menu actions." +requires-python = ">=3.10" +keywords = ["context menu", "programmatic open", "popup menu", "selection"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/ContextMenu"] + +[tool.flet.metadata] +title = "Programmatic open" +controls = ["SafeArea", "ContextMenu", "PopupMenuItem", "Button", "SnackBar"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["programmatic menu opening", "selection callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/context_menu/triggers.py b/sdk/python/examples/controls/context_menu/triggers.py deleted file mode 100644 index 9ad3e619fb..0000000000 --- a/sdk/python/examples/controls/context_menu/triggers.py +++ /dev/null @@ -1,45 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - # on web, disable default browser context menu - if page.web: - await page.browser_context_menu.disable() - - def handle_item_click(e: ft.Event[ft.PopupMenuItem]): - action = e.control.content - page.show_dialog(ft.SnackBar(content=f"Item '{action}' selected.")) - - page.add( - ft.ContextMenu( - primary_items=[ - ft.PopupMenuItem(content="Primary 1", on_click=handle_item_click), - ft.PopupMenuItem(content="Primary 2", on_click=handle_item_click), - ], - primary_trigger=ft.ContextMenuTrigger.DOWN, - secondary_items=[ - ft.PopupMenuItem(content="Secondary 1", on_click=handle_item_click), - ft.PopupMenuItem(content="Secondary 2", on_click=handle_item_click), - ], - secondary_trigger=ft.ContextMenuTrigger.DOWN, - tertiary_items=[ - ft.PopupMenuItem(content="Tertiary 1", on_click=handle_item_click), - ft.PopupMenuItem(content="Tertiary 2", on_click=handle_item_click), - ], - tertiary_trigger=ft.ContextMenuTrigger.DOWN, - on_select=lambda e: print(f"Selected item: {e.item.content}"), - on_dismiss=lambda e: print("Menu dismissed"), - expand=True, - content=ft.Container( - expand=True, - bgcolor=ft.Colors.BLUE, - alignment=ft.Alignment.CENTER, - border_radius=ft.BorderRadius.all(12), - content=ft.Text("Left/middle/right click to open a context menu."), - ), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/context_menu/triggers/main.py b/sdk/python/examples/controls/context_menu/triggers/main.py new file mode 100644 index 0000000000..0fac275403 --- /dev/null +++ b/sdk/python/examples/controls/context_menu/triggers/main.py @@ -0,0 +1,48 @@ +import flet as ft + + +async def main(page: ft.Page): + # on web, disable default browser context menu + if page.web: + await page.browser_context_menu.disable() + + def handle_item_click(e: ft.Event[ft.PopupMenuItem]): + action = e.control.content + page.show_dialog(ft.SnackBar(content=f"Item '{action}' selected.")) + + page.add( + ft.SafeArea( + expand=True, + content=ft.ContextMenu( + primary_items=[ + ft.PopupMenuItem(content="Primary 1", on_click=handle_item_click), + ft.PopupMenuItem(content="Primary 2", on_click=handle_item_click), + ], + primary_trigger=ft.ContextMenuTrigger.DOWN, + secondary_items=[ + ft.PopupMenuItem(content="Secondary 1", on_click=handle_item_click), + ft.PopupMenuItem(content="Secondary 2", on_click=handle_item_click), + ], + secondary_trigger=ft.ContextMenuTrigger.DOWN, + tertiary_items=[ + ft.PopupMenuItem(content="Tertiary 1", on_click=handle_item_click), + ft.PopupMenuItem(content="Tertiary 2", on_click=handle_item_click), + ], + tertiary_trigger=ft.ContextMenuTrigger.DOWN, + on_select=lambda e: print(f"Selected item: {e.item.content}"), + on_dismiss=lambda e: print("Menu dismissed"), + expand=True, + content=ft.Container( + expand=True, + bgcolor=ft.Colors.BLUE, + alignment=ft.Alignment.CENTER, + border_radius=ft.BorderRadius.all(12), + content=ft.Text("Left/middle/right click to open a context menu."), + ), + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/context_menu/triggers/pyproject.toml b/sdk/python/examples/controls/context_menu/triggers/pyproject.toml new file mode 100644 index 0000000000..1a54126e82 --- /dev/null +++ b/sdk/python/examples/controls/context_menu/triggers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "context-menu-triggers" +version = "1.0.0" +description = "ContextMenu trigger demo with separate primary, secondary, and tertiary click actions." +requires-python = ">=3.10" +keywords = ["context menu", "triggers", "popup menu", "mouse buttons"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/ContextMenu"] + +[tool.flet.metadata] +title = "Triggers" +controls = ["SafeArea", "ContextMenu", "PopupMenuItem", "Container", "Text", "SnackBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["multi-trigger menus", "item selection callback", "dismiss callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/contextmenu.md b/sdk/python/packages/flet/docs/controls/contextmenu.md index 9b86b016b7..1dbc5de055 100644 --- a/sdk/python/packages/flet/docs/controls/contextmenu.md +++ b/sdk/python/packages/flet/docs/controls/contextmenu.md @@ -11,13 +11,13 @@ example_images: ../test-images/examples/material/golden/macos/context_menu ### Triggers ```python ---8<-- "{{ examples }}/triggers.py" +--8<-- "{{ examples }}/triggers/main.py" ``` ## Programmatic open ```python ---8<-- "{{ examples }}/programmatic_open.py" +--8<-- "{{ examples }}/programmatic_open/main.py" ``` {{ image(example_images + "/programmatic_open.png", width="80%") }} @@ -25,7 +25,7 @@ example_images: ../test-images/examples/material/golden/macos/context_menu ## Programmatic open with custom trigger ```python ---8<-- "{{ examples }}/custom_trigger.py" +--8<-- "{{ examples }}/custom_trigger/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_context_menu.py b/sdk/python/packages/flet/integration_tests/examples/material/test_context_menu.py index 89f32ab44c..77be1e16b7 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_context_menu.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_context_menu.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.context_menu.programmatic_open.main as programmatic_open import flet as ft import flet.testing as ftt -from examples.controls.context_menu import programmatic_open @pytest.mark.asyncio(loop_scope="function") From 8472b56d56fcd525c8a07a3365d607d300c642f6 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 12:24:51 -0700 Subject: [PATCH 41/96] Refactor control examples into submodules Reorganize control examples into per-example folders with main.py entrypoints and add pyproject.toml metadata for each example. Wrap example containers in SafeArea where applicable, update documentation include paths to point to the new main.py locations, and adjust integration tests to import the relocated main() functions. Remove the old flat example files and the package __init__ to reflect the new layout. --- .../examples/controls/control/__init__.py | 0 .../main.py} | 12 +++-- .../expand_loose_chat_messages/pyproject.toml | 26 ++++++++++ .../control/expand_row_equal_split.py | 36 -------------- .../control/expand_row_equal_split/main.py | 38 +++++++++++++++ .../expand_row_equal_split/pyproject.toml | 26 ++++++++++ .../control/expand_row_proportional_1_3_1.py | 45 ------------------ .../expand_row_proportional_1_3_1/main.py | 47 +++++++++++++++++++ .../pyproject.toml | 26 ++++++++++ .../control/expand_textfield_in_row.py | 22 --------- .../control/expand_textfield_in_row/main.py | 24 ++++++++++ .../expand_textfield_in_row/pyproject.toml | 26 ++++++++++ .../flet/docs/cookbook/expanding-controls.md | 8 ++-- .../examples/core/test_control.py | 24 ++++++---- 14 files changed, 239 insertions(+), 121 deletions(-) delete mode 100644 sdk/python/examples/controls/control/__init__.py rename sdk/python/examples/controls/control/{expand_loose_chat_messages.py => expand_loose_chat_messages/main.py} (93%) create mode 100644 sdk/python/examples/controls/control/expand_loose_chat_messages/pyproject.toml delete mode 100644 sdk/python/examples/controls/control/expand_row_equal_split.py create mode 100644 sdk/python/examples/controls/control/expand_row_equal_split/main.py create mode 100644 sdk/python/examples/controls/control/expand_row_equal_split/pyproject.toml delete mode 100644 sdk/python/examples/controls/control/expand_row_proportional_1_3_1.py create mode 100644 sdk/python/examples/controls/control/expand_row_proportional_1_3_1/main.py create mode 100644 sdk/python/examples/controls/control/expand_row_proportional_1_3_1/pyproject.toml delete mode 100644 sdk/python/examples/controls/control/expand_textfield_in_row.py create mode 100644 sdk/python/examples/controls/control/expand_textfield_in_row/main.py create mode 100644 sdk/python/examples/controls/control/expand_textfield_in_row/pyproject.toml diff --git a/sdk/python/examples/controls/control/__init__.py b/sdk/python/examples/controls/control/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/control/expand_loose_chat_messages.py b/sdk/python/examples/controls/control/expand_loose_chat_messages/main.py similarity index 93% rename from sdk/python/examples/controls/control/expand_loose_chat_messages.py rename to sdk/python/examples/controls/control/expand_loose_chat_messages/main.py index 4b67623693..2c23e6dca7 100644 --- a/sdk/python/examples/controls/control/expand_loose_chat_messages.py +++ b/sdk/python/examples/controls/control/expand_loose_chat_messages/main.py @@ -76,11 +76,13 @@ def main(page: ft.Page): ) page.add( - ft.Container( - content=chat, - width=300, - height=500, - ) + ft.SafeArea( + content=ft.Container( + width=300, + height=500, + content=chat, + ) + ), ) diff --git a/sdk/python/examples/controls/control/expand_loose_chat_messages/pyproject.toml b/sdk/python/examples/controls/control/expand_loose_chat_messages/pyproject.toml new file mode 100644 index 0000000000..027409c582 --- /dev/null +++ b/sdk/python/examples/controls/control/expand_loose_chat_messages/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "control-expand-loose-chat-messages" +version = "1.0.0" +description = "Chat message layout demo using expand_loose for flexible message bubble sizing in rows." +requires-python = ">=3.10" +keywords = ["control", "expand_loose", "chat", "row", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Control"] + +[tool.flet.metadata] +title = "Expand loose chat messages" +controls = ["SafeArea", "Container", "ListView", "Row", "Text", "Column"] +layout_pattern = "chat" +complexity = "basic" +features = ["expand_loose behavior", "chat message bubbles"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/control/expand_row_equal_split.py b/sdk/python/examples/controls/control/expand_row_equal_split.py deleted file mode 100644 index 02ef2de503..0000000000 --- a/sdk/python/examples/controls/control/expand_row_equal_split.py +++ /dev/null @@ -1,36 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Container( - width=500, - height=180, - padding=10, - border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), - border_radius=10, - content=ft.Row( - spacing=8, - controls=[ - ft.Container( - expand=True, - bgcolor=ft.Colors.ORANGE_300, - border_radius=8, - alignment=ft.Alignment.CENTER, - content=ft.Text("Card 1"), - ), - ft.Container( - expand=True, - bgcolor=ft.Colors.GREEN_200, - border_radius=8, - alignment=ft.Alignment.CENTER, - content=ft.Text("Card 2"), - ), - ], - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/control/expand_row_equal_split/main.py b/sdk/python/examples/controls/control/expand_row_equal_split/main.py new file mode 100644 index 0000000000..624934537d --- /dev/null +++ b/sdk/python/examples/controls/control/expand_row_equal_split/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Container( + width=500, + height=180, + padding=10, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=10, + content=ft.Row( + spacing=8, + controls=[ + ft.Container( + expand=True, + bgcolor=ft.Colors.ORANGE_300, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("Card 1"), + ), + ft.Container( + expand=True, + bgcolor=ft.Colors.GREEN_200, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("Card 2"), + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/control/expand_row_equal_split/pyproject.toml b/sdk/python/examples/controls/control/expand_row_equal_split/pyproject.toml new file mode 100644 index 0000000000..09355576dd --- /dev/null +++ b/sdk/python/examples/controls/control/expand_row_equal_split/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "control-expand-row-equal-split" +version = "1.0.0" +description = "Row example where two containers equally split available horizontal space with expand=True." +requires-python = ">=3.10" +keywords = ["control", "expand", "row", "equal split", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Control"] + +[tool.flet.metadata] +title = "Expand row equal split" +controls = ["SafeArea", "Container", "Row", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["equal expand split", "row layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/control/expand_row_proportional_1_3_1.py b/sdk/python/examples/controls/control/expand_row_proportional_1_3_1.py deleted file mode 100644 index c025b9347e..0000000000 --- a/sdk/python/examples/controls/control/expand_row_proportional_1_3_1.py +++ /dev/null @@ -1,45 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Container( - width=500, - padding=10, - border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), - border_radius=10, - content=ft.Row( - spacing=8, - controls=[ - ft.Container( - expand=1, - height=60, - bgcolor=ft.Colors.CYAN_300, - alignment=ft.Alignment.CENTER, - border_radius=8, - content=ft.Text("1"), - ), - ft.Container( - expand=3, - height=60, - bgcolor=ft.Colors.AMBER_300, - alignment=ft.Alignment.CENTER, - border_radius=8, - content=ft.Text("3"), - ), - ft.Container( - expand=1, - height=60, - bgcolor=ft.Colors.PINK_200, - alignment=ft.Alignment.CENTER, - border_radius=8, - content=ft.Text("1"), - ), - ], - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/control/expand_row_proportional_1_3_1/main.py b/sdk/python/examples/controls/control/expand_row_proportional_1_3_1/main.py new file mode 100644 index 0000000000..65e1f27dd9 --- /dev/null +++ b/sdk/python/examples/controls/control/expand_row_proportional_1_3_1/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Container( + width=500, + padding=10, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=10, + content=ft.Row( + spacing=8, + controls=[ + ft.Container( + expand=1, + height=60, + bgcolor=ft.Colors.CYAN_300, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("1"), + ), + ft.Container( + expand=3, + height=60, + bgcolor=ft.Colors.AMBER_300, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("3"), + ), + ft.Container( + expand=1, + height=60, + bgcolor=ft.Colors.PINK_200, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("1"), + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/control/expand_row_proportional_1_3_1/pyproject.toml b/sdk/python/examples/controls/control/expand_row_proportional_1_3_1/pyproject.toml new file mode 100644 index 0000000000..d49c520dfa --- /dev/null +++ b/sdk/python/examples/controls/control/expand_row_proportional_1_3_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "control-expand-row-proportional-1-3-1" +version = "1.0.0" +description = "Row example using proportional expand values (1:3:1) for responsive width distribution." +requires-python = ">=3.10" +keywords = ["control", "expand", "row", "proportional", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Control"] + +[tool.flet.metadata] +title = "Expand row proportional 1 3 1" +controls = ["SafeArea", "Container", "Row", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["proportional expand", "row space distribution"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/control/expand_textfield_in_row.py b/sdk/python/examples/controls/control/expand_textfield_in_row.py deleted file mode 100644 index 1da25f2cd9..0000000000 --- a/sdk/python/examples/controls/control/expand_textfield_in_row.py +++ /dev/null @@ -1,22 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Container( - width=480, - padding=10, - border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), - border_radius=10, - content=ft.Row( - controls=[ - ft.TextField(hint_text="Enter your name", expand=True), - ft.Button("Join chat"), - ] - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/control/expand_textfield_in_row/main.py b/sdk/python/examples/controls/control/expand_textfield_in_row/main.py new file mode 100644 index 0000000000..e890745122 --- /dev/null +++ b/sdk/python/examples/controls/control/expand_textfield_in_row/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Container( + width=480, + padding=10, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=10, + content=ft.Row( + controls=[ + ft.TextField(hint_text="Enter your name", expand=True), + ft.Button("Join chat"), + ] + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/control/expand_textfield_in_row/pyproject.toml b/sdk/python/examples/controls/control/expand_textfield_in_row/pyproject.toml new file mode 100644 index 0000000000..34e1114ea1 --- /dev/null +++ b/sdk/python/examples/controls/control/expand_textfield_in_row/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "control-expand-textfield-in-row" +version = "1.0.0" +description = "Row layout with an expanding TextField and fixed-size action button." +requires-python = ">=3.10" +keywords = ["control", "expand", "row", "textfield", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Control"] + +[tool.flet.metadata] +title = "Expand textfield in row" +controls = ["SafeArea", "Container", "Row", "TextField", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["expand in row", "mixed flexible and fixed controls"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/cookbook/expanding-controls.md b/sdk/python/packages/flet/docs/cookbook/expanding-controls.md index b23868ad10..29923d09f3 100644 --- a/sdk/python/packages/flet/docs/cookbook/expanding-controls.md +++ b/sdk/python/packages/flet/docs/cookbook/expanding-controls.md @@ -27,7 +27,7 @@ In this example, a [`TextField`][flet.TextField] stretches to fill all remaining while the [`Button`][flet.Button] stays sized to its content: ```python ---8<-- "{{ examples }}/expand_textfield_in_row.py" +--8<-- "{{ examples }}/expand_textfield_in_row/main.py" ``` {{ image(example_images + "/expand_textfield_in_row.png", alt="expand textfield in row", width="70%") }} @@ -37,7 +37,7 @@ while the [`Button`][flet.Button] stays sized to its content: In this example, we create a [`Row`][flet.Row] with three [`Container`][flet.Container]s, distributed like 20% / 60% / 20%: ```python ---8<-- "{{ examples }}/expand_row_proportional_1_3_1.py" +--8<-- "{{ examples }}/expand_row_proportional_1_3_1/main.py" ``` Here, the available space is split into 5 total parts (1+3+1). @@ -54,7 +54,7 @@ The layout uses a parent [`Container`][flet.Container] and a nested row, where b expanded equally, resulting in a 50/50 split. ```python ---8<-- "{{ examples }}/expand_row_equal_split.py" +--8<-- "{{ examples }}/expand_row_equal_split/main.py" ``` {{ image(example_images + "/expand_row_equal_split.png", alt="expand row equal split", width="70%") }} @@ -81,7 +81,7 @@ or any of their subclasses: [`Row`][flet.Row], [`Column`][flet.Column], [`View`] In this example, [`Container`][flet.Container]s being placed in [`Row`][flet.Row]s with `expand_loose = True`: ```python ---8<-- "{{ examples }}/expand_loose_chat_messages.py" +--8<-- "{{ examples }}/expand_loose_chat_messages/main.py" ``` {{ image(example_images + "/expand_loose_chat_messages.png", alt="expand loose chat messages", width="70%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_control.py b/sdk/python/packages/flet/integration_tests/examples/core/test_control.py index 17b51ddeb4..b306dd9ede 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_control.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_control.py @@ -1,17 +1,23 @@ import pytest import flet.testing as ftt -from examples.controls.control import ( - expand_loose_chat_messages, - expand_row_equal_split, - expand_row_proportional_1_3_1, - expand_textfield_in_row, +from examples.controls.control.expand_loose_chat_messages import ( + main as expand_loose_chat_messages_main, +) +from examples.controls.control.expand_row_equal_split import ( + main as expand_row_equal_split_main, +) +from examples.controls.control.expand_row_proportional_1_3_1 import ( + main as expand_row_proportional_1_3_1_main, +) +from examples.controls.control.expand_textfield_in_row import ( + main as expand_textfield_in_row_main, ) @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": expand_textfield_in_row.main}], + [{"flet_app_main": expand_textfield_in_row_main.main}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") @@ -24,7 +30,7 @@ async def test_expand_textfield_in_row(flet_app_function: ftt.FletTestApp): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": expand_row_proportional_1_3_1.main}], + [{"flet_app_main": expand_row_proportional_1_3_1_main.main}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") @@ -37,7 +43,7 @@ async def test_expand_row_proportional_1_3_1(flet_app_function: ftt.FletTestApp) @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": expand_row_equal_split.main}], + [{"flet_app_main": expand_row_equal_split_main.main}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") @@ -50,7 +56,7 @@ async def test_expand_row_equal_split(flet_app_function: ftt.FletTestApp): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": expand_loose_chat_messages.main}], + [{"flet_app_main": expand_loose_chat_messages_main.main}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") From 80e810bf24a825fd758c47bfb2cf4028d62433d3 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 12:49:26 -0700 Subject: [PATCH 42/96] Organize Cupertino examples and add metadata Move and restructure multiple Cupertino example scripts into per-example main.py entrypoints, wrap UIs with SafeArea/Column, add message logging columns and stronger event typing, and add if __name__ == "__main__" guards. Add pyproject.toml metadata for each example (gallery categories, controls, features). Remove the old top-level example .py files and update documentation references to the new paths. --- .../{basic.py => basic/main.py} | 35 +++++--- .../basic/pyproject.toml | 26 ++++++ .../cupertino_activity_indicator/basic.py | 14 --- .../basic/main.py | 20 +++++ .../basic/pyproject.toml | 26 ++++++ .../cupertino_activity_indicator/progress.py | 26 ------ .../progress/main.py | 36 ++++++++ .../progress/pyproject.toml | 26 ++++++ .../cupertino_material_and_adaptive.py | 75 ---------------- .../cupertino_material_and_adaptive/main.py | 86 +++++++++++++++++++ .../pyproject.toml | 26 ++++++ .../file_deletion_confirmation.py | 38 -------- .../file_deletion_confirmation/main.py | 51 +++++++++++ .../file_deletion_confirmation/pyproject.toml | 26 ++++++ .../{basic.py => basic/main.py} | 9 +- .../cupertino_app_bar/basic/pyproject.toml | 26 ++++++ .../main.py} | 12 ++- .../theme_mode_toggle/pyproject.toml | 26 ++++++ .../controls/cupertino_button/basic.py | 44 ---------- .../controls/cupertino_button/basic/main.py | 54 ++++++++++++ .../cupertino_button/basic/pyproject.toml | 26 ++++++ .../cupertino_material_and_adaptive.py | 16 ---- .../cupertino_material_and_adaptive/main.py | 30 +++++++ .../pyproject.toml | 26 ++++++ .../controls/cupertino_checkbox/styled.py | 49 ----------- .../cupertino_checkbox/styled/main.py | 44 ++++++++++ .../cupertino_checkbox/styled/pyproject.toml | 26 ++++++ .../controls/cupertino_context_menu/basic.py | 35 -------- .../cupertino_context_menu/basic/main.py | 38 ++++++++ .../basic/pyproject.toml | 26 ++++++ .../controls/cupertino_date_picker/basic.py | 34 -------- .../cupertino_date_picker/basic/main.py | 43 ++++++++++ .../basic/pyproject.toml | 26 ++++++ .../cupertino_date_picker/custom_locale.py | 24 ------ .../custom_locale/main.py | 27 ++++++ .../custom_locale/pyproject.toml | 26 ++++++ .../controls/cupertino_filled_button/basic.py | 14 --- .../cupertino_filled_button/basic/main.py | 17 ++++ .../basic/pyproject.toml | 26 ++++++ .../controls/cupertinoactionsheet/index.md | 2 +- .../controls/cupertinoactivityindicator.md | 2 +- .../docs/controls/cupertinoalertdialog.md | 4 +- .../flet/docs/controls/cupertinoappbar.md | 4 +- .../flet/docs/controls/cupertinobutton.md | 2 +- .../flet/docs/controls/cupertinocheckbox.md | 4 +- .../controls/cupertinocontextmenu/index.md | 2 +- .../flet/docs/controls/cupertinodatepicker.md | 2 +- .../docs/controls/cupertinofilledbutton.md | 2 +- 48 files changed, 860 insertions(+), 399 deletions(-) rename sdk/python/examples/controls/cupertino_action_sheet/{basic.py => basic/main.py} (65%) create mode 100644 sdk/python/examples/controls/cupertino_action_sheet/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_activity_indicator/basic.py create mode 100644 sdk/python/examples/controls/cupertino_activity_indicator/basic/main.py create mode 100644 sdk/python/examples/controls/cupertino_activity_indicator/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_activity_indicator/progress.py create mode 100644 sdk/python/examples/controls/cupertino_activity_indicator/progress/main.py create mode 100644 sdk/python/examples/controls/cupertino_activity_indicator/progress/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive.py create mode 100644 sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive/main.py create mode 100644 sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation.py create mode 100644 sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation/main.py create mode 100644 sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation/pyproject.toml rename sdk/python/examples/controls/cupertino_app_bar/{basic.py => basic/main.py} (77%) create mode 100644 sdk/python/examples/controls/cupertino_app_bar/basic/pyproject.toml rename sdk/python/examples/controls/cupertino_app_bar/{theme_mode_toggle.py => theme_mode_toggle/main.py} (84%) create mode 100644 sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_button/basic.py create mode 100644 sdk/python/examples/controls/cupertino_button/basic/main.py create mode 100644 sdk/python/examples/controls/cupertino_button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive.py create mode 100644 sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive/main.py create mode 100644 sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_checkbox/styled.py create mode 100644 sdk/python/examples/controls/cupertino_checkbox/styled/main.py create mode 100644 sdk/python/examples/controls/cupertino_checkbox/styled/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_context_menu/basic.py create mode 100644 sdk/python/examples/controls/cupertino_context_menu/basic/main.py create mode 100644 sdk/python/examples/controls/cupertino_context_menu/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_date_picker/basic.py create mode 100644 sdk/python/examples/controls/cupertino_date_picker/basic/main.py create mode 100644 sdk/python/examples/controls/cupertino_date_picker/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_date_picker/custom_locale.py create mode 100644 sdk/python/examples/controls/cupertino_date_picker/custom_locale/main.py create mode 100644 sdk/python/examples/controls/cupertino_date_picker/custom_locale/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_filled_button/basic.py create mode 100644 sdk/python/examples/controls/cupertino_filled_button/basic/main.py create mode 100644 sdk/python/examples/controls/cupertino_filled_button/basic/pyproject.toml diff --git a/sdk/python/examples/controls/cupertino_action_sheet/basic.py b/sdk/python/examples/controls/cupertino_action_sheet/basic/main.py similarity index 65% rename from sdk/python/examples/controls/cupertino_action_sheet/basic.py rename to sdk/python/examples/controls/cupertino_action_sheet/basic/main.py index a17a30c4ba..e1b6dfd77b 100644 --- a/sdk/python/examples/controls/cupertino_action_sheet/basic.py +++ b/sdk/python/examples/controls/cupertino_action_sheet/basic/main.py @@ -4,37 +4,39 @@ def main(page: ft.Page): page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - def handle_click(e): - page.add(ft.Text(f"Action clicked: {e.control.content.value}")) + messages = ft.Column(tight=True) + + def handle_click(e: ft.Event[ft.CupertinoActionSheetAction]): + messages.controls.append(ft.Text(f"Action clicked: {e.control.content.value}")) page.pop_dialog() action_sheet = ft.CupertinoActionSheet( title=ft.Row( - controls=[ft.Text("Title"), ft.Icon(ft.Icons.BEDTIME)], alignment=ft.MainAxisAlignment.CENTER, + controls=[ft.Text("Title"), ft.Icon(ft.Icons.BEDTIME)], ), message=ft.Row( - controls=[ft.Text("Description"), ft.Icon(ft.Icons.AUTO_AWESOME)], alignment=ft.MainAxisAlignment.CENTER, + controls=[ft.Text("Description"), ft.Icon(ft.Icons.AUTO_AWESOME)], ), cancel=ft.CupertinoActionSheetAction( - content=ft.Text("Cancel"), on_click=handle_click, + content=ft.Text("Cancel"), ), actions=[ ft.CupertinoActionSheetAction( - content=ft.Text("Default Action"), default=True, on_click=handle_click, + content=ft.Text("Default Action"), ), ft.CupertinoActionSheetAction( - content=ft.Text("Normal Action"), on_click=handle_click, + content=ft.Text("Normal Action"), ), ft.CupertinoActionSheetAction( - content=ft.Text("Destructive Action"), destructive=True, on_click=handle_click, + content=ft.Text("Destructive Action"), ), ], ) @@ -42,11 +44,20 @@ def handle_click(e): bottom_sheet = ft.CupertinoBottomSheet(action_sheet) page.add( - ft.CupertinoFilledButton( - content="Open CupertinoBottomSheet", - on_click=lambda e: page.show_dialog(bottom_sheet), + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog(bottom_sheet), + content="Open CupertinoBottomSheet", + ), + messages, + ], + ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_action_sheet/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_action_sheet/basic/pyproject.toml new file mode 100644 index 0000000000..d75c53aeda --- /dev/null +++ b/sdk/python/examples/controls/cupertino_action_sheet/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-action-sheet-basic" +version = "1.0.0" +description = "Opens a CupertinoActionSheet in a CupertinoBottomSheet and logs the selected action." +requires-python = ">=3.10" +keywords = ["cupertino", "action sheet", "bottom sheet", "dialog"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/CupertinoActionSheet"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "CupertinoFilledButton", "CupertinoBottomSheet", "CupertinoActionSheet", "CupertinoActionSheetAction", "Text", "Row", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["open dialog", "action callbacks", "destructive action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_activity_indicator/basic.py b/sdk/python/examples/controls/cupertino_activity_indicator/basic.py deleted file mode 100644 index e0aaf62d2c..0000000000 --- a/sdk/python/examples/controls/cupertino_activity_indicator/basic.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.CupertinoActivityIndicator( - animating=True, - color=ft.Colors.RED, - radius=50, - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_activity_indicator/basic/main.py b/sdk/python/examples/controls/cupertino_activity_indicator/basic/main.py new file mode 100644 index 0000000000..daaac7718d --- /dev/null +++ b/sdk/python/examples/controls/cupertino_activity_indicator/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.CupertinoActivityIndicator( + animating=True, + color=ft.Colors.RED, + radius=50, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_activity_indicator/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_activity_indicator/basic/pyproject.toml new file mode 100644 index 0000000000..059023c68e --- /dev/null +++ b/sdk/python/examples/controls/cupertino_activity_indicator/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-activity-indicator-basic" +version = "1.0.0" +description = "Shows a centered CupertinoActivityIndicator with custom color and radius." +requires-python = ">=3.10" +keywords = ["cupertino", "activity indicator", "loading", "spinner"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/CupertinoActivityIndicator"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoActivityIndicator"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["indeterminate loading state", "custom radius", "custom color"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_activity_indicator/progress.py b/sdk/python/examples/controls/cupertino_activity_indicator/progress.py deleted file mode 100644 index da74c76db3..0000000000 --- a/sdk/python/examples/controls/cupertino_activity_indicator/progress.py +++ /dev/null @@ -1,26 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.spacing = 20 - - def handle_progress_change(e: ft.Event[ft.Slider]): - indicator.progress = e.control.value - - page.add( - indicator := ft.CupertinoActivityIndicator(progress=1.0, radius=40), - ft.Slider( - min=0.0, - value=indicator.progress, - max=1.0, - divisions=10, - round=1, - label="Progress = {value}", - width=400, - on_change=handle_progress_change, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_activity_indicator/progress/main.py b/sdk/python/examples/controls/cupertino_activity_indicator/progress/main.py new file mode 100644 index 0000000000..5e961f6871 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_activity_indicator/progress/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +async def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 20 + + indicator = ft.CupertinoActivityIndicator(progress=1.0, radius=40) + + def handle_progress_change(e: ft.Event[ft.Slider]): + indicator.progress = e.control.value + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + indicator, + ft.Slider( + min=0.0, + value=indicator.progress, + max=1.0, + divisions=10, + round=1, + label="Progress = {value}", + width=400, + on_change=handle_progress_change, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_activity_indicator/progress/pyproject.toml b/sdk/python/examples/controls/cupertino_activity_indicator/progress/pyproject.toml new file mode 100644 index 0000000000..9b9dd80ced --- /dev/null +++ b/sdk/python/examples/controls/cupertino_activity_indicator/progress/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-activity-indicator-progress" +version = "1.0.0" +description = "Drives CupertinoActivityIndicator progress with a slider for determinate loading feedback." +requires-python = ">=3.10" +keywords = ["cupertino", "activity indicator", "progress", "slider"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/CupertinoActivityIndicator"] + +[tool.flet.metadata] +title = "Progress" +controls = ["SafeArea", "Column", "CupertinoActivityIndicator", "Slider"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["determinate progress", "slider-driven updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive.py b/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive.py deleted file mode 100644 index 8dc1105614..0000000000 --- a/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive.py +++ /dev/null @@ -1,75 +0,0 @@ -from typing import Union - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.scroll = ft.ScrollMode.AUTO - - def handle_action_click( - e: ft.Event[Union[ft.TextButton, ft.CupertinoDialogAction]], - ): - page.add(ft.Text(f"Action clicked: {e.control.content}")) - page.pop_dialog() - - cupertino_actions = [ - ft.CupertinoDialogAction( - content="Yes", - destructive=True, - on_click=handle_action_click, - ), - ft.CupertinoDialogAction( - content="No", - default=False, - on_click=handle_action_click, - ), - ] - - material_actions = [ - ft.TextButton(content="Yes", on_click=handle_action_click), - ft.TextButton(content="No", on_click=handle_action_click), - ] - - page.add( - ft.FilledButton( - content="Open Material Dialog", - on_click=lambda e: page.show_dialog( - ft.AlertDialog( - title=ft.Text("Material Alert Dialog"), - content=ft.Text("Do you want to delete this file?"), - actions=material_actions, - ) - ), - ), - ft.CupertinoFilledButton( - content="Open Cupertino Dialog", - on_click=lambda e: page.show_dialog( - ft.CupertinoAlertDialog( - title=ft.Text("Cupertino Alert Dialog"), - content=ft.Text("Do you want to delete this file?"), - actions=cupertino_actions, - ) - ), - ), - ft.FilledButton( - content="Open Adaptive Dialog", - adaptive=True, - bgcolor=ft.Colors.BLUE_ACCENT, - on_click=lambda e: page.show_dialog( - ft.AlertDialog( - adaptive=True, - title=ft.Text("Adaptive Alert Dialog"), - content=ft.Text("Do you want to delete this file?"), - actions=( - cupertino_actions - if page.platform.is_apple() - else material_actions - ), - ) - ), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..a2ebc10673 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive/main.py @@ -0,0 +1,86 @@ +from typing import Union + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.scroll = ft.ScrollMode.AUTO + + messages = ft.Column(tight=True) + + def handle_action_click( + e: ft.Event[Union[ft.TextButton, ft.CupertinoDialogAction]], + ): + messages.controls.append(ft.Text(f"Action clicked: {e.control.content}")) + page.pop_dialog() + + cupertino_actions = [ + ft.CupertinoDialogAction( + destructive=True, + on_click=handle_action_click, + content="Yes", + ), + ft.CupertinoDialogAction( + default=False, + on_click=handle_action_click, + content="No", + ), + ] + + material_actions = [ + ft.TextButton(on_click=handle_action_click, content="Yes"), + ft.TextButton(on_click=handle_action_click, content="No"), + ] + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.FilledButton( + on_click=lambda _: page.show_dialog( + ft.AlertDialog( + title=ft.Text("Material Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + actions=material_actions, + ) + ), + content="Open Material Dialog", + ), + ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog( + ft.CupertinoAlertDialog( + title=ft.Text("Cupertino Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + actions=cupertino_actions, + ) + ), + content="Open Cupertino Dialog", + ), + ft.FilledButton( + adaptive=True, + bgcolor=ft.Colors.BLUE_ACCENT, + on_click=lambda _: page.show_dialog( + ft.AlertDialog( + adaptive=True, + title=ft.Text("Adaptive Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + actions=( + cupertino_actions + if page.platform.is_apple() + else material_actions + ), + ) + ), + content="Open Adaptive Dialog", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..9493419196 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_alert_dialog/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-alert-dialog-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Compares Material, Cupertino, and adaptive alert dialogs with platform-aware action sets." +requires-python = ">=3.10" +keywords = ["cupertino", "material", "adaptive", "alert dialog", "platform"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/CupertinoAlertDialog"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "FilledButton", "CupertinoFilledButton", "AlertDialog", "CupertinoAlertDialog", "TextButton", "CupertinoDialogAction", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["platform-adaptive dialog", "material and cupertino comparison", "action callbacks"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation.py b/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation.py deleted file mode 100644 index c98dd53155..0000000000 --- a/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation.py +++ /dev/null @@ -1,38 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_dialog_dismissal(e: ft.Event[ft.DialogControl]): - page.add(ft.Text("Dialog dismissed")) - - def handle_action_click(e: ft.Event[ft.CupertinoDialogAction]): - page.add(ft.Text(f"Action clicked: {e.control.content}")) - page.pop_dialog() - - cupertino_alert_dialog = ft.CupertinoAlertDialog( - title=ft.Text("Cupertino Alert Dialog"), - content=ft.Text("Do you want to delete this file?"), - on_dismiss=handle_dialog_dismissal, - actions=[ - ft.CupertinoDialogAction( - content="Yes", - destructive=True, - on_click=handle_action_click, - ), - ft.CupertinoDialogAction( - content="No", default=True, on_click=handle_action_click - ), - ], - ) - - page.add( - ft.CupertinoFilledButton( - content="Open CupertinoAlertDialog", - on_click=lambda e: page.show_dialog(cupertino_alert_dialog), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation/main.py b/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation/main.py new file mode 100644 index 0000000000..59b81d76d7 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation/main.py @@ -0,0 +1,51 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + messages = ft.Column(tight=True) + + def handle_dialog_dismissal(_: ft.Event[ft.DialogControl]): + messages.controls.append(ft.Text("Dialog dismissed")) + + def handle_action_click(e: ft.Event[ft.CupertinoDialogAction]): + messages.controls.append(ft.Text(f"Action clicked: {e.control.content}")) + page.pop_dialog() + + cupertino_alert_dialog = ft.CupertinoAlertDialog( + title=ft.Text("Cupertino Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + on_dismiss=handle_dialog_dismissal, + actions=[ + ft.CupertinoDialogAction( + destructive=True, + on_click=handle_action_click, + content="Yes", + ), + ft.CupertinoDialogAction( + default=True, + on_click=handle_action_click, + content="No", + ), + ], + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog(cupertino_alert_dialog), + content="Open CupertinoAlertDialog", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation/pyproject.toml b/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation/pyproject.toml new file mode 100644 index 0000000000..ccc954f4b0 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_alert_dialog/file_deletion_confirmation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-alert-dialog-file-deletion-confirmation" +version = "1.0.0" +description = "Shows a CupertinoAlertDialog for file deletion confirmation with dismiss and action callbacks." +requires-python = ">=3.10" +keywords = ["cupertino", "alert dialog", "confirmation", "actions"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/CupertinoAlertDialog"] + +[tool.flet.metadata] +title = "File deletion confirmation" +controls = ["SafeArea", "Column", "CupertinoFilledButton", "CupertinoAlertDialog", "CupertinoDialogAction", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["open dialog", "dismiss callback", "action callbacks", "destructive action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_app_bar/basic.py b/sdk/python/examples/controls/cupertino_app_bar/basic/main.py similarity index 77% rename from sdk/python/examples/controls/cupertino_app_bar/basic.py rename to sdk/python/examples/controls/cupertino_app_bar/basic/main.py index e6f56be91a..e8b2b54a4e 100644 --- a/sdk/python/examples/controls/cupertino_app_bar/basic.py +++ b/sdk/python/examples/controls/cupertino_app_bar/basic/main.py @@ -13,7 +13,12 @@ def main(page: ft.Page): brightness=ft.Brightness.LIGHT, ) - page.add(ft.Text("Body!")) + page.add( + ft.SafeArea( + content=ft.Text("Body!"), + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_app_bar/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_app_bar/basic/pyproject.toml new file mode 100644 index 0000000000..6daad9f02d --- /dev/null +++ b/sdk/python/examples/controls/cupertino_app_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-app-bar-basic" +version = "1.0.0" +description = "Displays a CupertinoAppBar with custom leading and trailing icons and light theme styling." +requires-python = ">=3.10" +keywords = ["cupertino", "app bar", "navigation", "toolbar"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/CupertinoAppBar"] + +[tool.flet.metadata] +title = "Basic" +controls = ["CupertinoAppBar", "Icon", "Text", "SafeArea"] +layout_pattern = "toolbar-actions" +complexity = "basic" +features = ["custom app bar colors", "leading and trailing icons"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle.py b/sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle/main.py similarity index 84% rename from sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle.py rename to sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle/main.py index 5376c73dbf..bfd61b3be1 100644 --- a/sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle.py +++ b/sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle/main.py @@ -4,7 +4,7 @@ def main(page: ft.Page): page.theme_mode = ft.ThemeMode.LIGHT - def handle_theme_mode_toggle(e: ft.Event[ft.IconButton]): + def handle_theme_mode_toggle(_: ft.Event[ft.IconButton]): page.theme_mode = ( ft.ThemeMode.DARK if page.theme_mode == ft.ThemeMode.LIGHT @@ -15,7 +15,6 @@ def handle_theme_mode_toggle(e: ft.Event[ft.IconButton]): if page.theme_mode == ft.ThemeMode.LIGHT else ft.Icons.WB_SUNNY ) - page.update() theme_mode_button = ft.IconButton( icon=( @@ -35,7 +34,12 @@ def handle_theme_mode_toggle(e: ft.Event[ft.IconButton]): title=ft.Text("CupertinoAppBar Example", color=ft.Colors.ON_INVERSE_SURFACE), ) - page.add(ft.Text("Body!")) + page.add( + ft.SafeArea( + content=ft.Text("Body!"), + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle/pyproject.toml b/sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle/pyproject.toml new file mode 100644 index 0000000000..6ee28dccbd --- /dev/null +++ b/sdk/python/examples/controls/cupertino_app_bar/theme_mode_toggle/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-app-bar-theme-mode-toggle" +version = "1.0.0" +description = "Toggles page theme mode from a CupertinoAppBar trailing icon button." +requires-python = ">=3.10" +keywords = ["cupertino", "app bar", "theme", "toggle", "icon button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/CupertinoAppBar"] + +[tool.flet.metadata] +title = "Theme mode toggle" +controls = ["CupertinoAppBar", "Icon", "IconButton", "Text", "SafeArea"] +layout_pattern = "toolbar-actions" +complexity = "basic" +features = ["theme mode toggle", "dynamic icon update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_button/basic.py b/sdk/python/examples/controls/cupertino_button/basic.py deleted file mode 100644 index 106ce1747e..0000000000 --- a/sdk/python/examples/controls/cupertino_button/basic.py +++ /dev/null @@ -1,44 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.CupertinoButton( - bgcolor=ft.CupertinoColors.LIGHT_BACKGROUND_GRAY, - opacity_on_click=0.3, - on_click=lambda e: print("Normal CupertinoButton clicked!"), - content=ft.Text( - value="Normal CupertinoButton", - color=ft.CupertinoColors.DESTRUCTIVE_RED, - ), - ), - ft.CupertinoButton( - bgcolor=ft.Colors.PRIMARY, - alignment=ft.Alignment.TOP_LEFT, - border_radius=ft.BorderRadius.all(15), - opacity_on_click=0.5, - on_click=lambda e: print("Filled CupertinoButton clicked!"), - content=ft.Text("Filled CupertinoButton", color=ft.Colors.YELLOW), - ), - ft.CupertinoButton( - bgcolor=ft.Colors.PRIMARY, - disabled=True, - alignment=ft.Alignment.TOP_LEFT, - opacity_on_click=0.5, - content=ft.Text("Disabled CupertinoButton"), - ), - ft.Button( - adaptive=True, - bgcolor=ft.CupertinoColors.SYSTEM_TEAL, - content=ft.Row( - tight=True, - controls=[ - ft.Icon(ft.Icons.FAVORITE, color="pink"), - ft.Text("Button+adaptive"), - ], - ), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_button/basic/main.py b/sdk/python/examples/controls/cupertino_button/basic/main.py new file mode 100644 index 0000000000..dfffecc41e --- /dev/null +++ b/sdk/python/examples/controls/cupertino_button/basic/main.py @@ -0,0 +1,54 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoButton( + bgcolor=ft.CupertinoColors.LIGHT_BACKGROUND_GRAY, + opacity_on_click=0.3, + on_click=lambda _: print("Normal CupertinoButton clicked!"), + content=ft.Text( + value="Normal CupertinoButton", + color=ft.CupertinoColors.DESTRUCTIVE_RED, + ), + ), + ft.CupertinoButton( + bgcolor=ft.Colors.PRIMARY, + alignment=ft.Alignment.TOP_LEFT, + border_radius=ft.BorderRadius.all(15), + opacity_on_click=0.5, + on_click=lambda _: print("Filled CupertinoButton clicked!"), + content=ft.Text( + "Filled CupertinoButton", + color=ft.Colors.YELLOW, + ), + ), + ft.CupertinoButton( + bgcolor=ft.Colors.PRIMARY, + disabled=True, + alignment=ft.Alignment.TOP_LEFT, + opacity_on_click=0.5, + content=ft.Text("Disabled CupertinoButton"), + ), + ft.Button( + adaptive=True, + bgcolor=ft.CupertinoColors.SYSTEM_TEAL, + content=ft.Row( + tight=True, + controls=[ + ft.Icon(ft.Icons.FAVORITE, color="pink"), + ft.Text("Button+adaptive"), + ], + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_button/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_button/basic/pyproject.toml new file mode 100644 index 0000000000..597cbb92ae --- /dev/null +++ b/sdk/python/examples/controls/cupertino_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-button-basic" +version = "1.0.0" +description = "Demonstrates styled, disabled, and adaptive CupertinoButton variations in one layout." +requires-python = ">=3.10" +keywords = ["cupertino", "button", "adaptive", "disabled", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "CupertinoButton", "Button", "Text", "Row", "Icon"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom button styling", "disabled button", "adaptive button"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive.py b/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive.py deleted file mode 100644 index d010a057f2..0000000000 --- a/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive.py +++ /dev/null @@ -1,16 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.CupertinoCheckbox(label="Cupertino Checkbox", value=True), - ft.Checkbox(label="Material Checkbox", value=True), - ft.Container(height=20), - ft.Text( - value="Adaptive Checkbox shows as CupertinoCheckbox on macOS and iOS and as Checkbox on other platforms:" - ), - ft.Checkbox(adaptive=True, label="Adaptive Checkbox", value=True), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..79d36b7ea0 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoCheckbox(label="Cupertino Checkbox", value=True), + ft.Checkbox(label="Material Checkbox", value=True), + ft.Container(height=20), + ft.Text( + value=( + "Adaptive Checkbox shows as CupertinoCheckbox on macOS " + "and iOS and as Checkbox on other platforms:" + ) + ), + ft.Checkbox( + adaptive=True, + label="Adaptive Checkbox", + value=True, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..9715f7580f --- /dev/null +++ b/sdk/python/examples/controls/cupertino_checkbox/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-checkbox-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Shows Cupertino, Material, and adaptive checkbox behavior side by side." +requires-python = ">=3.10" +keywords = ["cupertino", "checkbox", "adaptive", "material", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoCheckbox"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "CupertinoCheckbox", "Checkbox", "Text", "Container"] +layout_pattern = "form" +complexity = "basic" +features = ["platform-adaptive checkbox", "cupertino and material comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_checkbox/styled.py b/sdk/python/examples/controls/cupertino_checkbox/styled.py deleted file mode 100644 index c2bbe8a2e5..0000000000 --- a/sdk/python/examples/controls/cupertino_checkbox/styled.py +++ /dev/null @@ -1,49 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - - page.add( - ft.Column( - controls=[ - ft.CupertinoCheckbox( - label="Cupertino Checkbox tristate", - value=True, - tristate=True, - check_color=ft.Colors.GREY_900, - fill_color={ - ft.ControlState.HOVERED: ft.Colors.PINK_200, - ft.ControlState.PRESSED: ft.Colors.LIME_ACCENT_200, - ft.ControlState.SELECTED: ft.Colors.DEEP_ORANGE_200, - ft.ControlState.DEFAULT: ft.Colors.TEAL_200, - }, - ), - ft.CupertinoCheckbox( - label="Cupertino Checkbox circle border", - value=True, - shape=ft.CircleBorder(), - # scale=ft.Scale(2, alignment=ft.Alignment(-1, 0)), - ), - ft.CupertinoCheckbox( - label="Cupertino Checkbox border states", - value=True, - # v1 bug - border_side renders grey box - # border_side={ - # ft.ControlState.HOVERED: ft.BorderSide(width=5), - # ft.ControlState.DEFAULT: ft.BorderSide(width=3), - # ft.ControlState.FOCUSED: ft.BorderSide(), - # }, - # scale=ft.Scale(2, alignment=ft.Alignment(-0.9, 0)), - ), - ft.CupertinoCheckbox( - label="Cupertino Checkbox label position", - value=True, - label_position=ft.LabelPosition.LEFT, - ), - ] - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_checkbox/styled/main.py b/sdk/python/examples/controls/cupertino_checkbox/styled/main.py new file mode 100644 index 0000000000..bdf4215312 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_checkbox/styled/main.py @@ -0,0 +1,44 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoCheckbox( + label="Cupertino Checkbox tristate", + value=True, + tristate=True, + check_color=ft.Colors.GREY_900, + fill_color={ + ft.ControlState.HOVERED: ft.Colors.PINK_200, + ft.ControlState.PRESSED: ft.Colors.LIME_ACCENT_200, + ft.ControlState.SELECTED: ft.Colors.DEEP_ORANGE_200, + ft.ControlState.DEFAULT: ft.Colors.TEAL_200, + }, + ), + ft.CupertinoCheckbox( + label="Cupertino Checkbox circle border", + value=True, + shape=ft.CircleBorder(), + ), + ft.CupertinoCheckbox( + label="Cupertino Checkbox border states", + value=True, + ), + ft.CupertinoCheckbox( + label="Cupertino Checkbox label position", + value=True, + label_position=ft.LabelPosition.LEFT, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_checkbox/styled/pyproject.toml b/sdk/python/examples/controls/cupertino_checkbox/styled/pyproject.toml new file mode 100644 index 0000000000..f65ba4f923 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_checkbox/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-checkbox-styled" +version = "1.0.0" +description = "Configures CupertinoCheckbox styles including fill states, shape, tristate, and label position." +requires-python = ">=3.10" +keywords = ["cupertino", "checkbox", "styling", "tristate", "shape"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoCheckbox"] + +[tool.flet.metadata] +title = "Styled" +controls = ["SafeArea", "Column", "CupertinoCheckbox", "CircleBorder"] +layout_pattern = "form" +complexity = "basic" +features = ["tristate checkbox", "state-based fill colors", "custom shape", "left-side label"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_context_menu/basic.py b/sdk/python/examples/controls/cupertino_context_menu/basic.py deleted file mode 100644 index aa3a6db369..0000000000 --- a/sdk/python/examples/controls/cupertino_context_menu/basic.py +++ /dev/null @@ -1,35 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - page.add( - ft.CupertinoContextMenu( - enable_haptic_feedback=True, - content=ft.Image("https://picsum.photos/200/200"), - actions=[ - ft.CupertinoContextMenuAction( - content="Action 1", - default=True, - trailing_icon=ft.Icons.CHECK, - on_click=lambda e: print("Action 1"), - ), - ft.CupertinoContextMenuAction( - content="Action 2", - trailing_icon=ft.Icons.MORE, - on_click=lambda e: print("Action 2"), - ), - ft.CupertinoContextMenuAction( - content="Action 3", - destructive=True, - trailing_icon=ft.Icons.CANCEL, - on_click=lambda e: print("Action 3"), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_context_menu/basic/main.py b/sdk/python/examples/controls/cupertino_context_menu/basic/main.py new file mode 100644 index 0000000000..ef9b62851e --- /dev/null +++ b/sdk/python/examples/controls/cupertino_context_menu/basic/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.CupertinoContextMenu( + enable_haptic_feedback=True, + actions=[ + ft.CupertinoContextMenuAction( + default=True, + trailing_icon=ft.Icons.CHECK, + on_click=lambda _: print("Action 1"), + content="Action 1", + ), + ft.CupertinoContextMenuAction( + trailing_icon=ft.Icons.MORE, + on_click=lambda _: print("Action 2"), + content="Action 2", + ), + ft.CupertinoContextMenuAction( + destructive=True, + trailing_icon=ft.Icons.CANCEL, + on_click=lambda _: print("Action 3"), + content="Action 3", + ), + ], + content=ft.Image("https://picsum.photos/200/200"), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_context_menu/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_context_menu/basic/pyproject.toml new file mode 100644 index 0000000000..95a6ae7858 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_context_menu/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-context-menu-basic" +version = "1.0.0" +description = "Opens a CupertinoContextMenu on image long-press with default and destructive actions." +requires-python = ">=3.10" +keywords = ["cupertino", "context menu", "image", "actions", "long press"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoContextMenu"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoContextMenu", "CupertinoContextMenuAction", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["context menu actions", "destructive action", "haptic feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_date_picker/basic.py b/sdk/python/examples/controls/cupertino_date_picker/basic.py deleted file mode 100644 index 0a8105abb5..0000000000 --- a/sdk/python/examples/controls/cupertino_date_picker/basic.py +++ /dev/null @@ -1,34 +0,0 @@ -from datetime import datetime - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_date_change(e: ft.Event[ft.CupertinoDatePicker]): - message.value = f"Chosen Date: {e.control.value.strftime('%Y-%m-%d %H:%M %p')}" - page.update() - - cupertino_date_picker = ft.CupertinoDatePicker( - value=datetime.now(), - date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, - on_change=handle_date_change, - ) - - page.add( - ft.CupertinoFilledButton( - content="Open CupertinoDatePicker", - on_click=lambda e: page.show_dialog( - ft.CupertinoBottomSheet( - content=cupertino_date_picker, - height=216, - padding=ft.Padding.only(top=6), - ) - ), - ), - message := ft.Text("Chosen Time: "), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_date_picker/basic/main.py b/sdk/python/examples/controls/cupertino_date_picker/basic/main.py new file mode 100644 index 0000000000..d6dad041da --- /dev/null +++ b/sdk/python/examples/controls/cupertino_date_picker/basic/main.py @@ -0,0 +1,43 @@ +from datetime import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + message = ft.Text("Chosen Time:") + + def handle_date_change(e: ft.Event[ft.CupertinoDatePicker]): + message.value = f"Chosen Date: {e.control.value.strftime('%Y-%m-%d %H:%M %p')}" + + cupertino_date_picker = ft.CupertinoDatePicker( + value=datetime.now(), + date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, + on_change=handle_date_change, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog( + ft.CupertinoBottomSheet( + height=216, + padding=ft.Padding.only(top=6), + content=cupertino_date_picker, + ) + ), + content="Open CupertinoDatePicker", + ), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_date_picker/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_date_picker/basic/pyproject.toml new file mode 100644 index 0000000000..f262648823 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_date_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-date-picker-basic" +version = "1.0.0" +description = "Shows a CupertinoDatePicker in a bottom sheet and updates text when the value changes." +requires-python = ">=3.10" +keywords = ["cupertino", "date picker", "bottom sheet", "events", "datetime"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoDatePicker"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "CupertinoFilledButton", "CupertinoBottomSheet", "CupertinoDatePicker", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["date and time selection", "on_change callback", "bottom sheet presentation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_date_picker/custom_locale.py b/sdk/python/examples/controls/cupertino_date_picker/custom_locale.py deleted file mode 100644 index e8ebea22d5..0000000000 --- a/sdk/python/examples/controls/cupertino_date_picker/custom_locale.py +++ /dev/null @@ -1,24 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - page.add( - ft.CupertinoFilledButton( - content="Open CupertinoDatePicker (zh_Hans locale)", - on_click=lambda e: page.show_dialog( - ft.CupertinoBottomSheet( - height=216, - padding=ft.Padding.only(top=6), - content=ft.CupertinoDatePicker( - locale=ft.Locale("zh", "Hans"), - date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, - ), - ) - ), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_date_picker/custom_locale/main.py b/sdk/python/examples/controls/cupertino_date_picker/custom_locale/main.py new file mode 100644 index 0000000000..8defa93279 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_date_picker/custom_locale/main.py @@ -0,0 +1,27 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog( + ft.CupertinoBottomSheet( + height=216, + padding=ft.Padding.only(top=6), + content=ft.CupertinoDatePicker( + locale=ft.Locale("zh", "Hans"), + date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, + ), + ) + ), + content="Open CupertinoDatePicker (zh_Hans locale)", + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_date_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/cupertino_date_picker/custom_locale/pyproject.toml new file mode 100644 index 0000000000..1c922279f2 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_date_picker/custom_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-date-picker-custom-locale" +version = "1.0.0" +description = "Opens CupertinoDatePicker with zh_Hans locale to demonstrate localized date formatting." +requires-python = ">=3.10" +keywords = ["cupertino", "date picker", "locale", "internationalization", "zh_Hans"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoDatePicker"] + +[tool.flet.metadata] +title = "Custom locale" +controls = ["SafeArea", "CupertinoFilledButton", "CupertinoBottomSheet", "CupertinoDatePicker", "Locale"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom locale", "date and time picker", "bottom sheet presentation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_filled_button/basic.py b/sdk/python/examples/controls/cupertino_filled_button/basic.py deleted file mode 100644 index 37191fbd27..0000000000 --- a/sdk/python/examples/controls/cupertino_filled_button/basic.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.CupertinoFilledButton( - content=ft.Text("CupertinoFilledButton"), - opacity_on_click=0.3, - on_click=lambda e: print("CupertinoFilledButton clicked!"), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_filled_button/basic/main.py b/sdk/python/examples/controls/cupertino_filled_button/basic/main.py new file mode 100644 index 0000000000..8f1d5d727d --- /dev/null +++ b/sdk/python/examples/controls/cupertino_filled_button/basic/main.py @@ -0,0 +1,17 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.CupertinoFilledButton( + opacity_on_click=0.3, + on_click=lambda _: print("CupertinoFilledButton clicked!"), + content=ft.Text("CupertinoFilledButton"), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_filled_button/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_filled_button/basic/pyproject.toml new file mode 100644 index 0000000000..66d70134c2 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_filled_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-filled-button-basic" +version = "1.0.0" +description = "Renders a CupertinoFilledButton with click opacity and click callback behavior." +requires-python = ">=3.10" +keywords = ["cupertino", "filled button", "button", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoFilledButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoFilledButton", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom click opacity", "button click callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/cupertinoactionsheet/index.md b/sdk/python/packages/flet/docs/controls/cupertinoactionsheet/index.md index 8381af463e..c44b13041a 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinoactionsheet/index.md +++ b/sdk/python/packages/flet/docs/controls/cupertinoactionsheet/index.md @@ -16,7 +16,7 @@ example_media: ../../examples/controls/cupertino_action_sheet/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinoactivityindicator.md b/sdk/python/packages/flet/docs/controls/cupertinoactivityindicator.md index fe223956bd..957a76d0ed 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinoactivityindicator.md +++ b/sdk/python/packages/flet/docs/controls/cupertinoactivityindicator.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_activity_indicator/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinoalertdialog.md b/sdk/python/packages/flet/docs/controls/cupertinoalertdialog.md index e0787a7e7e..a22c54cb61 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinoalertdialog.md +++ b/sdk/python/packages/flet/docs/controls/cupertinoalertdialog.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/cupertino_alert_dialog/media ### File deletion confirmation ```python ---8<-- "{{ examples }}/file_deletion_confirmation.py" +--8<-- "{{ examples }}/file_deletion_confirmation/main.py" ``` {{ image(example_images + "/file_deletion_confirmation.png", alt="file-deletion-confirmation", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../examples/controls/cupertino_alert_dialog/media ### Cupertino, material and adaptive alert dialogs ```python ---8<-- "{{ examples }}/cupertino_material_and_adaptive.py" +--8<-- "{{ examples }}/cupertino_material_and_adaptive/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinoappbar.md b/sdk/python/packages/flet/docs/controls/cupertinoappbar.md index 55f6c671af..dd44704b70 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinoappbar.md +++ b/sdk/python/packages/flet/docs/controls/cupertinoappbar.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/cupertino_app_bar/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../examples/controls/cupertino_app_bar/media ### App bar with theme mode toggle ```python ---8<-- "{{ examples }}/theme_mode_toggle.py" +--8<-- "{{ examples }}/theme_mode_toggle/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinobutton.md b/sdk/python/packages/flet/docs/controls/cupertinobutton.md index 77e0626954..05bd182b97 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinobutton.md +++ b/sdk/python/packages/flet/docs/controls/cupertinobutton.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_button/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinocheckbox.md b/sdk/python/packages/flet/docs/controls/cupertinocheckbox.md index bfaa1cf744..26bf32ac8a 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinocheckbox.md +++ b/sdk/python/packages/flet/docs/controls/cupertinocheckbox.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_checkbox/media ### Cupertino, Material and Adaptive Checkboxes ```python ---8<-- "{{ examples }}/cupertino_material_and_adaptive.py" +--8<-- "{{ examples }}/cupertino_material_and_adaptive/main.py" ``` {{ image(example_media + "/cupertino_material_and_adaptive.png", alt="cupertino-material-and-adaptive", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/cupertino_checkbox/media ### Styled checkboxes ```python ---8<-- "{{ examples }}/styled.py" +--8<-- "{{ examples }}/styled/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinocontextmenu/index.md b/sdk/python/packages/flet/docs/controls/cupertinocontextmenu/index.md index 52f1ecf94a..8a94324bb5 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinocontextmenu/index.md +++ b/sdk/python/packages/flet/docs/controls/cupertinocontextmenu/index.md @@ -15,7 +15,7 @@ example_images: ../../examples/controls/cupertino_context_menu/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinodatepicker.md b/sdk/python/packages/flet/docs/controls/cupertinodatepicker.md index 55c770a045..1b523aa269 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinodatepicker.md +++ b/sdk/python/packages/flet/docs/controls/cupertinodatepicker.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/cupertino_date_picker/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinofilledbutton.md b/sdk/python/packages/flet/docs/controls/cupertinofilledbutton.md index dd359b4378..1efbe87b31 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinofilledbutton.md +++ b/sdk/python/packages/flet/docs/controls/cupertinofilledbutton.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_filled_button/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} From a2ce4edc08614a7ecd91fee2941f1527fd252752 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 15:49:37 -0700 Subject: [PATCH 43/96] Organize Cupertino examples and add pyproject Refactor Cupertino example scripts into per-example packages: move example code into main.py modules, add SafeArea wrappers and __main__ guards, and simplify state refs to direct controls. Remove legacy single-file examples and add pyproject.toml metadata for each example (gallery metadata, dependencies, and tooling). Also update related docs and an integration test to reflect the new layout and filenames. --- .../controls/cupertino_list_tile/notched.py | 30 -------- .../cupertino_list_tile/notched/main.py | 37 +++++++++ .../notched/pyproject.toml | 26 +++++++ .../{basic.py => basic/main.py} | 9 ++- .../basic/pyproject.toml | 26 +++++++ .../{wired.py => wired/main.py} | 16 ++-- .../wired/pyproject.toml | 26 +++++++ .../cupertino_picker/fruit_selection.py | 52 ------------- .../cupertino_picker/fruit_selection/main.py | 54 +++++++++++++ .../fruit_selection/pyproject.toml | 26 +++++++ .../controls/cupertino_radio/basic.py | 38 ---------- .../controls/cupertino_radio/basic/main.py | 48 ++++++++++++ .../cupertino_radio/basic/pyproject.toml | 26 +++++++ .../cupertino_material_and_adaptive.py | 39 ---------- .../cupertino_material_and_adaptive/main.py | 49 ++++++++++++ .../pyproject.toml | 26 +++++++ .../cupertino_segmented_button/basic.py | 28 ------- .../cupertino_segmented_button/basic/main.py | 31 ++++++++ .../basic/pyproject.toml | 26 +++++++ .../segments_padding.py | 63 ---------------- .../segments_padding/main.py | 75 +++++++++++++++++++ .../segments_padding/pyproject.toml | 26 +++++++ .../cupertino_slider/handling_events.py | 37 --------- .../cupertino_slider/handling_events/main.py | 45 +++++++++++ .../handling_events/pyproject.toml | 26 +++++++ .../basic.py | 27 ------- .../basic/main.py | 30 ++++++++ .../basic/pyproject.toml | 26 +++++++ .../cupertino_material_and_adaptive.py | 29 ------- .../cupertino_material_and_adaptive/main.py | 32 ++++++++ .../pyproject.toml | 26 +++++++ .../cupertino_text_field/background_image.py | 18 ----- .../background_image/main.py | 20 +++++ .../background_image/pyproject.toml | 26 +++++++ .../cupertino_material_and_adaptive.py | 22 ------ .../cupertino_material_and_adaptive/main.py | 29 +++++++ .../pyproject.toml | 26 +++++++ .../cupertino_text_field/selection_change.py | 52 ------------- .../selection_change/main.py | 55 ++++++++++++++ .../selection_change/pyproject.toml | 26 +++++++ .../cupertino_timer_picker/__init__.py | 0 .../{basic.py => basic/main.py} | 33 ++++---- .../basic/pyproject.toml | 26 +++++++ .../flet/docs/controls/cupertinolisttile.md | 2 +- .../docs/controls/cupertinonavigationbar.md | 4 +- .../flet/docs/controls/cupertinopicker.md | 2 +- .../flet/docs/controls/cupertinoradio.md | 2 +- .../docs/controls/cupertinosegmentedbutton.md | 4 +- .../flet/docs/controls/cupertinoslider.md | 2 +- .../cupertinoslidingsegmentedbutton.md | 2 +- .../flet/docs/controls/cupertinoswitch.md | 2 +- .../flet/docs/controls/cupertinotextfield.md | 6 +- .../docs/controls/cupertinotimerpicker.md | 2 +- .../cupertino/test_cupertino_timer_picker.py | 3 +- 54 files changed, 944 insertions(+), 475 deletions(-) delete mode 100644 sdk/python/examples/controls/cupertino_list_tile/notched.py create mode 100644 sdk/python/examples/controls/cupertino_list_tile/notched/main.py create mode 100644 sdk/python/examples/controls/cupertino_list_tile/notched/pyproject.toml rename sdk/python/examples/controls/cupertino_navigation_bar/{basic.py => basic/main.py} (87%) create mode 100644 sdk/python/examples/controls/cupertino_navigation_bar/basic/pyproject.toml rename sdk/python/examples/controls/cupertino_navigation_bar/{wired.py => wired/main.py} (79%) create mode 100644 sdk/python/examples/controls/cupertino_navigation_bar/wired/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_picker/fruit_selection.py create mode 100644 sdk/python/examples/controls/cupertino_picker/fruit_selection/main.py create mode 100644 sdk/python/examples/controls/cupertino_picker/fruit_selection/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_radio/basic.py create mode 100644 sdk/python/examples/controls/cupertino_radio/basic/main.py create mode 100644 sdk/python/examples/controls/cupertino_radio/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive.py create mode 100644 sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive/main.py create mode 100644 sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_segmented_button/basic.py create mode 100644 sdk/python/examples/controls/cupertino_segmented_button/basic/main.py create mode 100644 sdk/python/examples/controls/cupertino_segmented_button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_segmented_button/segments_padding.py create mode 100644 sdk/python/examples/controls/cupertino_segmented_button/segments_padding/main.py create mode 100644 sdk/python/examples/controls/cupertino_segmented_button/segments_padding/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_slider/handling_events.py create mode 100644 sdk/python/examples/controls/cupertino_slider/handling_events/main.py create mode 100644 sdk/python/examples/controls/cupertino_slider/handling_events/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_sliding_segmented_button/basic.py create mode 100644 sdk/python/examples/controls/cupertino_sliding_segmented_button/basic/main.py create mode 100644 sdk/python/examples/controls/cupertino_sliding_segmented_button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive.py create mode 100644 sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive/main.py create mode 100644 sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_text_field/background_image.py create mode 100644 sdk/python/examples/controls/cupertino_text_field/background_image/main.py create mode 100644 sdk/python/examples/controls/cupertino_text_field/background_image/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive.py create mode 100644 sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive/main.py create mode 100644 sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_text_field/selection_change.py create mode 100644 sdk/python/examples/controls/cupertino_text_field/selection_change/main.py create mode 100644 sdk/python/examples/controls/cupertino_text_field/selection_change/pyproject.toml delete mode 100644 sdk/python/examples/controls/cupertino_timer_picker/__init__.py rename sdk/python/examples/controls/cupertino_timer_picker/{basic.py => basic/main.py} (53%) create mode 100644 sdk/python/examples/controls/cupertino_timer_picker/basic/pyproject.toml diff --git a/sdk/python/examples/controls/cupertino_list_tile/notched.py b/sdk/python/examples/controls/cupertino_list_tile/notched.py deleted file mode 100644 index 44c9d85b6b..0000000000 --- a/sdk/python/examples/controls/cupertino_list_tile/notched.py +++ /dev/null @@ -1,30 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_tile_click(e: ft.Event[ft.CupertinoListTile]): - print("Tile clicked") - - page.add( - ft.CupertinoListTile( - additional_info=ft.Text("Wed Jan 24"), - bgcolor_activated=ft.Colors.AMBER_ACCENT, - leading=ft.Icon(ft.CupertinoIcons.GAME_CONTROLLER), - title=ft.Text("CupertinoListTile: notched = False"), - subtitle=ft.Text("Subtitle"), - trailing=ft.Icon(ft.CupertinoIcons.ALARM), - on_click=handle_tile_click, - ), - ft.CupertinoListTile( - notched=True, - additional_info=ft.Text("Thu Jan 25"), - leading=ft.Icon(ft.CupertinoIcons.GAME_CONTROLLER), - title=ft.Text("CupertinoListTile: notched = True"), - subtitle=ft.Text("Subtitle"), - trailing=ft.Icon(ft.CupertinoIcons.ALARM), - on_click=handle_tile_click, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_list_tile/notched/main.py b/sdk/python/examples/controls/cupertino_list_tile/notched/main.py new file mode 100644 index 0000000000..a60ccaefca --- /dev/null +++ b/sdk/python/examples/controls/cupertino_list_tile/notched/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_tile_click(_: ft.Event[ft.CupertinoListTile]): + print("Tile clicked") + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoListTile( + additional_info=ft.Text("Wed Jan 24"), + bgcolor_activated=ft.Colors.AMBER_ACCENT, + leading=ft.Icon(ft.CupertinoIcons.GAME_CONTROLLER), + title=ft.Text("CupertinoListTile: notched = False"), + subtitle=ft.Text("Subtitle"), + trailing=ft.Icon(ft.CupertinoIcons.ALARM), + on_click=handle_tile_click, + ), + ft.CupertinoListTile( + notched=True, + additional_info=ft.Text("Thu Jan 25"), + leading=ft.Icon(ft.CupertinoIcons.GAME_CONTROLLER), + title=ft.Text("CupertinoListTile: notched = True"), + subtitle=ft.Text("Subtitle"), + trailing=ft.Icon(ft.CupertinoIcons.ALARM), + on_click=handle_tile_click, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_list_tile/notched/pyproject.toml b/sdk/python/examples/controls/cupertino_list_tile/notched/pyproject.toml new file mode 100644 index 0000000000..3e07330748 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_list_tile/notched/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-list-tile-notched" +version = "1.0.0" +description = "Compares CupertinoListTile with and without notched layout, including leading, trailing, and click actions." +requires-python = ">=3.10" +keywords = ["cupertino", "list tile", "notched", "layout", "click"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/CupertinoListTile"] + +[tool.flet.metadata] +title = "Notched" +controls = ["SafeArea", "Column", "CupertinoListTile", "Text", "Icon"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["notched tile", "tile click callback", "additional info"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_navigation_bar/basic.py b/sdk/python/examples/controls/cupertino_navigation_bar/basic/main.py similarity index 87% rename from sdk/python/examples/controls/cupertino_navigation_bar/basic.py rename to sdk/python/examples/controls/cupertino_navigation_bar/basic/main.py index 247b797634..8c622ac09d 100644 --- a/sdk/python/examples/controls/cupertino_navigation_bar/basic.py +++ b/sdk/python/examples/controls/cupertino_navigation_bar/basic/main.py @@ -28,7 +28,12 @@ def main(page: ft.Page): ], ) - page.add(ft.SafeArea(content=ft.Text("Body!"))) + page.add( + ft.SafeArea( + content=ft.Text("Body!"), + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_navigation_bar/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_navigation_bar/basic/pyproject.toml new file mode 100644 index 0000000000..9883ea5523 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_navigation_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-navigation-bar-basic" +version = "1.0.0" +description = "Shows a CupertinoNavigationBar with three destinations and selected tab callback logging." +requires-python = ">=3.10" +keywords = ["cupertino", "navigation bar", "tabs", "destinations"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/CupertinoNavigationBar"] + +[tool.flet.metadata] +title = "Basic" +controls = ["CupertinoNavigationBar", "NavigationBarDestination", "SafeArea", "Text"] +layout_pattern = "tabbed-navigation" +complexity = "basic" +features = ["bottom navigation", "destination selection callback", "active and inactive colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_navigation_bar/wired.py b/sdk/python/examples/controls/cupertino_navigation_bar/wired/main.py similarity index 79% rename from sdk/python/examples/controls/cupertino_navigation_bar/wired.py rename to sdk/python/examples/controls/cupertino_navigation_bar/wired/main.py index 771e8b7441..bd46019cc1 100644 --- a/sdk/python/examples/controls/cupertino_navigation_bar/wired.py +++ b/sdk/python/examples/controls/cupertino_navigation_bar/wired/main.py @@ -4,14 +4,15 @@ def main(page: ft.Page): page.title = "CupertinoNavigationBar Example" + body_text = ft.Text("Explore!") + def handle_nav_destination_change(e: ft.Event[ft.CupertinoNavigationBar]): if e.control.selected_index == 0: - body.content.value = "Explore!" + body_text.value = "Explore!" elif e.control.selected_index == 1: - body.content.value = "Find Your Way!" + body_text.value = "Find Your Way!" else: - body.content.value = "Your Favorites!" - page.update() + body_text.value = "Your Favorites!" page.navigation_bar = ft.CupertinoNavigationBar( bgcolor=ft.Colors.AMBER_100, @@ -38,8 +39,11 @@ def handle_nav_destination_change(e: ft.Event[ft.CupertinoNavigationBar]): ) page.add( - body := ft.SafeArea(content=ft.Text("Explore!")), + ft.SafeArea( + content=body_text, + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_navigation_bar/wired/pyproject.toml b/sdk/python/examples/controls/cupertino_navigation_bar/wired/pyproject.toml new file mode 100644 index 0000000000..ed3db35d10 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_navigation_bar/wired/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-navigation-bar-wired" +version = "1.0.0" +description = "Wires CupertinoNavigationBar selection to update the page body text for each destination." +requires-python = ">=3.10" +keywords = ["cupertino", "navigation bar", "state", "destinations", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/CupertinoNavigationBar"] + +[tool.flet.metadata] +title = "Wired" +controls = ["CupertinoNavigationBar", "NavigationBarDestination", "SafeArea", "Text"] +layout_pattern = "tabbed-navigation" +complexity = "basic" +features = ["selection-driven content", "destination change handler"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_picker/fruit_selection.py b/sdk/python/examples/controls/cupertino_picker/fruit_selection.py deleted file mode 100644 index ad38f6a3d5..0000000000 --- a/sdk/python/examples/controls/cupertino_picker/fruit_selection.py +++ /dev/null @@ -1,52 +0,0 @@ -import flet as ft - -FRUITS = [ - "Apple", - "Mango", - "Banana", - "Orange", - "Pineapple", - "Strawberry", -] - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - selected_fruit_ref = ft.Ref[ft.Text]() - - def handle_selection_change(e: ft.Event[ft.CupertinoPicker]): - selected_fruit_ref.current.value = FRUITS[int(e.data)] - page.update() - - cupertino_picker = ft.CupertinoPicker( - selected_index=3, - magnification=1.22, - squeeze=1.2, - use_magnifier=True, - on_change=handle_selection_change, - controls=[ft.Text(value=f) for f in FRUITS], - ) - - page.add( - ft.Row( - tight=True, - controls=[ - ft.Text("Selected Fruit:", size=23), - ft.TextButton( - content=ft.Text(value=FRUITS[3], ref=selected_fruit_ref, size=23), - style=ft.ButtonStyle(color=ft.Colors.BLUE), - on_click=lambda e: page.show_dialog( - ft.CupertinoBottomSheet( - content=cupertino_picker, - height=216, - padding=ft.Padding.only(top=6), - ) - ), - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_picker/fruit_selection/main.py b/sdk/python/examples/controls/cupertino_picker/fruit_selection/main.py new file mode 100644 index 0000000000..ba028fea93 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_picker/fruit_selection/main.py @@ -0,0 +1,54 @@ +import flet as ft + +FRUITS = [ + "Apple", + "Mango", + "Banana", + "Orange", + "Pineapple", + "Strawberry", +] + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + selected_fruit_text = ft.Text(value=FRUITS[3], size=23) + + def handle_selection_change(e: ft.Event[ft.CupertinoPicker]): + selected_fruit_text.value = FRUITS[int(e.data)] + + cupertino_picker = ft.CupertinoPicker( + selected_index=3, + magnification=1.22, + squeeze=1.2, + use_magnifier=True, + on_change=handle_selection_change, + controls=[ft.Text(value=f) for f in FRUITS], + ) + + page.add( + ft.SafeArea( + content=ft.Row( + tight=True, + controls=[ + ft.Text("Selected Fruit:", size=23), + ft.TextButton( + style=ft.ButtonStyle(color=ft.Colors.BLUE), + on_click=lambda _: page.show_dialog( + ft.CupertinoBottomSheet( + height=216, + padding=ft.Padding.only(top=6), + content=cupertino_picker, + ) + ), + content=selected_fruit_text, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_picker/fruit_selection/pyproject.toml b/sdk/python/examples/controls/cupertino_picker/fruit_selection/pyproject.toml new file mode 100644 index 0000000000..63f20899d9 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_picker/fruit_selection/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-picker-fruit-selection" +version = "1.0.0" +description = "Opens a CupertinoPicker in a bottom sheet to choose a fruit and reflect the selected value." +requires-python = ">=3.10" +keywords = ["cupertino", "picker", "bottom sheet", "selection", "dialog"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoPicker"] + +[tool.flet.metadata] +title = "Fruit selection" +controls = ["SafeArea", "Row", "Text", "TextButton", "CupertinoBottomSheet", "CupertinoPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["picker selection callback", "bottom sheet presentation", "live value update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_radio/basic.py b/sdk/python/examples/controls/cupertino_radio/basic.py deleted file mode 100644 index c7d7a3f359..0000000000 --- a/sdk/python/examples/controls/cupertino_radio/basic.py +++ /dev/null @@ -1,38 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_button_click(e: ft.Event[ft.ElevatedButton]): - message.value = f"Your favorite color is: {group.value}" - page.update() - - page.add( - ft.Text("Select your favorite color:"), - group := ft.RadioGroup( - content=ft.Column( - controls=[ - ft.CupertinoRadio( - value="red", - label="Red", - active_color=ft.Colors.RED_200, - inactive_color=ft.Colors.RED_600, - ), - ft.CupertinoRadio( - value="green", - label="Green", - fill_color=ft.Colors.GREEN, - ), - ft.CupertinoRadio( - value="blue", - label="Blue", - active_color=ft.Colors.BLUE, - ), - ] - ) - ), - ft.Button(content="Submit", on_click=handle_button_click), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_radio/basic/main.py b/sdk/python/examples/controls/cupertino_radio/basic/main.py new file mode 100644 index 0000000000..9a5dae4b75 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_radio/basic/main.py @@ -0,0 +1,48 @@ +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + + group = ft.RadioGroup( + content=ft.Column( + controls=[ + ft.CupertinoRadio( + value="red", + label="Red", + active_color=ft.Colors.RED_200, + inactive_color=ft.Colors.RED_600, + ), + ft.CupertinoRadio( + value="green", + label="Green", + fill_color=ft.Colors.GREEN, + ), + ft.CupertinoRadio( + value="blue", + label="Blue", + active_color=ft.Colors.BLUE, + ), + ], + ) + ) + + def handle_button_click(_: ft.Event[ft.Button]): + message.value = f"Your favorite color is: {group.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Select your favorite color:"), + group, + ft.Button(content="Submit", on_click=handle_button_click), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_radio/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_radio/basic/pyproject.toml new file mode 100644 index 0000000000..cda13ceab4 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_radio/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-radio-basic" +version = "1.0.0" +description = "Collects color selection with CupertinoRadio controls in a RadioGroup and submit action." +requires-python = ">=3.10" +keywords = ["cupertino", "radio", "radio group", "selection", "form"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoRadio"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "RadioGroup", "CupertinoRadio", "Text", "Button"] +layout_pattern = "form" +complexity = "basic" +features = ["single-choice selection", "submit callback", "custom active colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive.py b/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive.py deleted file mode 100644 index d54a2e5c28..0000000000 --- a/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_button_click(e: ft.Event[ft.Button]): - message.value = f"Your favorite color is: {group.value}" - page.update() - - page.add( - ft.Text("Select your favorite color:"), - group := ft.RadioGroup( - content=ft.Column( - controls=[ - ft.CupertinoRadio( - value="red", - label="Red - Cupertino Radio", - active_color=ft.Colors.RED, - inactive_color=ft.Colors.RED, - ), - ft.Radio( - value="green", - label="Green - Material Radio", - fill_color=ft.Colors.GREEN, - ), - ft.Radio( - value="blue", - label="Blue - Adaptive Radio", - adaptive=True, - active_color=ft.Colors.BLUE, - ), - ] - ) - ), - ft.Button(content="Submit", on_click=handle_button_click), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..e7db545a6c --- /dev/null +++ b/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + + group = ft.RadioGroup( + content=ft.Column( + controls=[ + ft.CupertinoRadio( + value="red", + label="Red - Cupertino Radio", + active_color=ft.Colors.RED, + inactive_color=ft.Colors.RED, + ), + ft.Radio( + value="green", + label="Green - Material Radio", + fill_color=ft.Colors.GREEN, + ), + ft.Radio( + value="blue", + label="Blue - Adaptive Radio", + adaptive=True, + active_color=ft.Colors.BLUE, + ), + ], + ) + ) + + def handle_button_click(_: ft.Event[ft.Button]): + message.value = f"Your favorite color is: {group.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Select your favorite color:"), + group, + ft.Button(content="Submit", on_click=handle_button_click), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..5649e80abe --- /dev/null +++ b/sdk/python/examples/controls/cupertino_radio/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-radio-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Compares Cupertino, Material, and adaptive radio controls inside one RadioGroup workflow." +requires-python = ">=3.10" +keywords = ["cupertino", "radio", "adaptive", "material", "comparison"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoRadio"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "RadioGroup", "CupertinoRadio", "Radio", "Text", "Button"] +layout_pattern = "form" +complexity = "basic" +features = ["adaptive radio", "cupertino and material comparison", "submit callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_segmented_button/basic.py b/sdk/python/examples/controls/cupertino_segmented_button/basic.py deleted file mode 100644 index 0dcd7d3529..0000000000 --- a/sdk/python/examples/controls/cupertino_segmented_button/basic.py +++ /dev/null @@ -1,28 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - - page.add( - ft.CupertinoSegmentedButton( - selected_index=1, - selected_color=ft.Colors.RED_400, - on_change=lambda e: print(f"selected_index: {e.data}"), - padding=ft.Padding.symmetric(vertical=20, horizontal=50), - controls=[ - ft.Text("One"), - ft.Container( - padding=ft.Padding.symmetric(vertical=10, horizontal=30), - content=ft.Text("Two"), - ), - ft.Container( - padding=ft.Padding.symmetric(vertical=5, horizontal=10), - content=ft.Text("Three"), - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_segmented_button/basic/main.py b/sdk/python/examples/controls/cupertino_segmented_button/basic/main.py new file mode 100644 index 0000000000..2c53dbab8d --- /dev/null +++ b/sdk/python/examples/controls/cupertino_segmented_button/basic/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.CupertinoSegmentedButton( + selected_index=1, + selected_color=ft.Colors.RED_400, + on_change=lambda e: print(f"selected_index: {e.data}"), + padding=ft.Padding.symmetric(vertical=20, horizontal=50), + controls=[ + ft.Text("One"), + ft.Container( + padding=ft.Padding.symmetric(vertical=10, horizontal=30), + content=ft.Text("Two"), + ), + ft.Container( + padding=ft.Padding.symmetric(vertical=5, horizontal=10), + content=ft.Text("Three"), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_segmented_button/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_segmented_button/basic/pyproject.toml new file mode 100644 index 0000000000..5a95cc6b29 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_segmented_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-segmented-button-basic" +version = "1.0.0" +description = "Shows a CupertinoSegmentedButton with mixed segment content sizes and selection events." +requires-python = ">=3.10" +keywords = ["cupertino", "segmented button", "selection", "buttons"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoSegmentedButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoSegmentedButton", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["segment selection callback", "custom segment padding", "selected color"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_segmented_button/segments_padding.py b/sdk/python/examples/controls/cupertino_segmented_button/segments_padding.py deleted file mode 100644 index b7879b6e02..0000000000 --- a/sdk/python/examples/controls/cupertino_segmented_button/segments_padding.py +++ /dev/null @@ -1,63 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - - def handle_vertical_change(e: ft.Event[ft.Slider]): - segmented_button.controls[1].padding = ft.Padding.only( - top=e.control.value, bottom=e.control.value - ) - page.update() - - def handle_horizontal_change(e: ft.Event[ft.Slider]): - segmented_button.controls[2].padding = ft.Padding.only( - left=e.control.value, right=e.control.value - ) - page.update() - - page.add( - segmented_button := ft.CupertinoSegmentedButton( - selected_index=1, - selected_color=ft.Colors.RED_400, - unselected_color=ft.Colors.GREY_400, - on_change=lambda e: print(f"selected_index: {e.data}"), - controls=[ - ft.Text("All"), - ft.Container( - padding=ft.Padding.symmetric(vertical=30, horizontal=0), - content=ft.Text("None"), - ), - ft.Container( - padding=ft.Padding.symmetric(vertical=0, horizontal=30), - content=ft.Text("Some"), - ), - ], - ), - ft.Text("Vertical padding button 1: "), - ft.Slider( - label="{value}", - min=0, - max=50, - divisions=50, - value=30, - on_change=handle_vertical_change, - ), - ft.Text("Horizontal padding button 2:"), - ft.Slider( - label="{value}", - min=0, - max=50, - divisions=50, - value=30, - on_change=handle_horizontal_change, - ), - ft.Text( - value="*note that padding changes to one segment can effect padding on other segments*", - theme_style=ft.TextThemeStyle.LABEL_MEDIUM, - color=ft.Colors.ORANGE_ACCENT, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_segmented_button/segments_padding/main.py b/sdk/python/examples/controls/cupertino_segmented_button/segments_padding/main.py new file mode 100644 index 0000000000..89b8572a37 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_segmented_button/segments_padding/main.py @@ -0,0 +1,75 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + segmented_button = ft.CupertinoSegmentedButton( + selected_index=1, + selected_color=ft.Colors.RED_400, + unselected_color=ft.Colors.GREY_400, + on_change=lambda e: print(f"selected_index: {e.data}"), + controls=[ + ft.Text("All"), + ft.Container( + padding=ft.Padding.symmetric(vertical=30, horizontal=0), + content=ft.Text("None"), + ), + ft.Container( + padding=ft.Padding.symmetric(vertical=0, horizontal=30), + content=ft.Text("Some"), + ), + ], + ) + + def handle_vertical_change(e: ft.Event[ft.Slider]): + segmented_button.controls[1].padding = ft.Padding.only( + top=e.control.value, + bottom=e.control.value, + ) + + def handle_horizontal_change(e: ft.Event[ft.Slider]): + segmented_button.controls[2].padding = ft.Padding.only( + left=e.control.value, + right=e.control.value, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + segmented_button, + ft.Text("Vertical padding button 1:"), + ft.Slider( + label="{value}", + min=0, + max=50, + divisions=50, + value=30, + on_change=handle_vertical_change, + ), + ft.Text("Horizontal padding button 2:"), + ft.Slider( + label="{value}", + min=0, + max=50, + divisions=50, + value=30, + on_change=handle_horizontal_change, + ), + ft.Text( + value=( + "*note that padding changes to one segment can effect " + "padding on other segments*" + ), + theme_style=ft.TextThemeStyle.LABEL_MEDIUM, + color=ft.Colors.ORANGE_ACCENT, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_segmented_button/segments_padding/pyproject.toml b/sdk/python/examples/controls/cupertino_segmented_button/segments_padding/pyproject.toml new file mode 100644 index 0000000000..cc9405d557 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_segmented_button/segments_padding/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-segmented-button-segments-padding" +version = "1.0.0" +description = "Adjusts CupertinoSegmentedButton segment padding interactively using sliders." +requires-python = ">=3.10" +keywords = ["cupertino", "segmented button", "padding", "slider", "interactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoSegmentedButton"] + +[tool.flet.metadata] +title = "Segments padding" +controls = ["SafeArea", "Column", "CupertinoSegmentedButton", "Container", "Slider", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["interactive padding controls", "segment layout tuning", "selection callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_slider/handling_events.py b/sdk/python/examples/controls/cupertino_slider/handling_events.py deleted file mode 100644 index 01b4c31b20..0000000000 --- a/sdk/python/examples/controls/cupertino_slider/handling_events.py +++ /dev/null @@ -1,37 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.theme_mode = ft.ThemeMode.LIGHT - - def handle_change_start(e: ft.Event[ft.CupertinoSlider]): - slider_status.value = "Sliding" - page.update() - - def handle_change(e: ft.Event[ft.CupertinoSlider]): - slider_value.value = str(e.control.value) - page.update() - - def handle_change_end(e: ft.Event[ft.CupertinoSlider]): - slider_status.value = "Finished sliding" - page.update() - - page.add( - slider_value := ft.Text("0.0"), - ft.CupertinoSlider( - divisions=20, - min=0, - max=100, - active_color=ft.Colors.PURPLE, - thumb_color=ft.Colors.PURPLE, - on_change_start=handle_change_start, - on_change_end=handle_change_end, - on_change=handle_change, - ), - slider_status := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_slider/handling_events/main.py b/sdk/python/examples/controls/cupertino_slider/handling_events/main.py new file mode 100644 index 0000000000..bf0b5bbe24 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_slider/handling_events/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.theme_mode = ft.ThemeMode.LIGHT + + slider_value = ft.Text("0.0") + slider_status = ft.Text() + + def handle_change_start(_: ft.Event[ft.CupertinoSlider]): + slider_status.value = "Sliding" + + def handle_change(e: ft.Event[ft.CupertinoSlider]): + slider_value.value = str(e.control.value) + + def handle_change_end(_: ft.Event[ft.CupertinoSlider]): + slider_status.value = "Finished sliding" + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + slider_value, + ft.CupertinoSlider( + divisions=20, + min=0, + max=100, + active_color=ft.Colors.PURPLE, + thumb_color=ft.Colors.PURPLE, + on_change_start=handle_change_start, + on_change_end=handle_change_end, + on_change=handle_change, + ), + slider_status, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_slider/handling_events/pyproject.toml b/sdk/python/examples/controls/cupertino_slider/handling_events/pyproject.toml new file mode 100644 index 0000000000..5107f23c90 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_slider/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-slider-handling-events" +version = "1.0.0" +description = "Tracks CupertinoSlider start, change, and end events with live status text updates." +requires-python = ">=3.10" +keywords = ["cupertino", "slider", "events", "input", "status"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoSlider"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "Column", "CupertinoSlider", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["on_change_start", "on_change", "on_change_end", "live value display"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic.py b/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic.py deleted file mode 100644 index 94100bf757..0000000000 --- a/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic.py +++ /dev/null @@ -1,27 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "CupertinoSlidingSegmentedButton Example" - page.theme_mode = ft.ThemeMode.LIGHT - - def handle_selection_change(e: ft.Event[ft.CupertinoSlidingSegmentedButton]): - page.show_dialog( - ft.SnackBar(ft.Text(f"Segment {e.control.selected_index + 1} was chosen!")) - ) - - page.add( - ft.CupertinoSlidingSegmentedButton( - selected_index=1, - thumb_color=ft.Colors.BLUE_400, - on_change=handle_selection_change, - controls=[ - ft.Text("One"), - ft.Text("Two"), - ft.Text("Three"), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic/main.py b/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic/main.py new file mode 100644 index 0000000000..7202f24ef7 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "CupertinoSlidingSegmentedButton Example" + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_selection_change(e: ft.Event[ft.CupertinoSlidingSegmentedButton]): + page.show_dialog( + ft.SnackBar(ft.Text(f"Segment {e.control.selected_index + 1} was chosen!")) + ) + + page.add( + ft.SafeArea( + content=ft.CupertinoSlidingSegmentedButton( + selected_index=1, + thumb_color=ft.Colors.BLUE_400, + on_change=handle_selection_change, + controls=[ + ft.Text("One"), + ft.Text("Two"), + ft.Text("Three"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic/pyproject.toml new file mode 100644 index 0000000000..1602c82675 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_sliding_segmented_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-sliding-segmented-button-basic" +version = "1.0.0" +description = "Displays CupertinoSlidingSegmentedButton and shows feedback when segment selection changes." +requires-python = ">=3.10" +keywords = ["cupertino", "sliding segmented button", "selection", "snackbar"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoSlidingSegmentedButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoSlidingSegmentedButton", "Text", "SnackBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["segment change callback", "selection feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive.py b/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive.py deleted file mode 100644 index b6849d3a9f..0000000000 --- a/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive.py +++ /dev/null @@ -1,29 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.CupertinoSwitch( - label="Cupertino Switch", - value=True, - ), - ft.Switch( - label="Material Switch", - value=True, - thumb_color={ft.ControlState.SELECTED: ft.Colors.BLUE}, - track_color=ft.Colors.YELLOW, - focus_color=ft.Colors.PURPLE, - ), - ft.Container(height=20), - ft.Text( - value="Adaptive Switch shows as CupertinoSwitch on macOS and iOS and as Switch on other platforms:" - ), - ft.Switch( - adaptive=True, - label="Adaptive Switch", - value=True, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..b8e59fc494 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoSwitch(label="Cupertino Switch", value=True), + ft.Switch( + label="Material Switch", + value=True, + thumb_color={ft.ControlState.SELECTED: ft.Colors.BLUE}, + track_color=ft.Colors.YELLOW, + focus_color=ft.Colors.PURPLE, + ), + ft.Container(height=20), + ft.Text( + value=( + "Adaptive Switch shows as CupertinoSwitch on macOS and " + "iOS and as Switch on other platforms:" + ) + ), + ft.Switch(adaptive=True, label="Adaptive Switch", value=True), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..1b90621e72 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_switch/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-switch-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Shows Cupertino, Material, and adaptive switch controls with custom switch styling." +requires-python = ">=3.10" +keywords = ["cupertino", "switch", "adaptive", "material", "toggle"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoSwitch"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "CupertinoSwitch", "Switch", "Text", "Container"] +layout_pattern = "form" +complexity = "basic" +features = ["adaptive switch", "cupertino and material comparison", "custom thumb and track colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_text_field/background_image.py b/sdk/python/examples/controls/cupertino_text_field/background_image.py deleted file mode 100644 index 8123f706d2..0000000000 --- a/sdk/python/examples/controls/cupertino_text_field/background_image.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - page.add( - ctf := ft.CupertinoTextField( - label="Textfield Label", - label_style=ft.TextStyle(italic=True, weight=ft.FontWeight.BOLD), - bgcolor=ft.Colors.BLUE_GREY, - image=ft.DecorationImage( - src="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" - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_text_field/background_image/main.py b/sdk/python/examples/controls/cupertino_text_field/background_image/main.py new file mode 100644 index 0000000000..bd9c022ea0 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_text_field/background_image/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +async def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.CupertinoTextField( + label="Textfield Label", + label_style=ft.TextStyle(italic=True, weight=ft.FontWeight.BOLD), + bgcolor=ft.Colors.BLUE_GREY, + image=ft.DecorationImage(src="https://picsum.photos/1000/260"), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_text_field/background_image/pyproject.toml b/sdk/python/examples/controls/cupertino_text_field/background_image/pyproject.toml new file mode 100644 index 0000000000..fcaf3d9f18 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_text_field/background_image/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-text-field-background-image" +version = "1.0.0" +description = "Applies a background decoration image to CupertinoTextField with custom label styling." +requires-python = ">=3.10" +keywords = ["cupertino", "text field", "background image", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoTextField"] + +[tool.flet.metadata] +title = "Background image" +controls = ["SafeArea", "CupertinoTextField", "TextStyle", "DecorationImage"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["text field background image", "custom label style"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive.py b/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive.py deleted file mode 100644 index c579381b9c..0000000000 --- a/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive.py +++ /dev/null @@ -1,22 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.TextField( - label="Material text field", - label_style=ft.TextStyle(color=ft.Colors.GREY_400), - ), - ft.CupertinoTextField( - placeholder_text="Cupertino text field", - placeholder_style=ft.TextStyle(color=ft.Colors.GREY_400), - ), - ft.TextField( - adaptive=True, - label="Adaptive text field", - label_style=ft.TextStyle(color=ft.Colors.GREY_400), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..5243a7595d --- /dev/null +++ b/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive/main.py @@ -0,0 +1,29 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + label="Material text field", + label_style=ft.TextStyle(color=ft.Colors.GREY_400), + ), + ft.CupertinoTextField( + placeholder_text="Cupertino text field", + placeholder_style=ft.TextStyle(color=ft.Colors.GREY_400), + ), + ft.TextField( + adaptive=True, + label="Adaptive text field", + label_style=ft.TextStyle(color=ft.Colors.GREY_400), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..fb14e28587 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_text_field/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-text-field-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Compares Material, Cupertino, and adaptive text fields with placeholder and label styling." +requires-python = ">=3.10" +keywords = ["cupertino", "text field", "adaptive", "material", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoTextField"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "CupertinoTextField", "TextField", "TextStyle"] +layout_pattern = "form" +complexity = "basic" +features = ["adaptive text field", "cupertino and material comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_text_field/selection_change.py b/sdk/python/examples/controls/cupertino_text_field/selection_change.py deleted file mode 100644 index d44e9be939..0000000000 --- a/sdk/python/examples/controls/cupertino_text_field/selection_change.py +++ /dev/null @@ -1,52 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Text selection" - - def handle_selection_change(e: ft.TextSelectionChangeEvent[ft.CupertinoTextField]): - selection.value = ( - f"Selection: '{e.selected_text}'" if e.selected_text else "No selection." - ) - selection_details.value = f"start={e.selection.start}, end={e.selection.end}" - caret.value = f"Caret position: {e.selection.end}" - - async def select_characters(e: ft.Event[ft.Button]): - await field.focus() - field.selection = ft.TextSelection( - base_offset=0, extent_offset=len(field.value) - ) - - async def move_caret(e: ft.Event[ft.Button]): - await field.focus() - field.selection = ft.TextSelection(base_offset=0, extent_offset=0) - - page.add( - ft.Column( - spacing=10, - controls=[ - field := ft.CupertinoTextField( - value="Lorem ipsum dolor sit amet, consectetur adipiscing elit.", - multiline=True, - min_lines=3, - autofocus=True, - on_selection_change=handle_selection_change, - ), - selection := ft.Text("Select some text from the field."), - selection_details := ft.Text(), - caret := ft.Text("Caret position: -"), - ft.Button( - content="Select all text", - on_click=select_characters, - ), - ft.Button( - content="Move caret to start", - on_click=move_caret, - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_text_field/selection_change/main.py b/sdk/python/examples/controls/cupertino_text_field/selection_change/main.py new file mode 100644 index 0000000000..8f9318ba83 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_text_field/selection_change/main.py @@ -0,0 +1,55 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Text selection" + + selection = ft.Text("Select some text from the field.") + selection_details = ft.Text() + caret = ft.Text("Caret position: -") + + def handle_selection_change(e: ft.TextSelectionChangeEvent[ft.CupertinoTextField]): + selection.value = ( + f"Selection: '{e.selected_text}'" if e.selected_text else "No selection." + ) + selection_details.value = f"start={e.selection.start}, end={e.selection.end}" + caret.value = f"Caret position: {e.selection.end}" + + field = ft.CupertinoTextField( + value="Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + multiline=True, + min_lines=3, + autofocus=True, + on_selection_change=handle_selection_change, + ) + + async def select_characters(_: ft.Event[ft.Button]): + await field.focus() + field.selection = ft.TextSelection( + base_offset=0, + extent_offset=len(field.value), + ) + + async def move_caret(_: ft.Event[ft.Button]): + await field.focus() + field.selection = ft.TextSelection(base_offset=0, extent_offset=0) + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=10, + controls=[ + field, + selection, + selection_details, + caret, + ft.Button(content="Select all text", on_click=select_characters), + ft.Button(content="Move caret to start", on_click=move_caret), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino_text_field/selection_change/pyproject.toml b/sdk/python/examples/controls/cupertino_text_field/selection_change/pyproject.toml new file mode 100644 index 0000000000..ec7a8dee60 --- /dev/null +++ b/sdk/python/examples/controls/cupertino_text_field/selection_change/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-text-field-selection-change" +version = "1.0.0" +description = "Handles CupertinoTextField text selection changes and provides buttons to select text or move caret." +requires-python = ">=3.10" +keywords = ["cupertino", "text field", "selection", "caret", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoTextField"] + +[tool.flet.metadata] +title = "Selection change" +controls = ["SafeArea", "Column", "CupertinoTextField", "Text", "Button", "TextSelection"] +layout_pattern = "form" +complexity = "basic" +features = ["selection change callback", "programmatic selection", "caret control"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino_timer_picker/__init__.py b/sdk/python/examples/controls/cupertino_timer_picker/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/cupertino_timer_picker/basic.py b/sdk/python/examples/controls/cupertino_timer_picker/basic/main.py similarity index 53% rename from sdk/python/examples/controls/cupertino_timer_picker/basic.py rename to sdk/python/examples/controls/cupertino_timer_picker/basic/main.py index fe522e926b..b427f5f376 100644 --- a/sdk/python/examples/controls/cupertino_timer_picker/basic.py +++ b/sdk/python/examples/controls/cupertino_timer_picker/basic/main.py @@ -14,7 +14,6 @@ def main(page: ft.Page): def handle_timer_picker_change(e: ft.Event[ft.CupertinoTimerPicker]): timer_value_text.value = time.strftime("%H:%M:%S", time.gmtime(e.data)) - page.update() timer_picker = ft.CupertinoTimerPicker( value=300, @@ -25,22 +24,24 @@ def handle_timer_picker_change(e: ft.Event[ft.CupertinoTimerPicker]): ) page.add( - ft.Row( - tight=True, - controls=[ - ft.Text("TimerPicker Value:", size=23), - ft.CupertinoButton( - content=timer_value_text, - on_click=lambda e: page.show_dialog( - ft.CupertinoBottomSheet( - content=timer_picker, - height=216, - padding=ft.Padding.only(top=6), - ) + ft.SafeArea( + content=ft.Row( + tight=True, + controls=[ + ft.Text("TimerPicker Value:", size=23), + ft.CupertinoButton( + on_click=lambda _: page.show_dialog( + ft.CupertinoBottomSheet( + height=216, + padding=ft.Padding.only(top=6), + content=timer_picker, + ) + ), + content=timer_value_text, ), - ), - ], - ), + ], + ), + ) ) diff --git a/sdk/python/examples/controls/cupertino_timer_picker/basic/pyproject.toml b/sdk/python/examples/controls/cupertino_timer_picker/basic/pyproject.toml new file mode 100644 index 0000000000..28334699da --- /dev/null +++ b/sdk/python/examples/controls/cupertino_timer_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-timer-picker-basic" +version = "1.0.0" +description = "Opens CupertinoTimerPicker in a bottom sheet and updates displayed timer value on change." +requires-python = ">=3.10" +keywords = ["cupertino", "timer picker", "bottom sheet", "time", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoTimerPicker"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Row", "Text", "CupertinoButton", "CupertinoBottomSheet", "CupertinoTimerPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["timer selection", "on_change callback", "bottom sheet presentation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/cupertinolisttile.md b/sdk/python/packages/flet/docs/controls/cupertinolisttile.md index 05e50dae56..fadececbbc 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinolisttile.md +++ b/sdk/python/packages/flet/docs/controls/cupertinolisttile.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_list_tile/media ### Notched and non-notched list tiles ```python ---8<-- "{{ examples }}/notched.py" +--8<-- "{{ examples }}/notched/main.py" ``` {{ image(example_media + "/notched.png", alt="notched", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinonavigationbar.md b/sdk/python/packages/flet/docs/controls/cupertinonavigationbar.md index 50fc6eec46..329b531068 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinonavigationbar.md +++ b/sdk/python/packages/flet/docs/controls/cupertinonavigationbar.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/cupertino_navigation_bar/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../examples/controls/cupertino_navigation_bar/media ### Wired navigation bar ```python ---8<-- "{{ examples }}/wired.py" +--8<-- "{{ examples }}/wired/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinopicker.md b/sdk/python/packages/flet/docs/controls/cupertinopicker.md index 4a1fbcccb2..1961781aac 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinopicker.md +++ b/sdk/python/packages/flet/docs/controls/cupertinopicker.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/cupertino_picker/media ### Fruit selection ```python ---8<-- "{{ examples }}/fruit_selection.py" +--8<-- "{{ examples }}/fruit_selection/main.py" ``` {{ image(example_images + "/fruit_selection.gif", alt="fruit-selection", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinoradio.md b/sdk/python/packages/flet/docs/controls/cupertinoradio.md index 0ae14770b6..8990c90243 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinoradio.md +++ b/sdk/python/packages/flet/docs/controls/cupertinoradio.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_radio/media ### Cupertino, Material and Adaptive Radios ```python ---8<-- "{{ examples }}/cupertino_material_and_adaptive.py" +--8<-- "{{ examples }}/cupertino_material_and_adaptive/main.py" ``` {{ image(example_media + "/cupertino_material_and_adaptive.png", alt="cupertino-material-and-adaptive", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinosegmentedbutton.md b/sdk/python/packages/flet/docs/controls/cupertinosegmentedbutton.md index 04336b8bd0..a798cc5eb2 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinosegmentedbutton.md +++ b/sdk/python/packages/flet/docs/controls/cupertinosegmentedbutton.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_segmented_button/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/cupertino_segmented_button/media ### Adjusting segments padding ```python ---8<-- "{{ examples }}/segments_padding.py" +--8<-- "{{ examples }}/segments_padding/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinoslider.md b/sdk/python/packages/flet/docs/controls/cupertinoslider.md index b02d01f95e..629a15b05b 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinoslider.md +++ b/sdk/python/packages/flet/docs/controls/cupertinoslider.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_slider/media ### Handling events ```python ---8<-- "{{ examples }}/handling_events.py" +--8<-- "{{ examples }}/handling_events/main.py" ``` {{ image(example_media + "/handling_events.gif", alt="handling-events", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinoslidingsegmentedbutton.md b/sdk/python/packages/flet/docs/controls/cupertinoslidingsegmentedbutton.md index f704395654..3cf152b26e 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinoslidingsegmentedbutton.md +++ b/sdk/python/packages/flet/docs/controls/cupertinoslidingsegmentedbutton.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_sliding_segmented_button/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinoswitch.md b/sdk/python/packages/flet/docs/controls/cupertinoswitch.md index 166e83016d..ebe725d331 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinoswitch.md +++ b/sdk/python/packages/flet/docs/controls/cupertinoswitch.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_switch/media ### Cupertino, Material and Adaptive Switches ```python ---8<-- "{{ examples }}/cupertino_material_and_adaptive.py" +--8<-- "{{ examples }}/cupertino_material_and_adaptive/main.py" ``` {{ image(example_media + "/cupertino_material_and_adaptive.gif", alt="cupertino-material-and-adaptive", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinotextfield.md b/sdk/python/packages/flet/docs/controls/cupertinotextfield.md index 47519e59ac..d817d80e9e 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinotextfield.md +++ b/sdk/python/packages/flet/docs/controls/cupertinotextfield.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/cupertino_text_field/media ### Basic Example ```python ---8<-- "{{ examples }}/cupertino_material_and_adaptive.py" +--8<-- "{{ examples }}/cupertino_material_and_adaptive/main.py" ``` {{ image(example_media + "/cupertino_material_and_adaptive.png", alt="cupertino-material-and-adaptive", width="80%") }} @@ -22,13 +22,13 @@ example_media: ../examples/controls/cupertino_text_field/media ### Handling selection changes ```python ---8<-- "{{ examples }}/selection_change.py" +--8<-- "{{ examples }}/selection_change/main.py" ``` ### Background image ```python ---8<-- "{{ examples }}/background_image.py" +--8<-- "{{ examples }}/background_image/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/cupertinotimerpicker.md b/sdk/python/packages/flet/docs/controls/cupertinotimerpicker.md index bc470e8ea0..9466aaff22 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinotimerpicker.md +++ b/sdk/python/packages/flet/docs/controls/cupertinotimerpicker.md @@ -14,7 +14,7 @@ example_images: ../test-images/examples/cupertino/golden/macos/cupertino_timer_p ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/cupertino/test_cupertino_timer_picker.py b/sdk/python/packages/flet/integration_tests/examples/cupertino/test_cupertino_timer_picker.py index 1ac1e41e89..3ff4f5c72f 100644 --- a/sdk/python/packages/flet/integration_tests/examples/cupertino/test_cupertino_timer_picker.py +++ b/sdk/python/packages/flet/integration_tests/examples/cupertino/test_cupertino_timer_picker.py @@ -1,10 +1,9 @@ import pytest +import examples.controls.cupertino_timer_picker.basic.main as basic import flet as ft import flet.testing as ftt -from examples.controls.cupertino_timer_picker import basic - @pytest.mark.asyncio(loop_scope="function") async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): From 4c1d85239c24ba9bde4c114c5dfa887f44bc44b0 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 16:14:36 -0700 Subject: [PATCH 44/96] Restructure DataTable examples into subfolders Move DataTable example scripts into per-example folders with main.py and pyproject.toml, replace legacy flat example files and __init__.py. Wrap example UIs in SafeArea where appropriate and adjust some event/table update calls. Update documentation to reference the new examples/*/main.py paths and update integration tests to import the new example entrypoints. --- .../examples/controls/data_table/__init__.py | 0 .../data_table/adaptive_row_heights.py | 39 ----- .../data_table/adaptive_row_heights/main.py | 41 +++++ .../adaptive_row_heights/pyproject.toml | 26 +++ .../examples/controls/data_table/basic.py | 41 ----- .../controls/data_table/basic/main.py | 43 +++++ .../controls/data_table/basic/pyproject.toml | 26 +++ .../controls/data_table/handling_events.py | 82 ---------- .../data_table/handling_events/main.py | 81 ++++++++++ .../data_table/handling_events/pyproject.toml | 26 +++ .../data_table/sortable_and_selectable.py | 149 ------------------ .../sortable_and_selectable/main.py | 116 ++++++++++++++ .../sortable_and_selectable/pyproject.toml | 26 +++ .../examples/controls/data_table/spacing.py | 107 ------------- .../controls/data_table/spacing/main.py | 120 ++++++++++++++ .../data_table/spacing/pyproject.toml | 26 +++ .../flet/docs/controls/datatable/index.md | 10 +- .../examples/material/test_datatable.py | 5 +- 18 files changed, 540 insertions(+), 424 deletions(-) delete mode 100644 sdk/python/examples/controls/data_table/__init__.py delete mode 100644 sdk/python/examples/controls/data_table/adaptive_row_heights.py create mode 100644 sdk/python/examples/controls/data_table/adaptive_row_heights/main.py create mode 100644 sdk/python/examples/controls/data_table/adaptive_row_heights/pyproject.toml delete mode 100644 sdk/python/examples/controls/data_table/basic.py create mode 100644 sdk/python/examples/controls/data_table/basic/main.py create mode 100644 sdk/python/examples/controls/data_table/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/data_table/handling_events.py create mode 100644 sdk/python/examples/controls/data_table/handling_events/main.py create mode 100644 sdk/python/examples/controls/data_table/handling_events/pyproject.toml delete mode 100644 sdk/python/examples/controls/data_table/sortable_and_selectable.py create mode 100644 sdk/python/examples/controls/data_table/sortable_and_selectable/main.py create mode 100644 sdk/python/examples/controls/data_table/sortable_and_selectable/pyproject.toml delete mode 100644 sdk/python/examples/controls/data_table/spacing.py create mode 100644 sdk/python/examples/controls/data_table/spacing/main.py create mode 100644 sdk/python/examples/controls/data_table/spacing/pyproject.toml diff --git a/sdk/python/examples/controls/data_table/__init__.py b/sdk/python/examples/controls/data_table/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/data_table/adaptive_row_heights.py b/sdk/python/examples/controls/data_table/adaptive_row_heights.py deleted file mode 100644 index ef0e3cc400..0000000000 --- a/sdk/python/examples/controls/data_table/adaptive_row_heights.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.DataTable( - width=560, - data_row_min_height=48, - data_row_max_height=float("inf"), # infinity to allow adaptive row heights - columns=[ - ft.DataColumn(label="Description"), - ft.DataColumn(label="Notes"), - ], - rows=[ - ft.DataRow( - cells=[ - ft.DataCell("TWO lines visible without overflow"), - ft.DataCell("Line 1\nLine 2"), - ], - ), - ft.DataRow( - cells=[ - ft.DataCell("FOUR lines visible without overflow"), - ft.DataCell("Line 1\nLine 2\nLine 3\nLine 4"), - ], - ), - ft.DataRow( - cells=[ - ft.DataCell("FIVE lines visible without overflow"), - ft.DataCell("Line 1\nLine 2\nLine 3\nLine 4\nLine 5"), - ], - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/data_table/adaptive_row_heights/main.py b/sdk/python/examples/controls/data_table/adaptive_row_heights/main.py new file mode 100644 index 0000000000..b274ac4738 --- /dev/null +++ b/sdk/python/examples/controls/data_table/adaptive_row_heights/main.py @@ -0,0 +1,41 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.DataTable( + width=560, + data_row_min_height=48, + data_row_max_height=float("inf"), + columns=[ + ft.DataColumn(label="Description"), + ft.DataColumn(label="Notes"), + ], + rows=[ + ft.DataRow( + cells=[ + ft.DataCell("TWO lines visible without overflow"), + ft.DataCell("Line 1\nLine 2"), + ], + ), + ft.DataRow( + cells=[ + ft.DataCell("FOUR lines visible without overflow"), + ft.DataCell("Line 1\nLine 2\nLine 3\nLine 4"), + ], + ), + ft.DataRow( + cells=[ + ft.DataCell("FIVE lines visible without overflow"), + ft.DataCell("Line 1\nLine 2\nLine 3\nLine 4\nLine 5"), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/data_table/adaptive_row_heights/pyproject.toml b/sdk/python/examples/controls/data_table/adaptive_row_heights/pyproject.toml new file mode 100644 index 0000000000..819ec0f036 --- /dev/null +++ b/sdk/python/examples/controls/data_table/adaptive_row_heights/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-adaptive-row-heights" +version = "1.0.0" +description = "Demonstrates adaptive DataTable row heights for multi-line cell content using infinite max row height." +requires-python = ">=3.10" +keywords = ["data table", "adaptive row height", "multiline", "cells"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Adaptive row heights" +controls = ["SafeArea", "DataTable", "DataColumn", "DataRow", "DataCell"] +layout_pattern = "table-view" +complexity = "basic" +features = ["adaptive row height", "multiline cell content"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/data_table/basic.py b/sdk/python/examples/controls/data_table/basic.py deleted file mode 100644 index 5efa856e95..0000000000 --- a/sdk/python/examples/controls/data_table/basic.py +++ /dev/null @@ -1,41 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.DataTable( - expand=True, - columns=[ - ft.DataColumn(label=ft.Text("First name")), - ft.DataColumn(label=ft.Text("Last name")), - ft.DataColumn(label=ft.Text("Age"), numeric=True), - ], - rows=[ - ft.DataRow( - cells=[ - ft.DataCell(ft.Text("John")), - ft.DataCell(ft.Text("Smith")), - ft.DataCell(ft.Text("43")), - ], - ), - ft.DataRow( - cells=[ - ft.DataCell(ft.Text("Jack")), - ft.DataCell(ft.Text("Brown")), - ft.DataCell(ft.Text("19")), - ], - ), - ft.DataRow( - cells=[ - ft.DataCell(ft.Text("Alice")), - ft.DataCell(ft.Text("Wong")), - ft.DataCell(ft.Text("25")), - ], - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/data_table/basic/main.py b/sdk/python/examples/controls/data_table/basic/main.py new file mode 100644 index 0000000000..1aa53bbe3b --- /dev/null +++ b/sdk/python/examples/controls/data_table/basic/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.DataTable( + expand=True, + columns=[ + ft.DataColumn(label=ft.Text("First name")), + ft.DataColumn(label=ft.Text("Last name")), + ft.DataColumn(label=ft.Text("Age"), numeric=True), + ], + rows=[ + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("John")), + ft.DataCell(ft.Text("Smith")), + ft.DataCell(ft.Text("43")), + ], + ), + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("Jack")), + ft.DataCell(ft.Text("Brown")), + ft.DataCell(ft.Text("19")), + ], + ), + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("Alice")), + ft.DataCell(ft.Text("Wong")), + ft.DataCell(ft.Text("25")), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/data_table/basic/pyproject.toml b/sdk/python/examples/controls/data_table/basic/pyproject.toml new file mode 100644 index 0000000000..0943448c32 --- /dev/null +++ b/sdk/python/examples/controls/data_table/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-basic" +version = "1.0.0" +description = "Shows a basic DataTable with text columns and numeric age values." +requires-python = ">=3.10" +keywords = ["data table", "rows", "columns", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "DataTable", "DataColumn", "DataRow", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["tabular data", "numeric column"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/data_table/handling_events.py b/sdk/python/examples/controls/data_table/handling_events.py deleted file mode 100644 index 9b51a8504a..0000000000 --- a/sdk/python/examples/controls/data_table/handling_events.py +++ /dev/null @@ -1,82 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_row_selection_change(e: ft.Event[ft.DataRow]): - if e.control.data: - if e.control.data == 1: - row1.selected = not row1.selected - elif e.control.data == 2: - row2.selected = not row2.selected - elif e.control.data == 3: - row3.selected = not row3.selected - page.update() - - def handle_column_sort(e: ft.DataColumnSortEvent): - if e.control.data: - if e.control.data == 1: - print(f"{e.column_index}, {e.ascending}") - # table.sort_column_index = 1 - table.sort_ascending = e.ascending - elif e.control.data == 2: - print(f"{e.column_index}, {e.ascending}") - # table.sort_column_index = 2 - table.sort_ascending = e.ascending - page.update() - - page.add( - table := ft.DataTable( - width=700, - bgcolor=ft.Colors.TEAL_ACCENT_200, - border=ft.Border.all(2, ft.Colors.RED_ACCENT_200), - border_radius=10, - vertical_lines=ft.border.BorderSide(3, ft.Colors.BLUE_600), - horizontal_lines=ft.border.BorderSide(1, ft.Colors.GREEN_600), - sort_column_index=0, - sort_ascending=True, - heading_row_color=ft.Colors.BLACK_12, - heading_row_height=100, - data_row_color={ft.ControlState.HOVERED: "0x30FF0000"}, - show_checkbox_column=True, - divider_thickness=0, - column_spacing=200, - columns=[ - ft.DataColumn( - label=ft.Text("Column 1"), - tooltip="This is the first column", - data=1, - on_sort=handle_column_sort, - ), - ft.DataColumn( - label=ft.Text("Column 2"), - tooltip="This is a second column", - numeric=True, - data=2, - on_sort=handle_column_sort, - ), - ], - rows=[ - row1 := ft.DataRow( - cells=[ft.DataCell(ft.Text("A")), ft.DataCell(ft.Text("1"))], - selected=True, - on_select_change=handle_row_selection_change, - data=1, - ), - row2 := ft.DataRow( - cells=[ft.DataCell(ft.Text("B")), ft.DataCell(ft.Text("2"))], - selected=False, - on_select_change=handle_row_selection_change, - data=2, - ), - row3 := ft.DataRow( - cells=[ft.DataCell(ft.Text("C")), ft.DataCell(ft.Text("3"))], - selected=False, - on_select_change=handle_row_selection_change, - data=3, - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/data_table/handling_events/main.py b/sdk/python/examples/controls/data_table/handling_events/main.py new file mode 100644 index 0000000000..834ae328cb --- /dev/null +++ b/sdk/python/examples/controls/data_table/handling_events/main.py @@ -0,0 +1,81 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_row_selection_change(e: ft.Event[ft.DataRow]) -> None: + if e.control.data == 1: + row1.selected = not row1.selected + elif e.control.data == 2: + row2.selected = not row2.selected + elif e.control.data == 3: + row3.selected = not row3.selected + + table.update() + + def handle_column_sort(e: ft.DataColumnSortEvent) -> None: + if e.control.data in [1, 2]: + print(f"{e.column_index}, {e.ascending}") + table.sort_ascending = e.ascending + table.update() + + table = ft.DataTable( + width=700, + bgcolor=ft.Colors.TEAL_ACCENT_200, + border=ft.Border.all(2, ft.Colors.RED_ACCENT_200), + border_radius=10, + vertical_lines=ft.border.BorderSide(3, ft.Colors.BLUE_600), + horizontal_lines=ft.border.BorderSide(1, ft.Colors.GREEN_600), + sort_column_index=0, + sort_ascending=True, + heading_row_color=ft.Colors.BLACK_12, + heading_row_height=100, + data_row_color={ft.ControlState.HOVERED: "0x30FF0000"}, + show_checkbox_column=True, + divider_thickness=0, + column_spacing=200, + columns=[ + ft.DataColumn( + label=ft.Text("Column 1"), + tooltip="This is the first column", + data=1, + on_sort=handle_column_sort, + ), + ft.DataColumn( + label=ft.Text("Column 2"), + tooltip="This is a second column", + numeric=True, + data=2, + on_sort=handle_column_sort, + ), + ], + rows=[ + row1 := ft.DataRow( + cells=[ft.DataCell(ft.Text("A")), ft.DataCell(ft.Text("1"))], + selected=True, + on_select_change=handle_row_selection_change, + data=1, + ), + row2 := ft.DataRow( + cells=[ft.DataCell(ft.Text("B")), ft.DataCell(ft.Text("2"))], + selected=False, + on_select_change=handle_row_selection_change, + data=2, + ), + row3 := ft.DataRow( + cells=[ft.DataCell(ft.Text("C")), ft.DataCell(ft.Text("3"))], + selected=False, + on_select_change=handle_row_selection_change, + data=3, + ), + ], + ) + + page.add( + ft.SafeArea( + content=table, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/data_table/handling_events/pyproject.toml b/sdk/python/examples/controls/data_table/handling_events/pyproject.toml new file mode 100644 index 0000000000..7b0ba7433e --- /dev/null +++ b/sdk/python/examples/controls/data_table/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-handling-events" +version = "1.0.0" +description = "Handles DataTable row selection and column sort events with visual table state updates." +requires-python = ">=3.10" +keywords = ["data table", "events", "row selection", "sorting"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "DataTable", "DataColumn", "DataRow", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["row selection callback", "column sort callback", "table state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/data_table/sortable_and_selectable.py b/sdk/python/examples/controls/data_table/sortable_and_selectable.py deleted file mode 100644 index d8f4d39ffc..0000000000 --- a/sdk/python/examples/controls/data_table/sortable_and_selectable.py +++ /dev/null @@ -1,149 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - # Source data for the table (your domain objects). Each record has a stable `id` - # so we can track selection even when the table is sorted or rebuilt. - inventory_items = [ - {"id": 1, "name": "Alpha", "qty": 4}, - {"id": 2, "name": "Bravo", "qty": 9}, - {"id": 3, "name": "Charlie", "qty": 2}, - {"id": 4, "name": "Delta", "qty": 6}, - {"id": 5, "name": "Echo", "qty": 3}, - {"id": 6, "name": "Foxtrot", "qty": 8}, - {"id": 7, "name": "Golf", "qty": 1}, - {"id": 8, "name": "Hotel", "qty": 7}, - {"id": 9, "name": "India", "qty": 5}, - {"id": 10, "name": "Juliet", "qty": 10}, - ] - - # Working list used for sorting/reordering. We keep it separate so the original - # input remains untouched (useful if you later reload or re-filter data). - displayed_items = list(inventory_items) - - # Store selected item ids (not row indices) so selection survives sorting. - selected_item_ids: set[int] = {1, 3, 5} - - # Map column index -> callable used for sorting that column. - # Note: DataColumnSortEvent provides a `column_index` and an `ascending` flag. - sort_key_for_column = { - 0: lambda item: str(item["name"]).lower(), # "Item" column - 1: lambda item: int(item["qty"]), # "Quantity" column - } - - def build_rows(items: list[dict[str, int | str]]) -> list[ft.DataRow]: - """Convert a list of item dicts into DataRow objects.""" - return [ - ft.DataRow( - selected=item["id"] in selected_item_ids, - on_select_change=handle_row_selection_change, - data=item["id"], # used by event handlers to identify this item - cells=[ - ft.DataCell(ft.Text(item["name"])), - ft.DataCell(ft.Text(str(item["qty"]))), - ], - ) - for item in items - ] - - def refresh_table_rows(): - """ - Rebuild and redraw the table rows. - - Rebuilding rows is the simplest way to keep selection checkboxes and row - visuals consistent after a bulk change (sort, select-all, clear selection). - """ - table.rows = build_rows(displayed_items) - table.update() - - def handle_row_selection_change(e: ft.Event[ft.DataRow]): - """Called when a single row's checkbox is toggled.""" - row = e.control - item_id = row.data - is_selected = e.data # new selected state - - if is_selected: - selected_item_ids.add(item_id) - else: - selected_item_ids.discard(item_id) - - # Reflect the new state immediately on the toggled row. - e.control.selected = is_selected - e.control.update() - - def handle_select_all(e: ft.Event[ft.DataTable]): - """ - Called when the header "select all" checkbox is toggled. - - `e.data` is True when selecting all, False when clearing. - """ - select_all = e.data - - if select_all: - selected_item_ids.update(int(item["id"]) for item in displayed_items) - else: - selected_item_ids.clear() - - refresh_table_rows() - - def handle_column_sort(e: ft.DataColumnSortEvent): - """ - Called when a column header is clicked to sort. - - We sort `displayed_items` in-place and then refresh the rows. Selection is - preserved because it is tracked by item id in `selected_item_ids`. - """ - displayed_items.sort( - key=sort_key_for_column[e.column_index], - reverse=not e.ascending, - ) - - # Let the Table know which column is currently sorted and in what order. - table.sort_column_index = e.column_index - table.sort_ascending = e.ascending - - refresh_table_rows() - - page.add( - table := ft.DataTable( - width=700, - bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, - border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), - border_radius=10, - vertical_lines=ft.border.BorderSide(1, ft.Colors.OUTLINE_VARIANT), - horizontal_lines=ft.border.BorderSide(1, ft.Colors.OUTLINE_VARIANT), - sort_column_index=0, - sort_ascending=True, - heading_row_color=ft.Colors.SURFACE_CONTAINER_HIGHEST, - heading_row_height=100, - data_row_color={ - ft.ControlState.HOVERED: ft.Colors.with_opacity( - 0.08, ft.Colors.PRIMARY - ), - ft.ControlState.SELECTED: ft.Colors.with_opacity( - 0.14, ft.Colors.PRIMARY - ), - }, - show_checkbox_column=True, - on_select_all=handle_select_all, - divider_thickness=1, - column_spacing=200, - columns=[ - ft.DataColumn( - label=ft.Text("Item"), - on_sort=handle_column_sort, - ), - ft.DataColumn( - label=ft.Text("Quantity"), - tooltip="Numeric quantity", - numeric=True, - on_sort=handle_column_sort, - ), - ], - rows=build_rows(displayed_items), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/data_table/sortable_and_selectable/main.py b/sdk/python/examples/controls/data_table/sortable_and_selectable/main.py new file mode 100644 index 0000000000..ba277b0ff2 --- /dev/null +++ b/sdk/python/examples/controls/data_table/sortable_and_selectable/main.py @@ -0,0 +1,116 @@ +import flet as ft + + +def main(page: ft.Page): + inventory_items = [ + {"id": 1, "name": "Alpha", "qty": 4}, + {"id": 2, "name": "Bravo", "qty": 9}, + {"id": 3, "name": "Charlie", "qty": 2}, + {"id": 4, "name": "Delta", "qty": 6}, + {"id": 5, "name": "Echo", "qty": 3}, + {"id": 6, "name": "Foxtrot", "qty": 8}, + {"id": 7, "name": "Golf", "qty": 1}, + {"id": 8, "name": "Hotel", "qty": 7}, + {"id": 9, "name": "India", "qty": 5}, + {"id": 10, "name": "Juliet", "qty": 10}, + ] + displayed_items = list(inventory_items) + selected_item_ids: set[int] = {1, 3, 5} + + sort_key_for_column = { + 0: lambda item: str(item["name"]).lower(), + 1: lambda item: int(item["qty"]), + } + + def build_rows(items: list[dict[str, int | str]]) -> list[ft.DataRow]: + return [ + ft.DataRow( + selected=item["id"] in selected_item_ids, + on_select_change=handle_row_selection_change, + data=item["id"], + cells=[ + ft.DataCell(ft.Text(item["name"])), + ft.DataCell(ft.Text(str(item["qty"]))), + ], + ) + for item in items + ] + + def refresh_table_rows() -> None: + table.rows = build_rows(displayed_items) + table.update() + + def handle_row_selection_change(e: ft.Event[ft.DataRow]) -> None: + row = e.control + item_id = row.data + is_selected = e.data + + if is_selected: + selected_item_ids.add(item_id) + else: + selected_item_ids.discard(item_id) + + row.selected = is_selected + row.update() + + def handle_select_all(e: ft.Event[ft.DataTable]) -> None: + if e.data: + selected_item_ids.update(int(item["id"]) for item in displayed_items) + else: + selected_item_ids.clear() + + refresh_table_rows() + + def handle_column_sort(e: ft.DataColumnSortEvent) -> None: + displayed_items.sort( + key=sort_key_for_column[e.column_index], + reverse=not e.ascending, + ) + + table.sort_column_index = e.column_index + table.sort_ascending = e.ascending + refresh_table_rows() + + table = ft.DataTable( + width=700, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=10, + vertical_lines=ft.border.BorderSide(1, ft.Colors.OUTLINE_VARIANT), + horizontal_lines=ft.border.BorderSide(1, ft.Colors.OUTLINE_VARIANT), + sort_column_index=0, + sort_ascending=True, + heading_row_color=ft.Colors.SURFACE_CONTAINER_HIGHEST, + heading_row_height=100, + data_row_color={ + ft.ControlState.HOVERED: ft.Colors.with_opacity(0.08, ft.Colors.PRIMARY), + ft.ControlState.SELECTED: ft.Colors.with_opacity(0.14, ft.Colors.PRIMARY), + }, + show_checkbox_column=True, + on_select_all=handle_select_all, + divider_thickness=1, + column_spacing=200, + columns=[ + ft.DataColumn( + label=ft.Text("Item"), + on_sort=handle_column_sort, + ), + ft.DataColumn( + label=ft.Text("Quantity"), + tooltip="Numeric quantity", + numeric=True, + on_sort=handle_column_sort, + ), + ], + rows=build_rows(displayed_items), + ) + + page.add( + ft.SafeArea( + content=table, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/data_table/sortable_and_selectable/pyproject.toml b/sdk/python/examples/controls/data_table/sortable_and_selectable/pyproject.toml new file mode 100644 index 0000000000..5a6031e82c --- /dev/null +++ b/sdk/python/examples/controls/data_table/sortable_and_selectable/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-sortable-and-selectable" +version = "1.0.0" +description = "Implements sortable DataTable columns and selectable rows while preserving selection across sorts." +requires-python = ">=3.10" +keywords = ["data table", "sorting", "selection", "checkbox", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Sortable and selectable" +controls = ["SafeArea", "DataTable", "DataColumn", "DataRow", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "intermediate" +features = ["column sorting", "row selection", "select all", "stable selection across sorts"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/data_table/spacing.py b/sdk/python/examples/controls/data_table/spacing.py deleted file mode 100644 index 851325ada2..0000000000 --- a/sdk/python/examples/controls/data_table/spacing.py +++ /dev/null @@ -1,107 +0,0 @@ -import flet as ft - - -def _cell(label: str, color: str = ft.Colors.SURFACE_CONTAINER_HIGHEST) -> ft.DataCell: - return ft.DataCell( - ft.Container( - content=ft.Text(label, size=12, weight=ft.FontWeight.W_600), - width=90, - height=32, - alignment=ft.Alignment.CENTER, - bgcolor=color, - border=ft.Border.all(1, ft.Colors.BLACK_26), - ) - ) - - -def main(page: ft.Page): - page.scroll = ft.ScrollMode.AUTO - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.theme_mode = ft.ThemeMode.DARK - - def update_spacing(e: ft.Event[ft.Slider] = None): - table.horizontal_margin = horizontal_margin_slider.value - table.column_spacing = column_spacing_slider.value - page.update() - - def set_preset(horizontal_margin: float, column_spacing: float): - horizontal_margin_slider.value = horizontal_margin - column_spacing_slider.value = column_spacing - update_spacing() - - page.appbar = ft.AppBar(title="DataTable spacing") - page.add( - ft.Container( - width=520, - padding=12, - border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), - border_radius=8, - content=ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text("horizontal_margin (outer edges)"), - horizontal_margin_slider := ft.Slider( - min=0, - max=40, - divisions=40, - value=16, - label="{value}", - on_change=update_spacing, - ), - ft.Text("column_spacing (between columns)"), - column_spacing_slider := ft.Slider( - min=0, - max=40, - divisions=40, - value=16, - label="{value}", - on_change=update_spacing, - ), - ft.Row( - wrap=True, - controls=[ - ft.FilledButton( - "Reset", - on_click=lambda _: set_preset(16, 16), - ), - ft.OutlinedButton( - "Compact preset", - on_click=lambda _: set_preset(0, 0), - ), - ft.OutlinedButton( - "Spacious preset", - on_click=lambda _: set_preset(24, 32), - ), - ], - ), - ], - ), - ), - table := ft.DataTable( - border=ft.Border.all(1, ft.Colors.ON_SURFACE_VARIANT), - horizontal_margin=horizontal_margin_slider.value, - column_spacing=column_spacing_slider.value, - horizontal_lines=ft.BorderSide(1, ft.Colors.ON_SURFACE_VARIANT), - vertical_lines=ft.BorderSide(1, ft.Colors.ON_SURFACE_VARIANT), - heading_row_height=40, - data_row_min_height=40, - data_row_max_height=40, - columns=[ - ft.DataColumn(label="Col A"), - ft.DataColumn(label="Col B"), - ft.DataColumn(label="Col C"), - ], - rows=[ - ft.DataRow( - cells=[_cell("A1"), _cell("B1"), _cell("C1")], - ), - ft.DataRow( - cells=[_cell("A2"), _cell("B2"), _cell("C2")], - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/data_table/spacing/main.py b/sdk/python/examples/controls/data_table/spacing/main.py new file mode 100644 index 0000000000..924dc2f5e0 --- /dev/null +++ b/sdk/python/examples/controls/data_table/spacing/main.py @@ -0,0 +1,120 @@ +import flet as ft + + +def _cell(label: str, color: str = ft.Colors.SURFACE_CONTAINER_HIGHEST) -> ft.DataCell: + return ft.DataCell( + ft.Container( + width=90, + height=32, + alignment=ft.Alignment.CENTER, + bgcolor=color, + border=ft.Border.all(1, ft.Colors.BLACK_26), + content=ft.Text(label, size=12, weight=ft.FontWeight.W_600), + ) + ) + + +def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.theme_mode = ft.ThemeMode.DARK + + def update_spacing() -> None: + table.horizontal_margin = horizontal_margin_slider.value + table.column_spacing = column_spacing_slider.value + table.update() + + def handle_spacing_change(_: ft.Event[ft.Slider]) -> None: + update_spacing() + + def set_preset(horizontal_margin: float, column_spacing: float) -> None: + horizontal_margin_slider.value = horizontal_margin + column_spacing_slider.value = column_spacing + horizontal_margin_slider.update() + column_spacing_slider.update() + update_spacing() + + horizontal_margin_slider = ft.Slider( + min=0, + max=40, + divisions=40, + value=16, + label="{value}", + on_change=handle_spacing_change, + ) + column_spacing_slider = ft.Slider( + min=0, + max=40, + divisions=40, + value=16, + label="{value}", + on_change=handle_spacing_change, + ) + + table = ft.DataTable( + border=ft.Border.all(1, ft.Colors.ON_SURFACE_VARIANT), + horizontal_margin=horizontal_margin_slider.value, + column_spacing=column_spacing_slider.value, + horizontal_lines=ft.BorderSide(1, ft.Colors.ON_SURFACE_VARIANT), + vertical_lines=ft.BorderSide(1, ft.Colors.ON_SURFACE_VARIANT), + heading_row_height=40, + data_row_min_height=40, + data_row_max_height=40, + columns=[ + ft.DataColumn(label="Col A"), + ft.DataColumn(label="Col B"), + ft.DataColumn(label="Col C"), + ], + rows=[ + ft.DataRow(cells=[_cell("A1"), _cell("B1"), _cell("C1")]), + ft.DataRow(cells=[_cell("A2"), _cell("B2"), _cell("C2")]), + ], + ) + + page.appbar = ft.AppBar(title="DataTable spacing") + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Container( + width=520, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=8, + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("horizontal_margin (outer edges)"), + horizontal_margin_slider, + ft.Text("column_spacing (between columns)"), + column_spacing_slider, + ft.Row( + wrap=True, + controls=[ + ft.FilledButton( + "Reset", + on_click=lambda _: set_preset(16, 16), + ), + ft.OutlinedButton( + "Compact preset", + on_click=lambda _: set_preset(0, 0), + ), + ft.OutlinedButton( + "Spacious preset", + on_click=lambda _: set_preset(24, 32), + ), + ], + ), + ], + ), + ), + table, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/data_table/spacing/pyproject.toml b/sdk/python/examples/controls/data_table/spacing/pyproject.toml new file mode 100644 index 0000000000..cb2d259a87 --- /dev/null +++ b/sdk/python/examples/controls/data_table/spacing/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-spacing" +version = "1.0.0" +description = "Adjusts DataTable horizontal margin and column spacing interactively with sliders and presets." +requires-python = ">=3.10" +keywords = ["data table", "spacing", "horizontal margin", "slider", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Spacing" +controls = ["SafeArea", "Column", "DataTable", "DataColumn", "DataRow", "DataCell", "Slider", "FilledButton", "OutlinedButton", "Container", "Text", "AppBar"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["interactive spacing controls", "preset spacing buttons", "live table layout updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/datatable/index.md b/sdk/python/packages/flet/docs/controls/datatable/index.md index fdf613b583..bf6a50a2b1 100644 --- a/sdk/python/packages/flet/docs/controls/datatable/index.md +++ b/sdk/python/packages/flet/docs/controls/datatable/index.md @@ -15,7 +15,7 @@ example_images: ../../test-images/examples/material/golden/macos/datatable ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", width="80%") }} @@ -28,7 +28,7 @@ edge spacing of the first and last columns. Use [`column_spacing`][flet.DataTable.column_spacing] to control spacing between columns. ```python ---8<-- "{{ examples }}/spacing.py" +--8<-- "{{ examples }}/spacing/main.py" ``` ### Adaptive row heights @@ -38,7 +38,7 @@ Setting [`data_row_max_height`][flet.DataTable.data_row_max_height] to `float('i respective content, instead of all rows having the same height. ```python ---8<-- "{{ examples }}/adaptive_row_heights.py" +--8<-- "{{ examples }}/adaptive_row_heights/main.py" ``` ### Sortable columns and selectable rows @@ -47,7 +47,7 @@ This example demonstrates row selection (including select-all), sortable string and numeric columns, and stable selection across sorts and refreshes. ```python ---8<-- "{{ examples }}/sortable_and_selectable.py" +--8<-- "{{ examples }}/sortable_and_selectable/main.py" ``` {{ image(example_images + "/sortable_and_selectable.png", width="80%") }} @@ -56,7 +56,7 @@ sortable string and numeric columns, and stable selection across sorts and refre ### Handling events ```python ---8<-- "{{ examples }}/handling_events.py" +--8<-- "{{ examples }}/handling_events/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_datatable.py b/sdk/python/packages/flet/integration_tests/examples/material/test_datatable.py index f3d650b31c..3f5e64eaa8 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_datatable.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_datatable.py @@ -2,7 +2,10 @@ import flet as ft import flet.testing as ftt -from examples.controls.data_table import basic, sortable_and_selectable +from examples.controls.data_table.basic import main as basic +from examples.controls.data_table.sortable_and_selectable import ( + main as sortable_and_selectable, +) @pytest.mark.asyncio(loop_scope="function") From eba3bdaaba9e7942a03e14eee8f5e9a726f47b68 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Fri, 13 Mar 2026 16:22:38 -0700 Subject: [PATCH 45/96] Refactor datatable2 examples into example subfolders Reorganize datatable2 examples into example_1 and example_2 subfolders: move/rename example scripts to main.py, add pyproject.toml for each example, and relocate data.py into example_2. Apply small code cleanups (SafeArea wrappers, __main__ guards, type annotations, simplified list builders, and a minor on_select_all parameter change). Update docs to point to the new example paths. --- .../examples/controls/datatable2/example_1.py | 19 ----- .../controls/datatable2/example_1/main.py | 21 +++++ .../datatable2/example_1/pyproject.toml | 26 ++++++ .../datatable2/{ => example_2}/data.py | 0 .../{example_2.py => example_2/main.py} | 83 ++++++++----------- .../datatable2/example_2/pyproject.toml | 26 ++++++ .../packages/flet/docs/datatable2/index.md | 4 +- 7 files changed, 111 insertions(+), 68 deletions(-) delete mode 100644 sdk/python/examples/controls/datatable2/example_1.py create mode 100644 sdk/python/examples/controls/datatable2/example_1/main.py create mode 100644 sdk/python/examples/controls/datatable2/example_1/pyproject.toml rename sdk/python/examples/controls/datatable2/{ => example_2}/data.py (100%) rename sdk/python/examples/controls/datatable2/{example_2.py => example_2/main.py} (54%) create mode 100644 sdk/python/examples/controls/datatable2/example_2/pyproject.toml diff --git a/sdk/python/examples/controls/datatable2/example_1.py b/sdk/python/examples/controls/datatable2/example_1.py deleted file mode 100644 index b5a3c56c3b..0000000000 --- a/sdk/python/examples/controls/datatable2/example_1.py +++ /dev/null @@ -1,19 +0,0 @@ -import flet_datatable2 as fdt - -import flet as ft - - -def main(page: ft.Page): - page.add( - fdt.DataTable2( - empty=ft.Text("This table is empty."), - columns=[ - fdt.DataColumn2(label=ft.Text("First name")), - fdt.DataColumn2(label=ft.Text("Last name")), - fdt.DataColumn2(label=ft.Text("Age"), numeric=True), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/datatable2/example_1/main.py b/sdk/python/examples/controls/datatable2/example_1/main.py new file mode 100644 index 0000000000..1ff6eca6c2 --- /dev/null +++ b/sdk/python/examples/controls/datatable2/example_1/main.py @@ -0,0 +1,21 @@ +import flet as ft +import flet_datatable2 as fdt + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=fdt.DataTable2( + empty=ft.Text("This table is empty."), + columns=[ + fdt.DataColumn2(label=ft.Text("First name")), + fdt.DataColumn2(label=ft.Text("Last name")), + fdt.DataColumn2(label=ft.Text("Age"), numeric=True), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/datatable2/example_1/pyproject.toml b/sdk/python/examples/controls/datatable2/example_1/pyproject.toml new file mode 100644 index 0000000000..ce80295c8e --- /dev/null +++ b/sdk/python/examples/controls/datatable2/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "datatable2-example-1" +version = "1.0.0" +description = "Shows an empty DataTable2 state with configured columns and placeholder content." +requires-python = ">=3.10" +keywords = ["datatable2", "data table", "empty state", "extension"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-datatable2"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable2"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "DataTable2", "DataColumn2", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["empty table state", "DataTable2 columns"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/datatable2/data.py b/sdk/python/examples/controls/datatable2/example_2/data.py similarity index 100% rename from sdk/python/examples/controls/datatable2/data.py rename to sdk/python/examples/controls/datatable2/example_2/data.py diff --git a/sdk/python/examples/controls/datatable2/example_2.py b/sdk/python/examples/controls/datatable2/example_2/main.py similarity index 54% rename from sdk/python/examples/controls/datatable2/example_2.py rename to sdk/python/examples/controls/datatable2/example_2/main.py index d929e034bf..46fcd83d2d 100644 --- a/sdk/python/examples/controls/datatable2/example_2.py +++ b/sdk/python/examples/controls/datatable2/example_2/main.py @@ -7,16 +7,18 @@ def main(page: ft.Page): page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + sorted_desserts = list(desserts) data_table: ftd.DataTable2 | None = None - def handle_row_selection_change(e: ft.Event[ftd.DataRow2]): + def handle_row_selection_change(e: ft.Event[ftd.DataRow2]) -> None: e.control.selected = not e.control.selected e.control.update() - def sort_column(e: ft.DataColumnSortEvent): + def sort_column(e: ft.DataColumnSortEvent) -> None: if data_table is None: return + sorters = [ lambda d: d.name.lower(), lambda d: d.calories, @@ -33,8 +35,8 @@ def sort_column(e: ft.DataColumnSortEvent): data_table.sort_ascending = e.ascending data_table.update() - def get_data_columns(): - data_columns = [ + def get_data_columns() -> list[ftd.DataColumn2]: + return [ ftd.DataColumn2( label=ft.Text("Name"), size=ftd.DataColumnSize.L, @@ -47,59 +49,40 @@ def get_data_columns(): numeric=True, heading_row_alignment=ft.MainAxisAlignment.END, ), - ftd.DataColumn2( - label=ft.Text("Fat"), - on_sort=sort_column, - numeric=True, - ), - ftd.DataColumn2( - label=ft.Text("Carbs"), - on_sort=sort_column, - numeric=True, - ), + ftd.DataColumn2(label=ft.Text("Fat"), on_sort=sort_column, numeric=True), + ftd.DataColumn2(label=ft.Text("Carbs"), on_sort=sort_column, numeric=True), ftd.DataColumn2( label=ft.Text("Protein"), on_sort=sort_column, numeric=True, ), - ftd.DataColumn2( - label=ft.Text("Sodium"), - on_sort=sort_column, - numeric=True, - ), + ftd.DataColumn2(label=ft.Text("Sodium"), on_sort=sort_column, numeric=True), ftd.DataColumn2( label=ft.Text("Calcium"), on_sort=sort_column, numeric=True, ), - ftd.DataColumn2( - label=ft.Text("Iron"), - on_sort=sort_column, - numeric=True, - ), + ftd.DataColumn2(label=ft.Text("Iron"), on_sort=sort_column, numeric=True), ] - return data_columns - def get_data_rows(desserts): - data_rows = [] - for dessert in desserts: - data_rows.append( - ftd.DataRow2( - specific_row_height=50, - on_select_change=handle_row_selection_change, - cells=[ - ft.DataCell(content=ft.Text(dessert.name)), - ft.DataCell(content=ft.Text(dessert.calories)), - ft.DataCell(content=ft.Text(dessert.fat)), - ft.DataCell(content=ft.Text(dessert.carbs)), - ft.DataCell(content=ft.Text(dessert.protein)), - ft.DataCell(content=ft.Text(dessert.sodium)), - ft.DataCell(content=ft.Text(dessert.calcium)), - ft.DataCell(content=ft.Text(dessert.iron)), - ], - ) + def get_data_rows(items: list) -> list[ftd.DataRow2]: + return [ + ftd.DataRow2( + specific_row_height=50, + on_select_change=handle_row_selection_change, + cells=[ + ft.DataCell(content=ft.Text(dessert.name)), + ft.DataCell(content=ft.Text(dessert.calories)), + ft.DataCell(content=ft.Text(dessert.fat)), + ft.DataCell(content=ft.Text(dessert.carbs)), + ft.DataCell(content=ft.Text(dessert.protein)), + ft.DataCell(content=ft.Text(dessert.sodium)), + ft.DataCell(content=ft.Text(dessert.calcium)), + ft.DataCell(content=ft.Text(dessert.iron)), + ], ) - return data_rows + for dessert in items + ] data_table = ftd.DataTable2( show_checkbox_column=True, @@ -110,11 +93,17 @@ def get_data_rows(desserts): sort_ascending=True, bottom_margin=10, min_width=600, - on_select_all=lambda e: print("All selected"), + on_select_all=lambda _: print("All selected"), columns=get_data_columns(), rows=get_data_rows(sorted_desserts), ) - page.add(data_table) + + page.add( + ft.SafeArea( + content=data_table, + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/datatable2/example_2/pyproject.toml b/sdk/python/examples/controls/datatable2/example_2/pyproject.toml new file mode 100644 index 0000000000..52a448cd1a --- /dev/null +++ b/sdk/python/examples/controls/datatable2/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "datatable2-example-2" +version = "1.0.0" +description = "Builds an interactive DataTable2 with sortable nutrition columns and selectable rows." +requires-python = ">=3.10" +keywords = ["datatable2", "sorting", "selection", "rows", "extension"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-datatable2"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable2"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "DataTable2", "DataColumn2", "DataRow2", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["column sorting", "row selection", "select-all callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/datatable2/index.md b/sdk/python/packages/flet/docs/datatable2/index.md index 8957facc60..b427ed5a45 100644 --- a/sdk/python/packages/flet/docs/datatable2/index.md +++ b/sdk/python/packages/flet/docs/datatable2/index.md @@ -38,13 +38,13 @@ pip install flet-datatable2 # (1)! ### Example 1 ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ### Example 2 ```python ---8<-- "{{ examples }}/example_2.py" +--8<-- "{{ examples }}/example_2/main.py" ``` {{ image(example_media + "/example_2.gif", width="80%") }} From 88a745427ed026efdd7b4cc4cdb967574645915f Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 08:24:56 -0700 Subject: [PATCH 46/96] Restructure Python examples into standalone projects Move and convert many SDK Python examples into per-example folders with main.py and pyproject.toml, add SafeArea wrappers, and make declarative examples renderable via page.render(App). Added metadata files for each example and updated docs to reference new ".../main.py" paths. Updated .codex SKILL guidance about declarative @ft.component usage (don't pass component instances as children; render with page.render(App)). Minor change to cupertino-date-picker keywords in its pyproject.toml. Refactors include converting imperative examples to use message columns, stable dismissible handling, and declarative drag-and-drop adaptations. --- .../create-flet-example-projects/SKILL.md | 2 + .../custom_locale/pyproject.toml | 2 +- .../examples/controls/date_picker/basic.py | 33 ------- .../controls/date_picker/basic/main.py | 46 ++++++++++ .../controls/date_picker/basic/pyproject.toml | 26 ++++++ .../controls/date_picker/custom_locale.py | 18 ---- .../date_picker/custom_locale/main.py | 21 +++++ .../date_picker/custom_locale/pyproject.toml | 26 ++++++ .../controls/date_range_picker/basic.py | 38 -------- .../controls/date_range_picker/basic/main.py | 53 +++++++++++ .../date_range_picker/basic/pyproject.toml | 26 ++++++ .../date_range_picker/custom_locale.py | 18 ---- .../date_range_picker/custom_locale/main.py | 21 +++++ .../custom_locale/pyproject.toml | 26 ++++++ .../dismissible/dismissible_list_tiles.py | 59 ------------ .../dismissible_list_tiles/main.py | 60 +++++++++++++ .../dismissible_list_tiles/pyproject.toml | 26 ++++++ .../remove_on_dismiss_declarative.py | 29 ------ .../remove_on_dismiss_declarative/main.py | 36 ++++++++ .../pyproject.toml | 26 ++++++ sdk/python/examples/controls/divider/basic.py | 38 -------- .../examples/controls/divider/basic/main.py | 42 +++++++++ .../controls/divider/basic/pyproject.toml | 26 ++++++ .../drag_and_drop_containers/main.py | 83 +++++++++++++++++ .../drag_and_drop_containers/pyproject.toml | 26 ++++++ .../drag_and_drop_containers_declarative.py | 89 ------------------- .../main.py} | 67 +++++++++----- .../pyproject.toml | 26 ++++++ .../main.py} | 45 +++++----- .../pyproject.toml | 26 ++++++ .../packages/flet/docs/controls/datepicker.md | 2 +- .../flet/docs/controls/daterangepicker.md | 2 +- .../flet/docs/controls/dismissible.md | 4 +- .../packages/flet/docs/controls/divider.md | 2 +- .../packages/flet/docs/controls/draggable.md | 4 +- 35 files changed, 700 insertions(+), 374 deletions(-) delete mode 100644 sdk/python/examples/controls/date_picker/basic.py create mode 100644 sdk/python/examples/controls/date_picker/basic/main.py create mode 100644 sdk/python/examples/controls/date_picker/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/date_picker/custom_locale.py create mode 100644 sdk/python/examples/controls/date_picker/custom_locale/main.py create mode 100644 sdk/python/examples/controls/date_picker/custom_locale/pyproject.toml delete mode 100644 sdk/python/examples/controls/date_range_picker/basic.py create mode 100644 sdk/python/examples/controls/date_range_picker/basic/main.py create mode 100644 sdk/python/examples/controls/date_range_picker/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/date_range_picker/custom_locale.py create mode 100644 sdk/python/examples/controls/date_range_picker/custom_locale/main.py create mode 100644 sdk/python/examples/controls/date_range_picker/custom_locale/pyproject.toml delete mode 100644 sdk/python/examples/controls/dismissible/dismissible_list_tiles.py create mode 100644 sdk/python/examples/controls/dismissible/dismissible_list_tiles/main.py create mode 100644 sdk/python/examples/controls/dismissible/dismissible_list_tiles/pyproject.toml delete mode 100644 sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative.py create mode 100644 sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative/main.py create mode 100644 sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative/pyproject.toml delete mode 100644 sdk/python/examples/controls/divider/basic.py create mode 100644 sdk/python/examples/controls/divider/basic/main.py create mode 100644 sdk/python/examples/controls/divider/basic/pyproject.toml create mode 100644 sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers/main.py create mode 100644 sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers/pyproject.toml delete mode 100644 sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative.py rename sdk/python/examples/controls/drag_target_and_draggable/{drag_and_drop_containers.py => drag_and_drop_containers_declarative/main.py} (60%) create mode 100644 sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative/pyproject.toml rename sdk/python/examples/controls/drag_target_and_draggable/{drag_and_drop_ordering_declarative.py => drag_and_drop_ordering_declarative/main.py} (89%) create mode 100644 sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative/pyproject.toml diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index c6cf5c3357..798edb5e25 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -74,6 +74,8 @@ Ensure each runnable example is a standalone project containing: - Apply this to all examples in the touched folder (new, migrated, and already converted), not only files changed by moves. - During validation, confirm every `/main.py` in scope includes a top-level `ft.SafeArea` around rendered content. +- For declarative examples using `@ft.component`, do not pass component instances as regular control children (for example `SafeArea(content=App())`) because this can raise runtime attribute errors. +- In declarative examples, ensure the component itself returns regular controls (including `SafeArea` when needed) and render it at page level with `page.render(App)` in `main()`. 7. Prefer `@ft.control` for custom controls in examples. - If an example defines a custom control class inheriting from a Flet control (for example `class MyThing(ft.Column)`), prefer `@ft.control` style. diff --git a/sdk/python/examples/controls/cupertino_date_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/cupertino_date_picker/custom_locale/pyproject.toml index 1c922279f2..5d73da8931 100644 --- a/sdk/python/examples/controls/cupertino_date_picker/custom_locale/pyproject.toml +++ b/sdk/python/examples/controls/cupertino_date_picker/custom_locale/pyproject.toml @@ -3,7 +3,7 @@ name = "cupertino-date-picker-custom-locale" version = "1.0.0" description = "Opens CupertinoDatePicker with zh_Hans locale to demonstrate localized date formatting." requires-python = ">=3.10" -keywords = ["cupertino", "date picker", "locale", "internationalization", "zh_Hans"] +keywords = ["date picker", "custom locale", "locale", "internationalization", "zh_Hans"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] dependencies = ["flet"] diff --git a/sdk/python/examples/controls/date_picker/basic.py b/sdk/python/examples/controls/date_picker/basic.py deleted file mode 100644 index b888792b83..0000000000 --- a/sdk/python/examples/controls/date_picker/basic.py +++ /dev/null @@ -1,33 +0,0 @@ -import datetime - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_change(e: ft.Event[ft.DatePicker]): - page.add(ft.Text(f"Date changed: {e.control.value.strftime('%m/%d/%Y')}")) - - def handle_dismissal(e: ft.Event[ft.DialogControl]): - page.add(ft.Text("DatePicker dismissed")) - - today = datetime.datetime.now() - - d = ft.DatePicker( - first_date=datetime.datetime(year=today.year - 1, month=1, day=1), - last_date=datetime.datetime(year=today.year + 1, month=today.month, day=20), - on_change=handle_change, - on_dismiss=handle_dismissal, - ) - - page.add( - ft.Button( - content="Pick date", - icon=ft.Icons.CALENDAR_MONTH, - on_click=lambda e: page.show_dialog(d), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/date_picker/basic/main.py b/sdk/python/examples/controls/date_picker/basic/main.py new file mode 100644 index 0000000000..eae14605f1 --- /dev/null +++ b/sdk/python/examples/controls/date_picker/basic/main.py @@ -0,0 +1,46 @@ +import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + messages = ft.Column(tight=True) + + def handle_change(e: ft.Event[ft.DatePicker]): + messages.controls.append( + ft.Text(f"Date changed: {e.control.value.strftime('%m/%d/%Y')}") + ) + + def handle_dismissal(_: ft.Event[ft.DialogControl]): + messages.controls.append(ft.Text("DatePicker dismissed")) + + today = datetime.datetime.now() + + picker = ft.DatePicker( + first_date=datetime.datetime(year=today.year - 1, month=1, day=1), + last_date=datetime.datetime(year=today.year + 1, month=today.month, day=20), + on_change=handle_change, + on_dismiss=handle_dismissal, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Button( + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _: page.show_dialog(picker), + content="Pick date", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/date_picker/basic/pyproject.toml b/sdk/python/examples/controls/date_picker/basic/pyproject.toml new file mode 100644 index 0000000000..3a637a72e7 --- /dev/null +++ b/sdk/python/examples/controls/date_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "date-picker-basic" +version = "1.0.0" +description = "Opens DatePicker dialog and logs selected date and dismiss events in the page content." +requires-python = ">=3.10" +keywords = ["date picker", "dialog", "events", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/DatePicker"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Button", "DatePicker", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["open dialog", "date change callback", "dismiss callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/date_picker/custom_locale.py b/sdk/python/examples/controls/date_picker/custom_locale.py deleted file mode 100644 index 7fb9d1924a..0000000000 --- a/sdk/python/examples/controls/date_picker/custom_locale.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - page.add( - ft.Button( - content="Pick date (zh_Hans locale)", - icon=ft.Icons.CALENDAR_MONTH, - on_click=lambda e: page.show_dialog( - ft.DatePicker(locale=ft.Locale("zh", "Hans")) - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/date_picker/custom_locale/main.py b/sdk/python/examples/controls/date_picker/custom_locale/main.py new file mode 100644 index 0000000000..3240e1167c --- /dev/null +++ b/sdk/python/examples/controls/date_picker/custom_locale/main.py @@ -0,0 +1,21 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Button( + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _: page.show_dialog( + ft.DatePicker(locale=ft.Locale("zh", "Hans")) + ), + content="Pick date (zh_Hans locale)", + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/date_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/date_picker/custom_locale/pyproject.toml new file mode 100644 index 0000000000..e1eaefa81c --- /dev/null +++ b/sdk/python/examples/controls/date_picker/custom_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "date-picker-custom-locale" +version = "1.0.0" +description = "Opens DatePicker with zh_Hans locale to demonstrate localized calendar UI." +requires-python = ">=3.10" +keywords = ["date picker", "custom locale", "locale", "internationalization", "zh_Hans"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/DatePicker"] + +[tool.flet.metadata] +title = "Custom locale" +controls = ["SafeArea", "Button", "DatePicker", "Locale"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["localized date picker", "dialog open action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/date_range_picker/basic.py b/sdk/python/examples/controls/date_range_picker/basic.py deleted file mode 100644 index bd59d6dfc6..0000000000 --- a/sdk/python/examples/controls/date_range_picker/basic.py +++ /dev/null @@ -1,38 +0,0 @@ -import datetime - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_change(e: ft.Event[ft.DateRangePicker]): - page.add( - ft.Text( - f"Start Date changed: {e.control.start_value.strftime('%m/%d/%Y')}" - ), - ft.Text(f"End Date changed: {e.control.end_value.strftime('%m/%d/%Y')}"), - ) - - def handle_dismissal(e: ft.Event[ft.DialogControl]): - page.add(ft.Text("DatePicker dismissed")) - - today = datetime.datetime.now() - - drp = ft.DateRangePicker( - start_value=datetime.datetime(year=today.year, month=today.month, day=1), - end_value=datetime.datetime(year=today.year, month=today.month, day=15), - on_change=handle_change, - on_dismiss=handle_dismissal, - ) - - page.add( - ft.Button( - content=ft.Text("Pick date"), - icon=ft.Icons.PHONE, - on_click=lambda e: page.show_dialog(drp), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/date_range_picker/basic/main.py b/sdk/python/examples/controls/date_range_picker/basic/main.py new file mode 100644 index 0000000000..3597e791ad --- /dev/null +++ b/sdk/python/examples/controls/date_range_picker/basic/main.py @@ -0,0 +1,53 @@ +import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + messages = ft.Column(tight=True) + + def handle_change(e: ft.Event[ft.DateRangePicker]): + messages.controls.extend( + [ + ft.Text( + f"Start Date changed: {e.control.start_value.strftime('%m/%d/%Y')}" + ), + ft.Text( + f"End Date changed: {e.control.end_value.strftime('%m/%d/%Y')}" + ), + ] + ) + + def handle_dismissal(_: ft.Event[ft.DialogControl]): + messages.controls.append(ft.Text("DateRangePicker dismissed")) + + today = datetime.datetime.now() + + picker = ft.DateRangePicker( + start_value=datetime.datetime(year=today.year, month=today.month, day=1), + end_value=datetime.datetime(year=today.year, month=today.month, day=15), + on_change=handle_change, + on_dismiss=handle_dismissal, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Button( + icon=ft.Icons.DATE_RANGE, + on_click=lambda _: page.show_dialog(picker), + content="Pick date range", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/date_range_picker/basic/pyproject.toml b/sdk/python/examples/controls/date_range_picker/basic/pyproject.toml new file mode 100644 index 0000000000..277af9af5f --- /dev/null +++ b/sdk/python/examples/controls/date_range_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "date-range-picker-basic" +version = "1.0.0" +description = "Opens DateRangePicker and displays start and end date values after selection." +requires-python = ">=3.10" +keywords = ["date range picker", "dialog", "events", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/DateRangePicker"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Button", "DateRangePicker", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["open dialog", "range change callback", "dismiss callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/date_range_picker/custom_locale.py b/sdk/python/examples/controls/date_range_picker/custom_locale.py deleted file mode 100644 index 79853b7178..0000000000 --- a/sdk/python/examples/controls/date_range_picker/custom_locale.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - page.add( - ft.Button( - content="Pick dates (zh_Hans locale)", - icon=ft.Icons.CALENDAR_MONTH, - on_click=lambda e: page.show_dialog( - ft.DateRangePicker(locale=ft.Locale("zh", "Hans")) - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/date_range_picker/custom_locale/main.py b/sdk/python/examples/controls/date_range_picker/custom_locale/main.py new file mode 100644 index 0000000000..75d432c54b --- /dev/null +++ b/sdk/python/examples/controls/date_range_picker/custom_locale/main.py @@ -0,0 +1,21 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Button( + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _: page.show_dialog( + ft.DateRangePicker(locale=ft.Locale("zh", "Hans")) + ), + content="Pick dates (zh_Hans locale)", + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/date_range_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/date_range_picker/custom_locale/pyproject.toml new file mode 100644 index 0000000000..96095238e7 --- /dev/null +++ b/sdk/python/examples/controls/date_range_picker/custom_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "date-range-picker-custom-locale" +version = "1.0.0" +description = "Opens DateRangePicker with zh_Hans locale for localized date range selection." +requires-python = ">=3.10" +keywords = ["date range picker", "custom locale", "locale", "internationalization", "zh_Hans"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/DateRangePicker"] + +[tool.flet.metadata] +title = "Custom locale" +controls = ["SafeArea", "Button", "DateRangePicker", "Locale"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["localized date range picker", "dialog open action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dismissible/dismissible_list_tiles.py b/sdk/python/examples/controls/dismissible/dismissible_list_tiles.py deleted file mode 100644 index 585c402d8c..0000000000 --- a/sdk/python/examples/controls/dismissible/dismissible_list_tiles.py +++ /dev/null @@ -1,59 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - async def handle_dialog_action_click(e: ft.Event[ft.TextButton]): - page.pop_dialog() - await dlg.data.confirm_dismiss(e.control.data) - - dlg = ft.AlertDialog( - modal=True, - title=ft.Text("Please confirm"), - content=ft.Text("Do you really want to delete this item?"), - actions=[ - ft.TextButton("Yes", data=True, on_click=handle_dialog_action_click), - ft.TextButton("No", data=False, on_click=handle_dialog_action_click), - ], - actions_alignment=ft.MainAxisAlignment.CENTER, - ) - - async def handle_confirm_dismiss(e: ft.DismissibleDismissEvent): - if e.direction == ft.DismissDirection.END_TO_START: # right-to-left slide - # save current dismissible to dialog's data, for confirmation in - # handle_dialog_action_click - dlg.data = e.control - page.show_dialog(dlg) - else: # left-to-right slide - await e.control.confirm_dismiss(True) - - def handle_dismiss(e): - e.control.parent.controls.remove(e.control) - page.update() - - def handle_update(e: ft.DismissibleUpdateEvent): - print(e) - - page.add( - ft.ListView( - expand=True, - controls=[ - ft.Dismissible( - content=ft.ListTile(title=ft.Text(f"Item {i}")), - dismiss_direction=ft.DismissDirection.HORIZONTAL, - background=ft.Container(bgcolor=ft.Colors.GREEN), - secondary_background=ft.Container(bgcolor=ft.Colors.RED), - on_dismiss=handle_dismiss, - on_update=handle_update, - on_confirm_dismiss=handle_confirm_dismiss, - dismiss_thresholds={ - ft.DismissDirection.END_TO_START: 0.2, - ft.DismissDirection.START_TO_END: 0.2, - }, - ) - for i in range(10) - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/dismissible/dismissible_list_tiles/main.py b/sdk/python/examples/controls/dismissible/dismissible_list_tiles/main.py new file mode 100644 index 0000000000..cbda275343 --- /dev/null +++ b/sdk/python/examples/controls/dismissible/dismissible_list_tiles/main.py @@ -0,0 +1,60 @@ +import flet as ft + + +def main(page: ft.Page): + async def handle_dialog_action_click(e: ft.Event[ft.TextButton]): + page.pop_dialog() + await dialog.data.confirm_dismiss(e.control.data) + + dialog = ft.AlertDialog( + modal=True, + title=ft.Text("Please confirm"), + content=ft.Text("Do you really want to delete this item?"), + actions=[ + ft.TextButton("Yes", data=True, on_click=handle_dialog_action_click), + ft.TextButton("No", data=False, on_click=handle_dialog_action_click), + ], + actions_alignment=ft.MainAxisAlignment.CENTER, + ) + + async def handle_confirm_dismiss(e: ft.DismissibleDismissEvent): + if e.direction == ft.DismissDirection.END_TO_START: + dialog.data = e.control + page.show_dialog(dialog) + else: + await e.control.confirm_dismiss(True) + + def handle_dismiss(e: ft.Event[ft.Dismissible]): + e.control.parent.controls.remove(e.control) + e.control.parent.update() + + def handle_update(e: ft.DismissibleUpdateEvent): + print(e) + + page.add( + ft.SafeArea( + content=ft.ListView( + expand=True, + controls=[ + ft.Dismissible( + dismiss_direction=ft.DismissDirection.HORIZONTAL, + background=ft.Container(bgcolor=ft.Colors.GREEN), + secondary_background=ft.Container(bgcolor=ft.Colors.RED), + on_dismiss=handle_dismiss, + on_update=handle_update, + on_confirm_dismiss=handle_confirm_dismiss, + dismiss_thresholds={ + ft.DismissDirection.END_TO_START: 0.2, + ft.DismissDirection.START_TO_END: 0.2, + }, + content=ft.ListTile(title=ft.Text(f"Item {i}")), + ) + for i in range(10) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dismissible/dismissible_list_tiles/pyproject.toml b/sdk/python/examples/controls/dismissible/dismissible_list_tiles/pyproject.toml new file mode 100644 index 0000000000..1f6138ddd9 --- /dev/null +++ b/sdk/python/examples/controls/dismissible/dismissible_list_tiles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dismissible-list-tiles" +version = "1.0.0" +description = "Demonstrates dismissible ListTile items with per-direction backgrounds and confirm-dismiss dialog." +requires-python = ">=3.10" +keywords = ["dismissible", "list", "swipe", "confirmation", "dialog"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Dismissible"] + +[tool.flet.metadata] +title = "Dismissible ListTiles" +controls = ["SafeArea", "ListView", "Dismissible", "ListTile", "AlertDialog", "TextButton", "Container", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["swipe to dismiss", "confirm dismiss callback", "dismiss progress callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative.py b/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative.py deleted file mode 100644 index 812124f30e..0000000000 --- a/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative.py +++ /dev/null @@ -1,29 +0,0 @@ -import flet as ft - - -@ft.component -def App(): - items, set_items = ft.use_state(list(range(5))) - - return ft.ListView( - controls=[ - ft.Dismissible( - key=i, - content=ft.ListTile(title=ft.Text(f"Item {i}")), - dismiss_direction=ft.DismissDirection.HORIZONTAL, - background=ft.Container(bgcolor=ft.Colors.GREEN), - secondary_background=ft.Container(bgcolor=ft.Colors.RED), - on_dismiss=lambda e, index=i: set_items( - [item for item in items if item != index] - ), - dismiss_thresholds={ - ft.DismissDirection.HORIZONTAL: 0.1, - ft.DismissDirection.START_TO_END: 0.1, - }, - ) - for i in items - ], - ) - - -ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative/main.py b/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative/main.py new file mode 100644 index 0000000000..809c235a3d --- /dev/null +++ b/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +@ft.component +def App(): + items, set_items = ft.use_state(list(range(5))) + + return ft.SafeArea( + content=ft.ListView( + controls=[ + ft.Dismissible( + key=i, + dismiss_direction=ft.DismissDirection.HORIZONTAL, + background=ft.Container(bgcolor=ft.Colors.GREEN), + secondary_background=ft.Container(bgcolor=ft.Colors.RED), + on_dismiss=lambda _, index=i: set_items( + [item for item in items if item != index] + ), + dismiss_thresholds={ + ft.DismissDirection.HORIZONTAL: 0.1, + ft.DismissDirection.START_TO_END: 0.1, + }, + content=ft.ListTile(title=ft.Text(f"Item {i}")), + ) + for i in items + ], + ), + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative/pyproject.toml b/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative/pyproject.toml new file mode 100644 index 0000000000..a4f3eebd5b --- /dev/null +++ b/sdk/python/examples/controls/dismissible/remove_on_dismiss_declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dismissible-remove-on-dismiss-declarative" +version = "1.0.0" +description = "Shows declarative Dismissible list updates by removing items from component state on dismiss." +requires-python = ">=3.10" +keywords = ["dismissible", "declarative", "component", "state", "list"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Dismissible"] + +[tool.flet.metadata] +title = "Remove on dismiss declarative" +controls = ["SafeArea", "ListView", "Dismissible", "ListTile"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["declarative state updates", "swipe to dismiss", "stable dismissible keys"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/divider/basic.py b/sdk/python/examples/controls/divider/basic.py deleted file mode 100644 index e910379cad..0000000000 --- a/sdk/python/examples/controls/divider/basic.py +++ /dev/null @@ -1,38 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Column( - spacing=0, - expand=True, - controls=[ - ft.Container( - expand=True, - bgcolor=ft.Colors.AMBER, - alignment=ft.Alignment.CENTER, - ), - ft.Divider(), - ft.Container( - expand=True, - bgcolor=ft.Colors.PINK, - alignment=ft.Alignment.CENTER, - ), - ft.Divider(height=1, color=ft.Colors.WHITE), - ft.Container( - expand=True, - bgcolor=ft.Colors.BLUE_300, - alignment=ft.Alignment.CENTER, - ), - ft.Divider(height=9, thickness=3), - ft.Container( - expand=True, - bgcolor=ft.Colors.DEEP_PURPLE_200, - alignment=ft.Alignment.CENTER, - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/divider/basic/main.py b/sdk/python/examples/controls/divider/basic/main.py new file mode 100644 index 0000000000..8821065032 --- /dev/null +++ b/sdk/python/examples/controls/divider/basic/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + spacing=0, + expand=True, + controls=[ + ft.Container( + expand=True, + bgcolor=ft.Colors.AMBER, + alignment=ft.Alignment.CENTER, + ), + ft.Divider(), + ft.Container( + expand=True, + bgcolor=ft.Colors.PINK, + alignment=ft.Alignment.CENTER, + ), + ft.Divider(height=1, color=ft.Colors.WHITE), + ft.Container( + expand=True, + bgcolor=ft.Colors.BLUE_300, + alignment=ft.Alignment.CENTER, + ), + ft.Divider(height=9, thickness=3), + ft.Container( + expand=True, + bgcolor=ft.Colors.DEEP_PURPLE_200, + alignment=ft.Alignment.CENTER, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/divider/basic/pyproject.toml b/sdk/python/examples/controls/divider/basic/pyproject.toml new file mode 100644 index 0000000000..91cdcc1a7d --- /dev/null +++ b/sdk/python/examples/controls/divider/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "divider-basic" +version = "1.0.0" +description = "Demonstrates Divider height, thickness, and color between vertically stacked containers." +requires-python = ">=3.10" +keywords = ["divider", "layout", "spacing", "separator"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Divider"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Container", "Divider"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom divider thickness", "custom divider color", "section separation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers/main.py b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers/main.py new file mode 100644 index 0000000000..f6d37f7ec6 --- /dev/null +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers/main.py @@ -0,0 +1,83 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_drag_will_accept(e: ft.DragWillAcceptEvent): + e.control.content.border = ft.Border.all( + 2, + ft.Colors.BLACK_45 if e.accept else ft.Colors.RED, + ) + e.control.update() + + def handle_drag_accept(e: ft.DragTargetEvent): + src = page.get_control(e.src_id) + e.control.content.bgcolor = src.content.bgcolor + e.control.content.border = None + e.control.update() + + def handle_drag_leave(e: ft.DragTargetLeaveEvent): + e.control.content.border = None + e.control.update() + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Column( + controls=[ + ft.Draggable( + group="color", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN, + border_radius=5, + ), + content_feedback=ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.CYAN, + border_radius=3, + ), + ), + ft.Draggable( + group="color", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.YELLOW, + border_radius=5, + ), + ), + ft.Draggable( + group="color", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.GREEN, + border_radius=5, + ), + ), + ], + ), + ft.Container(width=100), + ft.DragTarget( + group="color", + on_will_accept=handle_drag_will_accept, + on_accept=handle_drag_accept, + on_leave=handle_drag_leave, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.BLUE_GREY_100, + border_radius=5, + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers/pyproject.toml b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers/pyproject.toml new file mode 100644 index 0000000000..14cad26d66 --- /dev/null +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "drag-and-drop-containers" +version = "1.0.0" +description = "Implements imperative drag-and-drop between Draggable color chips and a DragTarget box." +requires-python = ">=3.10" +keywords = ["draggable", "drag target", "drag and drop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Draggable"] + +[tool.flet.metadata] +title = "Drag and drop containers" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["drag and drop", "drop acceptance feedback", "target color update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative.py b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative.py deleted file mode 100644 index 621c898ebc..0000000000 --- a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative.py +++ /dev/null @@ -1,89 +0,0 @@ -from dataclasses import dataclass - -import flet as ft - - -@dataclass -@ft.observable -class TargetState: - bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 - is_drag_over: bool = False - - -@ft.component -def App(): - target, _ = ft.use_state(lambda: TargetState()) - - def on_will_accept(e: ft.DragWillAcceptEvent): - target.is_drag_over = True - - def on_accept(e: ft.DragTargetEvent): - target.bgcolor = e.src.data - target.is_drag_over = False - - def on_leave(e: ft.DragTargetLeaveEvent): - target.is_drag_over = False - - return ft.Row( - controls=[ - ft.Column( - controls=[ - ft.Draggable( - group="color", - data=ft.Colors.CYAN, - content=ft.Container( - width=50, - height=50, - bgcolor=ft.Colors.CYAN, - border_radius=5, - ), - content_feedback=ft.Container( - width=20, - height=20, - bgcolor=ft.Colors.CYAN, - border_radius=3, - ), - ), - ft.Draggable( - group="color", - data=ft.Colors.YELLOW, - content=ft.Container( - width=50, - height=50, - bgcolor=ft.Colors.YELLOW, - border_radius=5, - ), - ), - ft.Draggable( - group="color", - data=ft.Colors.GREEN, - content=ft.Container( - width=50, - height=50, - bgcolor=ft.Colors.GREEN, - border_radius=5, - ), - ), - ] - ), - ft.Container(width=100), - ft.DragTarget( - group="color", - on_will_accept=on_will_accept, - on_accept=on_accept, - on_leave=on_leave, - content=ft.Container( - width=50, - height=50, - bgcolor=target.bgcolor, - border=ft.Border.all(2, ft.Colors.BLACK_45) - if target.is_drag_over - else None, - border_radius=5, - ), - ), - ] - ) - - -ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers.py b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative/main.py similarity index 60% rename from sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers.py rename to sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative/main.py index 677d2c21de..d3be31fe82 100644 --- a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers.py +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative/main.py @@ -1,30 +1,37 @@ +from dataclasses import dataclass + import flet as ft -def main(page: ft.Page): - def handle_drag_will_accept(e: ft.DragWillAcceptEvent): - e.control.content.border = ft.Border.all( - 2, ft.Colors.BLACK_45 if e.accept else ft.Colors.RED - ) - e.control.update() +@dataclass +@ft.observable +class TargetState: + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + is_drag_over: bool = False + + +@ft.component +def App(): + target, _ = ft.use_state(lambda: TargetState()) + + def on_will_accept(_: ft.DragWillAcceptEvent): + target.is_drag_over = True - def handle_drag_accept(e: ft.DragTargetEvent): - src = page.get_control(e.src_id) - e.control.content.bgcolor = src.content.bgcolor - e.control.content.border = None - e.control.update() + def on_accept(e: ft.DragTargetEvent): + target.bgcolor = e.src.data + target.is_drag_over = False - def handle_drag_leave(e: ft.DragTargetLeaveEvent): - e.control.content.border = None - e.control.update() + def on_leave(_: ft.DragTargetLeaveEvent): + target.is_drag_over = False - page.add( - ft.Row( + return ft.SafeArea( + content=ft.Row( controls=[ ft.Column( controls=[ ft.Draggable( group="color", + data=ft.Colors.CYAN, content=ft.Container( width=50, height=50, @@ -40,6 +47,7 @@ def handle_drag_leave(e: ft.DragTargetLeaveEvent): ), ft.Draggable( group="color", + data=ft.Colors.YELLOW, content=ft.Container( width=50, height=50, @@ -49,6 +57,7 @@ def handle_drag_leave(e: ft.DragTargetLeaveEvent): ), ft.Draggable( group="color", + data=ft.Colors.GREEN, content=ft.Container( width=50, height=50, @@ -56,24 +65,34 @@ def handle_drag_leave(e: ft.DragTargetLeaveEvent): border_radius=5, ), ), - ] + ], ), ft.Container(width=100), ft.DragTarget( group="color", - on_will_accept=handle_drag_will_accept, - on_accept=handle_drag_accept, - on_leave=handle_drag_leave, + on_will_accept=on_will_accept, + on_accept=on_accept, + on_leave=on_leave, content=ft.Container( width=50, height=50, - bgcolor=ft.Colors.BLUE_GREY_100, + bgcolor=target.bgcolor, + border=( + ft.Border.all(2, ft.Colors.BLACK_45) + if target.is_drag_over + else None + ), border_radius=5, ), ), - ] - ) + ], + ), ) -ft.run(main) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative/pyproject.toml b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative/pyproject.toml new file mode 100644 index 0000000000..be5ff96a5a --- /dev/null +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "drag-and-drop-containers-declarative" +version = "1.0.0" +description = "Builds declarative drag-and-drop containers with observable target state and hover feedback." +requires-python = ">=3.10" +keywords = ["draggable", "drag target", "drag and drop", "declarative", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Draggable"] + +[tool.flet.metadata] +title = "Drag and drop containers declarative" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["declarative state", "drag and drop", "hover border feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative/main.py similarity index 89% rename from sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py rename to sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative/main.py index 04a1b4cf30..4c0051dec8 100644 --- a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative/main.py @@ -84,7 +84,7 @@ def on_accept(e: ft.DragTargetEvent): e.accept and e.src.data != item ), on_accept=on_accept, - on_leave=lambda: set_is_item_over(False), + on_leave=lambda _: set_is_item_over(False), content=ft.Card( content=ft.Container( padding=7, @@ -118,7 +118,7 @@ def on_group_accept(e: ft.DragTargetEvent): move_group(e.src.data, group) set_is_group_over(False) - def on_add_item(self): + def on_add_item(_: ft.Event[ft.TextButton] | None = None): if stripped_text := new_item_text.strip(): group.add_item(stripped_text) set_new_item_text("") @@ -144,7 +144,7 @@ def on_add_item(self): data=group, on_will_accept=lambda e: set_is_item_over(e.accept), on_accept=on_item_accept, - on_leave=lambda: set_is_item_over(False), + on_leave=lambda _: set_is_item_over(False), content=ft.DragTarget( group="groups", data=group, @@ -152,11 +152,13 @@ def on_add_item(self): e.accept and e.src.data != group ), on_accept=on_group_accept, - on_leave=lambda: set_is_group_over(False), + on_leave=lambda _: set_is_group_over(False), content=ft.Container( - border=ft.Border.all(2, ft.Colors.BLACK12) - if not is_group_over - else ft.Border.all(2, ft.Colors.BLACK38), + border=( + ft.Border.all(2, ft.Colors.BLACK12) + if not is_group_over + else ft.Border.all(2, ft.Colors.BLACK38) + ), border_radius=ft.BorderRadius.all(15), bgcolor=group.color, padding=ft.Padding.all(20), @@ -178,9 +180,9 @@ def on_add_item(self): on_submit=on_add_item, ), ft.TextButton( - content="Add", icon=ft.Icons.ADD, on_click=on_add_item, + content="Add", ), ft.Column( spacing=2, @@ -221,16 +223,12 @@ def App(): group_3 = Group(title="Group 3", color=ft.Colors.CYAN_400) group_3.add_item("Item 4") - # group_4 = Group(title="Group 4", color=ft.Colors.GREEN_400) - # group_4.add_item("Item 5") - app, _ = ft.use_state( lambda: AppState( groups=[ group_1, group_2, group_3, - # group_4, ] ) ) @@ -240,14 +238,21 @@ def on_mounted(): ft.on_mounted(on_mounted) - return ft.Row( - spacing=4, - vertical_alignment=ft.CrossAxisAlignment.START, - controls=[ - GroupView(group, move_group=app.move_group, key=group.title) - for group in app.groups - ], + return ft.SafeArea( + content=ft.Row( + spacing=4, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + GroupView(group, move_group=app.move_group, key=group.title) + for group in app.groups + ], + ), ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative/pyproject.toml b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative/pyproject.toml new file mode 100644 index 0000000000..30778e4be1 --- /dev/null +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "drag-and-drop-ordering-declarative" +version = "1.0.0" +description = "Provides declarative drag-and-drop ordering across groups with nested DragTarget and Draggable controls." +requires-python = ">=3.10" +keywords = ["draggable", "drag target", "ordering", "declarative", "kanban"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Draggable"] + +[tool.flet.metadata] +title = "Drag and drop ordering declarative" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "Card", "TextField", "TextButton", "Divider", "VerticalDivider"] +layout_pattern = "dashboard" +complexity = "intermediate" +features = ["group reordering", "item reordering", "nested drag targets", "declarative state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/datepicker.md b/sdk/python/packages/flet/docs/controls/datepicker.md index f07c9a9942..e88d92602d 100644 --- a/sdk/python/packages/flet/docs/controls/datepicker.md +++ b/sdk/python/packages/flet/docs/controls/datepicker.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/date_picker/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/daterangepicker.md b/sdk/python/packages/flet/docs/controls/daterangepicker.md index ee818c04d2..629da71088 100644 --- a/sdk/python/packages/flet/docs/controls/daterangepicker.md +++ b/sdk/python/packages/flet/docs/controls/daterangepicker.md @@ -13,7 +13,7 @@ example_images: ../test-images/controls/material/golden/macos/date_range_picker ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="60%") }} diff --git a/sdk/python/packages/flet/docs/controls/dismissible.md b/sdk/python/packages/flet/docs/controls/dismissible.md index 4fd4d88576..ac57631e88 100644 --- a/sdk/python/packages/flet/docs/controls/dismissible.md +++ b/sdk/python/packages/flet/docs/controls/dismissible.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/dismissible/media ### Dismissible `ListTile`s ```python ---8<-- "{{ examples }}/dismissible_list_tiles.py" +--8<-- "{{ examples }}/dismissible_list_tiles/main.py" ``` {{ image(example_images + "/dismissible_list_tiles.gif", alt="dismissible-list-tiles", width="80%") }} @@ -42,7 +42,7 @@ On Flutter’s side, though, the already-dismissed `Dismissible` widget in the m Example: ```python ---8<-- "{{ examples }}/remove_on_dismiss_declarative.py" +--8<-- "{{ examples }}/remove_on_dismiss_declarative/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/divider.md b/sdk/python/packages/flet/docs/controls/divider.md index a14d51c6c1..9dc9387081 100644 --- a/sdk/python/packages/flet/docs/controls/divider.md +++ b/sdk/python/packages/flet/docs/controls/divider.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/divider/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/draggable.md b/sdk/python/packages/flet/docs/controls/draggable.md index 0b7f12f81f..d71049f1f8 100644 --- a/sdk/python/packages/flet/docs/controls/draggable.md +++ b/sdk/python/packages/flet/docs/controls/draggable.md @@ -15,13 +15,13 @@ example_images: ../examples/controls/drag_target_and_draggable/media #### Imperative ```python ---8<-- "{{ examples }}/drag_and_drop_containers.py" +--8<-- "{{ examples }}/drag_and_drop_containers/main.py" ``` #### Declarative ```python ---8<-- "{{ examples }}/drag_and_drop_containers_declarative.py" +--8<-- "{{ examples }}/drag_and_drop_containers_declarative/main.py" ``` {{ image(example_images + "/drag_and_drop_containers.gif", alt="drag-and-drop-containers", width="80%") }} From e0cbc531f48c00cbb34b1f52b33c41ecbad26201 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 09:00:43 -0700 Subject: [PATCH 47/96] Restructure dropdown examples into main.py Move and standardize dropdown and dropdown_m2 example scripts into main.py entrypoints, add pyproject.toml metadata for each example, and remove the old flat example files. Wrap example UIs with SafeArea/Column where appropriate, add type hints and more explicit event typing, and replace direct ft.run calls with a guarded main() + if __name__ == "__main__" launch. Update docs to point to the new example paths. These changes standardize example layout, provide per-example package metadata, and keep examples consistent for gallery/build tooling. --- .../main.py} | 18 +-- .../pyproject.toml | 26 ++++ .../{declarative.py => declarative/main.py} | 17 ++- .../dropdown/declarative/pyproject.toml | 26 ++++ .../main.py} | 21 +-- .../dropdown/icon_selection/pyproject.toml | 26 ++++ .../dropdown/select_and_change_events.py | 50 ------- .../dropdown/select_and_change_events/main.py | 57 ++++++++ .../select_and_change_events/pyproject.toml | 26 ++++ .../examples/controls/dropdown/styled.py | 126 ----------------- .../examples/controls/dropdown/styled/main.py | 128 ++++++++++++++++++ .../controls/dropdown/styled/pyproject.toml | 26 ++++ .../dropdown_m2/add_and_delete_options.py | 40 ------ .../add_and_delete_options/main.py | 50 +++++++ .../add_and_delete_options/pyproject.toml | 26 ++++ .../examples/controls/dropdown_m2/basic.py | 26 ---- .../controls/dropdown_m2/basic/main.py | 34 +++++ .../controls/dropdown_m2/basic/pyproject.toml | 26 ++++ .../dropdown_m2/dropdown_random_icon.py | 32 ----- .../dropdown_m2/dropdown_random_icon/main.py | 44 ++++++ .../dropdown_random_icon/pyproject.toml | 26 ++++ .../controls/dropdown_m2/handling_events.py | 24 ---- .../dropdown_m2/handling_events/main.py | 32 +++++ .../handling_events/pyproject.toml | 26 ++++ .../controls/dropdown_m2/label_and_hint.py | 20 --- .../dropdown_m2/label_and_hint/main.py | 23 ++++ .../dropdown_m2/label_and_hint/pyproject.toml | 26 ++++ .../docs/controls/cupertinobottomsheet.md | 2 +- .../flet/docs/controls/dropdown/index.md | 6 +- .../packages/flet/docs/controls/dropdownm2.md | 8 +- 30 files changed, 669 insertions(+), 349 deletions(-) rename sdk/python/examples/controls/dropdown/{color_selection_with_filtering.py => color_selection_with_filtering/main.py} (65%) create mode 100644 sdk/python/examples/controls/dropdown/color_selection_with_filtering/pyproject.toml rename sdk/python/examples/controls/dropdown/{declarative.py => declarative/main.py} (84%) create mode 100644 sdk/python/examples/controls/dropdown/declarative/pyproject.toml rename sdk/python/examples/controls/dropdown/{icon_selection.py => icon_selection/main.py} (56%) create mode 100644 sdk/python/examples/controls/dropdown/icon_selection/pyproject.toml delete mode 100644 sdk/python/examples/controls/dropdown/select_and_change_events.py create mode 100644 sdk/python/examples/controls/dropdown/select_and_change_events/main.py create mode 100644 sdk/python/examples/controls/dropdown/select_and_change_events/pyproject.toml delete mode 100644 sdk/python/examples/controls/dropdown/styled.py create mode 100644 sdk/python/examples/controls/dropdown/styled/main.py create mode 100644 sdk/python/examples/controls/dropdown/styled/pyproject.toml delete mode 100644 sdk/python/examples/controls/dropdown_m2/add_and_delete_options.py create mode 100644 sdk/python/examples/controls/dropdown_m2/add_and_delete_options/main.py create mode 100644 sdk/python/examples/controls/dropdown_m2/add_and_delete_options/pyproject.toml delete mode 100644 sdk/python/examples/controls/dropdown_m2/basic.py create mode 100644 sdk/python/examples/controls/dropdown_m2/basic/main.py create mode 100644 sdk/python/examples/controls/dropdown_m2/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/dropdown_m2/dropdown_random_icon.py create mode 100644 sdk/python/examples/controls/dropdown_m2/dropdown_random_icon/main.py create mode 100644 sdk/python/examples/controls/dropdown_m2/dropdown_random_icon/pyproject.toml delete mode 100644 sdk/python/examples/controls/dropdown_m2/handling_events.py create mode 100644 sdk/python/examples/controls/dropdown_m2/handling_events/main.py create mode 100644 sdk/python/examples/controls/dropdown_m2/handling_events/pyproject.toml delete mode 100644 sdk/python/examples/controls/dropdown_m2/label_and_hint.py create mode 100644 sdk/python/examples/controls/dropdown_m2/label_and_hint/main.py create mode 100644 sdk/python/examples/controls/dropdown_m2/label_and_hint/pyproject.toml diff --git a/sdk/python/examples/controls/dropdown/color_selection_with_filtering.py b/sdk/python/examples/controls/dropdown/color_selection_with_filtering/main.py similarity index 65% rename from sdk/python/examples/controls/dropdown/color_selection_with_filtering.py rename to sdk/python/examples/controls/dropdown/color_selection_with_filtering/main.py index 2237b662f9..516baee2c7 100644 --- a/sdk/python/examples/controls/dropdown/color_selection_with_filtering.py +++ b/sdk/python/examples/controls/dropdown/color_selection_with_filtering/main.py @@ -4,7 +4,7 @@ def main(page: ft.Page): page.theme_mode = ft.ThemeMode.LIGHT - def get_options(): + def get_options() -> list[ft.DropdownOption]: colors = [ ft.Colors.RED, ft.Colors.BLUE, @@ -22,16 +22,18 @@ def get_options(): def handle_dropdown_select(e: ft.Event[ft.Dropdown]): e.control.color = e.control.value - page.update() page.add( - ft.Dropdown( - editable=True, - label="Color", - options=get_options(), - on_select=handle_dropdown_select, + ft.SafeArea( + content=ft.Dropdown( + editable=True, + label="Color", + options=get_options(), + on_select=handle_dropdown_select, + ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown/color_selection_with_filtering/pyproject.toml b/sdk/python/examples/controls/dropdown/color_selection_with_filtering/pyproject.toml new file mode 100644 index 0000000000..0d65fd09f6 --- /dev/null +++ b/sdk/python/examples/controls/dropdown/color_selection_with_filtering/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-color-selection-with-filtering" +version = "1.0.0" +description = "Filters editable dropdown options by color and applies selected color to the control text." +requires-python = ">=3.10" +keywords = ["dropdown", "filter", "editable", "selection", "color"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Color selection with filtering" +controls = ["SafeArea", "Dropdown", "DropdownOption", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["editable dropdown", "option filtering", "selection callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown/declarative.py b/sdk/python/examples/controls/dropdown/declarative/main.py similarity index 84% rename from sdk/python/examples/controls/dropdown/declarative.py rename to sdk/python/examples/controls/dropdown/declarative/main.py index 74c427414b..30a4ec4e74 100644 --- a/sdk/python/examples/controls/dropdown/declarative.py +++ b/sdk/python/examples/controls/dropdown/declarative/main.py @@ -19,13 +19,13 @@ def App(): form, _ = ft.use_state(lambda: Form()) return ft.SafeArea( - ft.Column( - cast( + content=ft.Column( + controls=cast( list[ft.Control], [ ft.Text(f"Selected color: {form.color}"), ft.Column( - [ + controls=[ ft.Dropdown( editable=True, label="Color", @@ -39,12 +39,17 @@ def App(): ft.DropdownOption(key="blue", text="Blue"), ], ), - ] + ], ), ], - ) + ), ), ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown/declarative/pyproject.toml b/sdk/python/examples/controls/dropdown/declarative/pyproject.toml new file mode 100644 index 0000000000..491b746bca --- /dev/null +++ b/sdk/python/examples/controls/dropdown/declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-declarative" +version = "1.0.0" +description = "Uses a declarative component and observable state to keep Dropdown selection synchronized." +requires-python = ">=3.10" +keywords = ["dropdown", "declarative", "component", "state", "observable"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Declarative" +controls = ["SafeArea", "Column", "Dropdown", "DropdownOption", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["declarative state", "selection binding", "component rendering"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown/icon_selection.py b/sdk/python/examples/controls/dropdown/icon_selection/main.py similarity index 56% rename from sdk/python/examples/controls/dropdown/icon_selection.py rename to sdk/python/examples/controls/dropdown/icon_selection/main.py index 5b9ff25abf..ec32ac8b3f 100644 --- a/sdk/python/examples/controls/dropdown/icon_selection.py +++ b/sdk/python/examples/controls/dropdown/icon_selection/main.py @@ -2,7 +2,7 @@ def main(page: ft.Page): - def get_options(): + def get_options() -> list[ft.DropdownOption]: icons = [ {"name": "Smile", "icon": ft.Icons.SENTIMENT_SATISFIED_OUTLINED}, {"name": "Cloud", "icon": ft.Icons.CLOUD_OUTLINED}, @@ -15,15 +15,18 @@ def get_options(): ] page.add( - ft.Dropdown( - border=ft.InputBorder.UNDERLINE, - enable_filter=True, - editable=True, - leading_icon=ft.Icons.SEARCH, - label="Icon", - options=get_options(), + ft.SafeArea( + content=ft.Dropdown( + border=ft.InputBorder.UNDERLINE, + enable_filter=True, + editable=True, + leading_icon=ft.Icons.SEARCH, + label="Icon", + options=get_options(), + ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown/icon_selection/pyproject.toml b/sdk/python/examples/controls/dropdown/icon_selection/pyproject.toml new file mode 100644 index 0000000000..a956da14f8 --- /dev/null +++ b/sdk/python/examples/controls/dropdown/icon_selection/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-icon-selection" +version = "1.0.0" +description = "Displays dropdown options with leading icons and interactive text filtering." +requires-python = ">=3.10" +keywords = ["dropdown", "icons", "filter", "editable", "search"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Icon selection" +controls = ["SafeArea", "Dropdown", "DropdownOption"] +layout_pattern = "form" +complexity = "basic" +features = ["leading icons", "editable dropdown", "option filtering"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown/select_and_change_events.py b/sdk/python/examples/controls/dropdown/select_and_change_events.py deleted file mode 100644 index f3591aced4..0000000000 --- a/sdk/python/examples/controls/dropdown/select_and_change_events.py +++ /dev/null @@ -1,50 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - colors = [ - ft.Colors.RED, - ft.Colors.BLUE, - ft.Colors.YELLOW, - ft.Colors.PURPLE, - ft.Colors.LIME, - ] - - def get_options(): - options = [] - for color in colors: - options.append( - ft.DropdownOption( - key=color.value, - content=ft.Text( - value=color.value, - color=color, - ), - leading_icon=ft.Icon(ft.Icons.PALETTE, color=color), - ) - ) - return options - - def dropdown_select(e): - e.control.color = e.control.value - display_value.value = f"VALUE changed to {e.control.value}" - - def dropdown_text_change(e): - display_text.value = f"TEXT changed to {e.control.text}" - - page.scroll = ft.ScrollMode.AUTO - page.add( - display_value := ft.Text(), - display_text := ft.Text(), - ft.Dropdown( - editable=True, - label="Color", - width=float("inf"), - options=get_options(), - on_select=dropdown_select, - on_text_change=dropdown_text_change, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/dropdown/select_and_change_events/main.py b/sdk/python/examples/controls/dropdown/select_and_change_events/main.py new file mode 100644 index 0000000000..1c4b55908d --- /dev/null +++ b/sdk/python/examples/controls/dropdown/select_and_change_events/main.py @@ -0,0 +1,57 @@ +import flet as ft + + +def main(page: ft.Page): + colors = [ + ft.Colors.RED, + ft.Colors.BLUE, + ft.Colors.YELLOW, + ft.Colors.PURPLE, + ft.Colors.LIME, + ] + + def get_options() -> list[ft.DropdownOption]: + options: list[ft.DropdownOption] = [] + for color in colors: + options.append( + ft.DropdownOption( + key=color.value, + content=ft.Text(value=color.value, color=color), + leading_icon=ft.Icon(ft.Icons.PALETTE, color=color), + ) + ) + return options + + display_value = ft.Text() + display_text = ft.Text() + + def dropdown_select(e: ft.Event[ft.Dropdown]): + e.control.color = e.control.value + display_value.value = f"VALUE changed to {e.control.value}" + + def dropdown_text_change(e: ft.Event[ft.Dropdown]): + display_text.value = f"TEXT changed to {e.control.text}" + + page.scroll = ft.ScrollMode.AUTO + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + display_value, + display_text, + ft.Dropdown( + editable=True, + label="Color", + width=float("inf"), + options=get_options(), + on_select=dropdown_select, + on_text_change=dropdown_text_change, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown/select_and_change_events/pyproject.toml b/sdk/python/examples/controls/dropdown/select_and_change_events/pyproject.toml new file mode 100644 index 0000000000..ecbb6b06ec --- /dev/null +++ b/sdk/python/examples/controls/dropdown/select_and_change_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-select-and-change-events" +version = "1.0.0" +description = "Handles dropdown select and text-change events while showing selected value and typed text." +requires-python = ">=3.10" +keywords = ["dropdown", "events", "on_select", "on_text_change", "editable"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Select and change events" +controls = ["SafeArea", "Column", "Dropdown", "DropdownOption", "Icon", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["select callback", "text change callback", "live value labels"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown/styled.py b/sdk/python/examples/controls/dropdown/styled.py deleted file mode 100644 index 14f354fa52..0000000000 --- a/sdk/python/examples/controls/dropdown/styled.py +++ /dev/null @@ -1,126 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - # 1 - ft.Dropdown( - text_size=20, - content_padding=10, - color=ft.Colors.PURPLE_200, - bgcolor=ft.Colors.BLUE_200, - filled=True, - border_radius=30, - border_color=ft.Colors.GREEN_800, - focused_border_color=ft.Colors.GREEN_ACCENT_400, - focused_border_width=5, - options=[ - ft.DropdownOption("a", "Item A"), - ft.DropdownOption("b", "Item B"), - ft.DropdownOption("c", "Item C"), - ], - ), - # 2 - ft.Dropdown( - border_radius=30, - filled=True, - fill_color=ft.Colors.RED_400, - border_color=ft.Colors.TRANSPARENT, - bgcolor=ft.Colors.RED_200, - color=ft.Colors.CYAN_400, - focused_border_color=ft.Colors.PINK_300, - focused_border_width=20, - options=[ - ft.DropdownOption("a", "Item A"), - ft.DropdownOption("b", "Item B"), - ft.DropdownOption("c", "Item C"), - ], - ), - # 3 - ft.Dropdown( - border_color=ft.Colors.PINK_ACCENT, - focused_border_color=ft.Colors.GREEN_ACCENT_400, - focused_border_width=25, - border_radius=30, - width=150, - border_width=5, - options=[ - ft.DropdownOption("a", "Item A"), - ft.DropdownOption("b", "Item B"), - ft.DropdownOption("c", "Item C"), - ], - ), - # 4 - ft.Container( - padding=ft.Padding.only(bottom=20), - content=ft.Dropdown( - text_size=30, - color=ft.Colors.ORANGE_ACCENT, - border_radius=20, - filled=True, - border_width=0, - autofocus=True, - focused_border_color=ft.Colors.GREEN_100, - focused_border_width=10, - width=200, - height=50, - options=[ - ft.dropdown.Option("a", "Item A"), - ft.dropdown.Option("b", "Item B"), - ft.dropdown.Option("c", "Item C"), - ], - ), - ), - # 5 - ft.Dropdown( - text_size=30, - border_radius=20, - filled=True, - border_width=0, - focused_border_color=ft.Colors.GREEN_100, - focused_border_width=10, - content_padding=20, - width=200, - options=[ - ft.DropdownOption( - key="a", - text="Item A", - style=ft.ButtonStyle( - shape=ft.BeveledRectangleBorder(radius=15), - color={ - ft.ControlState.HOVERED: ft.Colors.WHITE, - ft.ControlState.FOCUSED: ft.Colors.BLUE, - ft.ControlState.DEFAULT: ft.Colors.BLACK, - }, - ), - ), - ft.DropdownOption( - key="b", - text="Item B", - style=ft.ButtonStyle( - shape=ft.BeveledRectangleBorder(radius=15), - color={ - ft.ControlState.HOVERED: ft.Colors.WHITE, - ft.ControlState.FOCUSED: ft.Colors.BLUE, - ft.ControlState.DEFAULT: ft.Colors.BLACK, - }, - ), - ), - ft.DropdownOption( - key="c", - text="Item C", - style=ft.ButtonStyle( - shape=ft.BeveledRectangleBorder(radius=15), - color={ - ft.ControlState.HOVERED: ft.Colors.WHITE, - ft.ControlState.FOCUSED: ft.Colors.BLUE, - ft.ControlState.DEFAULT: ft.Colors.BLACK, - }, - ), - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/dropdown/styled/main.py b/sdk/python/examples/controls/dropdown/styled/main.py new file mode 100644 index 0000000000..4427a84169 --- /dev/null +++ b/sdk/python/examples/controls/dropdown/styled/main.py @@ -0,0 +1,128 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Dropdown( + text_size=20, + content_padding=10, + color=ft.Colors.PURPLE_200, + bgcolor=ft.Colors.BLUE_200, + filled=True, + border_radius=30, + border_color=ft.Colors.GREEN_800, + focused_border_color=ft.Colors.GREEN_ACCENT_400, + focused_border_width=5, + options=[ + ft.DropdownOption("a", "Item A"), + ft.DropdownOption("b", "Item B"), + ft.DropdownOption("c", "Item C"), + ], + ), + ft.Dropdown( + border_radius=30, + filled=True, + fill_color=ft.Colors.RED_400, + border_color=ft.Colors.TRANSPARENT, + bgcolor=ft.Colors.RED_200, + color=ft.Colors.CYAN_400, + focused_border_color=ft.Colors.PINK_300, + focused_border_width=20, + options=[ + ft.DropdownOption("a", "Item A"), + ft.DropdownOption("b", "Item B"), + ft.DropdownOption("c", "Item C"), + ], + ), + ft.Dropdown( + border_color=ft.Colors.PINK_ACCENT, + focused_border_color=ft.Colors.GREEN_ACCENT_400, + focused_border_width=25, + border_radius=30, + width=150, + border_width=5, + options=[ + ft.DropdownOption("a", "Item A"), + ft.DropdownOption("b", "Item B"), + ft.DropdownOption("c", "Item C"), + ], + ), + ft.Container( + padding=ft.Padding.only(bottom=20), + content=ft.Dropdown( + text_size=30, + color=ft.Colors.ORANGE_ACCENT, + border_radius=20, + filled=True, + border_width=0, + autofocus=True, + focused_border_color=ft.Colors.GREEN_100, + focused_border_width=10, + width=200, + height=50, + options=[ + ft.dropdown.Option("a", "Item A"), + ft.dropdown.Option("b", "Item B"), + ft.dropdown.Option("c", "Item C"), + ], + ), + ), + ft.Dropdown( + text_size=30, + border_radius=20, + filled=True, + border_width=0, + focused_border_color=ft.Colors.GREEN_100, + focused_border_width=10, + content_padding=20, + width=200, + options=[ + ft.DropdownOption( + key="a", + text="Item A", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=15), + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + ), + ), + ft.DropdownOption( + key="b", + text="Item B", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=15), + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + ), + ), + ft.DropdownOption( + key="c", + text="Item C", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=15), + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + ), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown/styled/pyproject.toml b/sdk/python/examples/controls/dropdown/styled/pyproject.toml new file mode 100644 index 0000000000..dce56d324e --- /dev/null +++ b/sdk/python/examples/controls/dropdown/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-styled" +version = "1.0.0" +description = "Showcases multiple Dropdown visual styles including borders, fills, and per-option button styles." +requires-python = ">=3.10" +keywords = ["dropdown", "styling", "theming", "options", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Styled" +controls = ["SafeArea", "Column", "Container", "Dropdown", "DropdownOption", "ButtonStyle"] +layout_pattern = "form" +complexity = "basic" +features = ["custom borders", "filled styles", "option style customization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown_m2/add_and_delete_options.py b/sdk/python/examples/controls/dropdown_m2/add_and_delete_options.py deleted file mode 100644 index 44781cd8ab..0000000000 --- a/sdk/python/examples/controls/dropdown_m2/add_and_delete_options.py +++ /dev/null @@ -1,40 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def find_option(option_name): - for option in dropdown.options: - if option_name == option.key: - return option - return None - - def handle_addition(e: ft.Event[ft.Button]): - dropdown.options.append(ft.dropdownm2.Option(input_field.value)) - dropdown.value = input_field.value - input_field.value = "" - page.update() - - def handle_deletion(e: ft.Event[ft.OutlinedButton]): - option = find_option(dropdown.value) - if option is not None: - dropdown.options.remove(option) - # d.value = None - page.update() - - page.add( - dropdown := ft.DropdownM2(options=[], color=ft.Colors.BLUE_400), - ft.Row( - controls=[ - input_field := ft.TextField(hint_text="Enter item name"), - ft.Button(content="Add", on_click=handle_addition), - ft.OutlinedButton( - content="Delete selected", - on_click=handle_deletion, - style=ft.ButtonStyle(bgcolor=ft.Colors.RED), - ), - ] - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/add_and_delete_options/main.py b/sdk/python/examples/controls/dropdown_m2/add_and_delete_options/main.py new file mode 100644 index 0000000000..552f45e500 --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/add_and_delete_options/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + dropdown = ft.DropdownM2(options=[], color=ft.Colors.BLUE_400) + input_field = ft.TextField(hint_text="Enter item name") + + def find_option(option_name: str): + for option in dropdown.options: + if option_name == option.key: + return option + return None + + def handle_addition(_: ft.Event[ft.Button]): + dropdown.options.append(ft.dropdownm2.Option(input_field.value)) + dropdown.value = input_field.value + input_field.value = "" + dropdown.update() + input_field.update() + + def handle_deletion(_: ft.Event[ft.OutlinedButton]): + option = find_option(dropdown.value) + if option is not None: + dropdown.options.remove(option) + dropdown.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + dropdown, + ft.Row( + controls=[ + input_field, + ft.Button(content="Add", on_click=handle_addition), + ft.OutlinedButton( + content="Delete selected", + on_click=handle_deletion, + style=ft.ButtonStyle(bgcolor=ft.Colors.RED), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/add_and_delete_options/pyproject.toml b/sdk/python/examples/controls/dropdown_m2/add_and_delete_options/pyproject.toml new file mode 100644 index 0000000000..25f4c60fda --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/add_and_delete_options/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-add-and-delete-options" +version = "1.0.0" +description = "Adds and removes DropdownM2 options dynamically based on text input and current selection." +requires-python = ">=3.10" +keywords = ["dropdownm2", "dynamic options", "add option", "delete option", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Add and delete options" +controls = ["SafeArea", "Column", "Row", "DropdownM2", "TextField", "Button", "OutlinedButton"] +layout_pattern = "form" +complexity = "basic" +features = ["dynamic option insertion", "delete selected option"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown_m2/basic.py b/sdk/python/examples/controls/dropdown_m2/basic.py deleted file mode 100644 index 02b94a10fc..0000000000 --- a/sdk/python/examples/controls/dropdown_m2/basic.py +++ /dev/null @@ -1,26 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - # page.theme_mode = ft.ThemeMode.DARK - - def handle_button_click(e): - message.value = f"Dropdown value is: {dd.value}" - page.update() - - page.add( - dd := ft.DropdownM2( - width=100, - value="Green", - options=[ - ft.dropdownm2.Option("Red"), - ft.dropdownm2.Option("Green"), - ft.dropdownm2.Option("Blue"), - ], - ), - ft.Button(content="Submit", on_click=handle_button_click), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/basic/main.py b/sdk/python/examples/controls/dropdown_m2/basic/main.py new file mode 100644 index 0000000000..4c305510e3 --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/basic/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + + dd = ft.DropdownM2( + width=100, + value="Green", + options=[ + ft.dropdownm2.Option("Red"), + ft.dropdownm2.Option("Green"), + ft.dropdownm2.Option("Blue"), + ], + ) + + def handle_button_click(_: ft.Event[ft.Button]): + message.value = f"Dropdown value is: {dd.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + dd, + ft.Button(content="Submit", on_click=handle_button_click), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/basic/pyproject.toml b/sdk/python/examples/controls/dropdown_m2/basic/pyproject.toml new file mode 100644 index 0000000000..616704dcd2 --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-basic" +version = "1.0.0" +description = "Submits selected DropdownM2 value and displays it in a message label." +requires-python = ">=3.10" +keywords = ["dropdownm2", "selection", "submit", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "DropdownM2", "Button", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["value selection", "submit callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon.py b/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon.py deleted file mode 100644 index 02c491b982..0000000000 --- a/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon.py +++ /dev/null @@ -1,32 +0,0 @@ -import random - -import flet as ft - - -def main(page: ft.Page): - def handle_dropdown_change(e: ft.Event[ft.DropdownM2]): - message.value = f"{e.control.value} chosen" - page.update() - - def handle_new_random_item(e: ft.Event[ft.Button]): - icon = ft.Icon(ft.Icons.random()) - dd.options.append( - ft.dropdownm2.Option(text=f"{str(icon.icon)[6:]}", content=icon) - ) - page.update() - - def handle_items_shuffle(e: ft.Event[ft.Button]): - random.shuffle(dd.options) - page.update() - - page.add( - dd := ft.DropdownM2( - options=[], options_fill_horizontally=True, on_change=handle_dropdown_change - ), - ft.Button("Add random Option", on_click=handle_new_random_item), - ft.Button("Shuffle Options", on_click=handle_items_shuffle), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon/main.py b/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon/main.py new file mode 100644 index 0000000000..672eae65a9 --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon/main.py @@ -0,0 +1,44 @@ +import random + +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + dd = ft.DropdownM2(options=[], options_fill_horizontally=True) + + def handle_dropdown_change(e: ft.Event[ft.DropdownM2]): + message.value = f"{e.control.value} chosen" + + def handle_new_random_item(_: ft.Event[ft.Button]): + icon = ft.Icon(ft.Icons.random()) + dd.options.append( + ft.dropdownm2.Option( + text=f"{str(icon.icon)[6:]}", + content=icon, + ) + ) + dd.update() + + def handle_items_shuffle(_: ft.Event[ft.Button]): + random.shuffle(dd.options) + dd.update() + + dd.on_change = handle_dropdown_change + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + dd, + ft.Button("Add random Option", on_click=handle_new_random_item), + ft.Button("Shuffle Options", on_click=handle_items_shuffle), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon/pyproject.toml b/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon/pyproject.toml new file mode 100644 index 0000000000..deb83af937 --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-dropdown-random-icon" +version = "1.0.0" +description = "Adds random icon options to DropdownM2 and supports shuffling option order interactively." +requires-python = ">=3.10" +keywords = ["dropdownm2", "icons", "dynamic options", "shuffle", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Dropdown random icon" +controls = ["SafeArea", "Column", "DropdownM2", "Button", "Icon", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["random option generation", "option shuffling", "selection callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown_m2/handling_events.py b/sdk/python/examples/controls/dropdown_m2/handling_events.py deleted file mode 100644 index ce8558af81..0000000000 --- a/sdk/python/examples/controls/dropdown_m2/handling_events.py +++ /dev/null @@ -1,24 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def dropdown_changed(e: ft.Event[ft.DropdownM2]): - message.value = f"Dropdown changed to {e.control.value}" - page.update() - - page.add( - ft.DropdownM2( - width=200, - color=ft.Colors.BLUE_GREY_700, - on_change=dropdown_changed, - options=[ - ft.dropdownm2.Option("Red"), - ft.dropdownm2.Option("Green"), - ft.dropdownm2.Option("Blue"), - ], - ), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/handling_events/main.py b/sdk/python/examples/controls/dropdown_m2/handling_events/main.py new file mode 100644 index 0000000000..411705aa8a --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/handling_events/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + + def dropdown_changed(e: ft.Event[ft.DropdownM2]): + message.value = f"Dropdown changed to {e.control.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.DropdownM2( + width=200, + color=ft.Colors.BLUE_GREY_700, + on_change=dropdown_changed, + options=[ + ft.dropdownm2.Option("Red"), + ft.dropdownm2.Option("Green"), + ft.dropdownm2.Option("Blue"), + ], + ), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/handling_events/pyproject.toml b/sdk/python/examples/controls/dropdown_m2/handling_events/pyproject.toml new file mode 100644 index 0000000000..7cb513559f --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-handling-events" +version = "1.0.0" +description = "Updates helper text when DropdownM2 selection changes via on_change event." +requires-python = ">=3.10" +keywords = ["dropdownm2", "events", "on_change", "selection", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "Column", "DropdownM2", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["on_change callback", "live message update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/dropdown_m2/label_and_hint.py b/sdk/python/examples/controls/dropdown_m2/label_and_hint.py deleted file mode 100644 index 6c75247f00..0000000000 --- a/sdk/python/examples/controls/dropdown_m2/label_and_hint.py +++ /dev/null @@ -1,20 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.DropdownM2( - label="Color", - hint_text="Choose your favourite color?", - autofocus=True, - color=ft.Colors.BLACK, - options=[ - ft.dropdownm2.Option("Red"), - ft.dropdownm2.Option("Green"), - ft.dropdownm2.Option("Blue"), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/label_and_hint/main.py b/sdk/python/examples/controls/dropdown_m2/label_and_hint/main.py new file mode 100644 index 0000000000..16f5a73680 --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/label_and_hint/main.py @@ -0,0 +1,23 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.DropdownM2( + label="Color", + hint_text="Choose your favourite color?", + autofocus=True, + color=ft.Colors.BLACK, + options=[ + ft.dropdownm2.Option("Red"), + ft.dropdownm2.Option("Green"), + ft.dropdownm2.Option("Blue"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/dropdown_m2/label_and_hint/pyproject.toml b/sdk/python/examples/controls/dropdown_m2/label_and_hint/pyproject.toml new file mode 100644 index 0000000000..41dca107a4 --- /dev/null +++ b/sdk/python/examples/controls/dropdown_m2/label_and_hint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-label-and-hint" +version = "1.0.0" +description = "Shows DropdownM2 with label, hint text, and autofocus configuration." +requires-python = ">=3.10" +keywords = ["dropdownm2", "label", "hint", "autofocus", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Dropdown with label and hint" +controls = ["SafeArea", "DropdownM2"] +layout_pattern = "form" +complexity = "basic" +features = ["label text", "hint text", "autofocus"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/cupertinobottomsheet.md b/sdk/python/packages/flet/docs/controls/cupertinobottomsheet.md index 4b9d7688c7..5e82474fd6 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinobottomsheet.md +++ b/sdk/python/packages/flet/docs/controls/cupertinobottomsheet.md @@ -13,7 +13,7 @@ example_images: ../examples/controls/cupertino_action_sheet/media ### Displaying a `CupertinoActionSheet` ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="cupertinoactionsheet", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/dropdown/index.md b/sdk/python/packages/flet/docs/controls/dropdown/index.md index e4f2ba9025..3d5e6904d7 100644 --- a/sdk/python/packages/flet/docs/controls/dropdown/index.md +++ b/sdk/python/packages/flet/docs/controls/dropdown/index.md @@ -16,7 +16,7 @@ example_media: ../../examples/controls/dropdown/media ### Color selection with filtering ```python ---8<-- "{{ examples }}/color_selection_with_filtering.py" +--8<-- "{{ examples }}/color_selection_with_filtering/main.py" ``` {{ image(example_media + "/color_selection_with_filtering.gif", alt="color-selection-with-filtering", width="80%") }} @@ -26,7 +26,7 @@ example_media: ../../examples/controls/dropdown/media ### Icon selection ```python ---8<-- "{{ examples }}/icon_selection.py" +--8<-- "{{ examples }}/icon_selection/main.py" ``` {{ image(example_media + "/icon_selection.png", alt="icon-selection", width="80%") }} @@ -35,7 +35,7 @@ example_media: ../../examples/controls/dropdown/media ### Styled dropdowns ```python ---8<-- "{{ examples }}/styled.py" +--8<-- "{{ examples }}/styled/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/dropdownm2.md b/sdk/python/packages/flet/docs/controls/dropdownm2.md index ce4315e4f0..b90b8c187e 100644 --- a/sdk/python/packages/flet/docs/controls/dropdownm2.md +++ b/sdk/python/packages/flet/docs/controls/dropdownm2.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/dropdown_m2/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/dropdown_m2/media ### Dropdown with label and hint ```python ---8<-- "{{ examples }}/label_and_hint.py" +--8<-- "{{ examples }}/label_and_hint/main.py" ``` {{ image(example_media + "/label_and_hint.gif", alt="label-and-hint", width="80%") }} @@ -32,7 +32,7 @@ example_media: ../examples/controls/dropdown_m2/media ### Handling events ```python ---8<-- "{{ examples }}/handling_events.py" +--8<-- "{{ examples }}/handling_events/main.py" ``` {{ image(example_media + "/handling_events.gif", alt="handling-events", width="80%") }} @@ -42,7 +42,7 @@ example_media: ../examples/controls/dropdown_m2/media ### Add and delete options ```python ---8<-- "{{ examples }}/add_and_delete_options.py" +--8<-- "{{ examples }}/add_and_delete_options/main.py" ``` {{ image(example_media + "/add_and_delete_options.gif", alt="add-and-delete-options", width="80%") }} From 4e89567e91c8ab0c3433091a3d3600ff6ae60a50 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 12:19:36 -0700 Subject: [PATCH 48/96] Restructure expansion examples into main.py files Move and reorganize ExpansionTile/ExpansionPanelList examples into per-example folders with main.py entrypoints and add pyproject.toml metadata for each example. Update example code to wrap content in SafeArea/Column, use control.update() where appropriate, simplify loops (enumerate), and add if __name__ == "__main__" guards. Remove old flat example files, update documentation include paths to point to the new ".../main.py" locations, update a test import to the new module path, and refresh the golden image for ExpansionTile. --- .../{basic.py => basic/main.py} | 15 ++- .../expansion_panel_list/basic/pyproject.toml | 26 +++++ .../controls/expansion_tile/__init__.py | 0 .../examples/controls/expansion_tile/basic.py | 72 ------------ .../controls/expansion_tile/basic/main.py | 79 ++++++++++++++ .../expansion_tile/basic/pyproject.toml | 26 +++++ .../controls/expansion_tile/borders.py | 45 -------- .../controls/expansion_tile/borders/main.py | 45 ++++++++ .../expansion_tile/borders/pyproject.toml | 26 +++++ .../expansion_tile/custom_animations.py | 45 -------- .../expansion_tile/custom_animations/main.py | 53 +++++++++ .../custom_animations/pyproject.toml | 26 +++++ .../expansion_tile/programmatic_expansion.py | 35 ------ .../programmatic_expansion/main.py | 43 ++++++++ .../programmatic_expansion/pyproject.toml | 26 +++++ .../expansion_tile/theme_mode_toggle.py | 94 ---------------- .../expansion_tile/theme_mode_toggle/main.py | 103 ++++++++++++++++++ .../theme_mode_toggle/pyproject.toml | 26 +++++ .../flet/docs/controls/expansionpanellist.md | 2 +- .../flet/docs/controls/expansiontile.md | 10 +- .../golden/macos/expansion_tile/basic.png | Bin 80865 -> 80621 bytes .../examples/material/test_expansion_tile.py | 2 +- 22 files changed, 495 insertions(+), 304 deletions(-) rename sdk/python/examples/controls/expansion_panel_list/{basic.py => basic/main.py} (87%) create mode 100644 sdk/python/examples/controls/expansion_panel_list/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/expansion_tile/__init__.py delete mode 100644 sdk/python/examples/controls/expansion_tile/basic.py create mode 100644 sdk/python/examples/controls/expansion_tile/basic/main.py create mode 100644 sdk/python/examples/controls/expansion_tile/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/expansion_tile/borders.py create mode 100644 sdk/python/examples/controls/expansion_tile/borders/main.py create mode 100644 sdk/python/examples/controls/expansion_tile/borders/pyproject.toml delete mode 100644 sdk/python/examples/controls/expansion_tile/custom_animations.py create mode 100644 sdk/python/examples/controls/expansion_tile/custom_animations/main.py create mode 100644 sdk/python/examples/controls/expansion_tile/custom_animations/pyproject.toml delete mode 100644 sdk/python/examples/controls/expansion_tile/programmatic_expansion.py create mode 100644 sdk/python/examples/controls/expansion_tile/programmatic_expansion/main.py create mode 100644 sdk/python/examples/controls/expansion_tile/programmatic_expansion/pyproject.toml delete mode 100644 sdk/python/examples/controls/expansion_tile/theme_mode_toggle.py create mode 100644 sdk/python/examples/controls/expansion_tile/theme_mode_toggle/main.py create mode 100644 sdk/python/examples/controls/expansion_tile/theme_mode_toggle/pyproject.toml diff --git a/sdk/python/examples/controls/expansion_panel_list/basic.py b/sdk/python/examples/controls/expansion_panel_list/basic/main.py similarity index 87% rename from sdk/python/examples/controls/expansion_panel_list/basic.py rename to sdk/python/examples/controls/expansion_panel_list/basic/main.py index 60e9da6b4d..70c6420a6d 100644 --- a/sdk/python/examples/controls/expansion_panel_list/basic.py +++ b/sdk/python/examples/controls/expansion_panel_list/basic/main.py @@ -13,7 +13,7 @@ def handle_delete(e: ft.Event[ft.IconButton]): panel = tile.parent panel_list.controls.remove(panel) - page.update() + panel_list.update() panel_list = ft.ExpansionPanelList( expand_icon_color=ft.Colors.AMBER, @@ -22,7 +22,6 @@ def handle_delete(e: ft.Event[ft.IconButton]): on_change=handle_change, controls=[ ft.ExpansionPanel( - # has no header and content - placeholders will be used bgcolor=ft.Colors.BLUE_400, expanded=True, ), @@ -35,8 +34,7 @@ def handle_delete(e: ft.Event[ft.IconButton]): ft.Colors.RED_800, ] - for i in range(len(colors)): - bgcolor = colors[i % len(colors)] + for i, bgcolor in enumerate(colors): panel_list.controls.append( ft.ExpansionPanel( bgcolor=bgcolor, @@ -53,7 +51,12 @@ def handle_delete(e: ft.Event[ft.IconButton]): ) ) - page.add(panel_list) + page.add( + ft.SafeArea( + content=panel_list, + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/expansion_panel_list/basic/pyproject.toml b/sdk/python/examples/controls/expansion_panel_list/basic/pyproject.toml new file mode 100644 index 0000000000..6210493fde --- /dev/null +++ b/sdk/python/examples/controls/expansion_panel_list/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-panel-list-basic" +version = "1.0.0" +description = "Builds an ExpansionPanelList with dynamic panel deletion and panel-change callbacks." +requires-python = ">=3.10" +keywords = ["expansion panel list", "panels", "delete", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionPanelList"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "ExpansionPanelList", "ExpansionPanel", "ListTile", "IconButton", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["panel expand/collapse", "dynamic panel removal", "panel change callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/expansion_tile/__init__.py b/sdk/python/examples/controls/expansion_tile/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/expansion_tile/basic.py b/sdk/python/examples/controls/expansion_tile/basic.py deleted file mode 100644 index 9e47ab1f14..0000000000 --- a/sdk/python/examples/controls/expansion_tile/basic.py +++ /dev/null @@ -1,72 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - page.spacing = 0 - page.padding = 0 - - def handle_tile_change(e: ft.Event[ft.ExpansionTile]): - page.show_dialog( - ft.SnackBar( - duration=1000, - content=ft.Text( - value=( - f"ExpansionTile was " - f"{'expanded' if e.data == 'true' else 'collapsed'}" - ) - ), - ) - ) - if e.control.trailing: - e.control.trailing.icon = ( - ft.Icons.ARROW_DROP_DOWN - if e.control.trailing.icon == ft.Icons.ARROW_DROP_DOWN_CIRCLE - else ft.Icons.ARROW_DROP_DOWN_CIRCLE - ) - page.update() - - page.add( - ft.ExpansionTile( - expanded=True, - title=ft.Text("ExpansionTile 1"), - subtitle=ft.Text("Trailing expansion arrow icon"), - affinity=ft.TileAffinity.PLATFORM, - maintain_state=True, - collapsed_text_color=ft.Colors.RED, - text_color=ft.Colors.RED, - controls=[ - ft.ListTile(title=ft.Text("This is sub-tile number 1.1")), - ft.ListTile(title=ft.Text("This is sub-tile number 1.2")), - ], - ), - ft.ExpansionTile( - expanded=True, - title=ft.Text("ExpansionTile 2"), - subtitle=ft.Text("Custom expansion arrow icon"), - trailing=ft.Icon(ft.Icons.ARROW_DROP_DOWN), - collapsed_text_color=ft.Colors.GREEN, - text_color=ft.Colors.GREEN, - on_change=handle_tile_change, - controls=[ - ft.ListTile(title=ft.Text("This is sub-tile number 2.1")), - ft.ListTile(title=ft.Text("This is sub-tile number 2.2")), - ], - ), - ft.ExpansionTile( - expanded=True, - title=ft.Text("ExpansionTile 3"), - subtitle=ft.Text("Leading expansion arrow icon"), - affinity=ft.TileAffinity.LEADING, - collapsed_text_color=ft.Colors.BLUE_800, - text_color=ft.Colors.BLUE_200, - controls=[ - ft.ListTile(title=ft.Text("This is sub-tile number 3.1")), - ft.ListTile(title=ft.Text("This is sub-tile number 3.2")), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/basic/main.py b/sdk/python/examples/controls/expansion_tile/basic/main.py new file mode 100644 index 0000000000..35c995f70a --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/basic/main.py @@ -0,0 +1,79 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + page.spacing = 0 + page.padding = 0 + + def handle_tile_change(e: ft.Event[ft.ExpansionTile]): + page.show_dialog( + ft.SnackBar( + duration=1000, + content=ft.Text( + value=( + f"ExpansionTile was " + f"{'expanded' if e.data == 'true' else 'collapsed'}" + ) + ), + ) + ) + if e.control.trailing: + e.control.trailing.icon = ( + ft.Icons.ARROW_DROP_DOWN + if e.control.trailing.icon == ft.Icons.ARROW_DROP_DOWN_CIRCLE + else ft.Icons.ARROW_DROP_DOWN_CIRCLE + ) + e.control.trailing.update() + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=0, + controls=[ + ft.ExpansionTile( + expanded=True, + title=ft.Text("ExpansionTile 1"), + subtitle=ft.Text("Trailing expansion arrow icon"), + affinity=ft.TileAffinity.PLATFORM, + maintain_state=True, + collapsed_text_color=ft.Colors.RED, + text_color=ft.Colors.RED, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 1.1")), + ft.ListTile(title=ft.Text("This is sub-tile number 1.2")), + ], + ), + ft.ExpansionTile( + expanded=True, + title=ft.Text("ExpansionTile 2"), + subtitle=ft.Text("Custom expansion arrow icon"), + trailing=ft.Icon(ft.Icons.ARROW_DROP_DOWN), + collapsed_text_color=ft.Colors.GREEN, + text_color=ft.Colors.GREEN, + on_change=handle_tile_change, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 2.1")), + ft.ListTile(title=ft.Text("This is sub-tile number 2.2")), + ], + ), + ft.ExpansionTile( + expanded=True, + title=ft.Text("ExpansionTile 3"), + subtitle=ft.Text("Leading expansion arrow icon"), + affinity=ft.TileAffinity.LEADING, + collapsed_text_color=ft.Colors.BLUE_800, + text_color=ft.Colors.BLUE_200, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 3.1")), + ft.ListTile(title=ft.Text("This is sub-tile number 3.2")), + ], + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/basic/pyproject.toml b/sdk/python/examples/controls/expansion_tile/basic/pyproject.toml new file mode 100644 index 0000000000..215a1a74fe --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-basic" +version = "1.0.0" +description = "Shows ExpansionTile variants with trailing and leading arrows, snack feedback, and nested list tiles." +requires-python = ">=3.10" +keywords = ["expansion tile", "layout", "events", "list tiles"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "ExpansionTile", "ListTile", "Text", "Icon", "SnackBar"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["tile expand/collapse", "change callback", "custom arrow affinity"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/expansion_tile/borders.py b/sdk/python/examples/controls/expansion_tile/borders.py deleted file mode 100644 index 643b1a5584..0000000000 --- a/sdk/python/examples/controls/expansion_tile/borders.py +++ /dev/null @@ -1,45 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - - page.add( - ft.ExpansionTile( - title=ft.Text( - value="Expansion Tile with changing borders", - text_align=ft.TextAlign.CENTER, - ), - subtitle=ft.Text( - value="Tile border changes when expanded", - text_align=ft.TextAlign.CENTER, - ), - bgcolor=ft.Colors.BLUE_GREY_200, - controls_padding=ft.Padding.symmetric(horizontal=10), - collapsed_bgcolor=ft.Colors.BLUE_GREY_200, - affinity=ft.TileAffinity.PLATFORM, - maintain_state=True, - shape=ft.RoundedRectangleBorder(radius=20), - collapsed_shape=ft.StadiumBorder(side=ft.BorderSide(width=2)), - collapsed_text_color=ft.Colors.GREY_800, - text_color=ft.Colors.GREY_800, - controls=[ - ft.ListTile( - title=ft.Text("A sub-tile"), - bgcolor=ft.Colors.BLUE_GREY_200, - shape=ft.RoundedRectangleBorder(radius=20), - # shape=ft.StadiumBorder(), - ), - ft.ListTile( - title=ft.Text("Another sub-tile"), - bgcolor=ft.Colors.BLUE_GREY_200, - shape=ft.RoundedRectangleBorder(radius=20), - # shape=ft.StadiumBorder(), - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/borders/main.py b/sdk/python/examples/controls/expansion_tile/borders/main.py new file mode 100644 index 0000000000..6182183949 --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/borders/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.ExpansionTile( + title=ft.Text( + value="Expansion Tile with changing borders", + text_align=ft.TextAlign.CENTER, + ), + subtitle=ft.Text( + value="Tile border changes when expanded", + text_align=ft.TextAlign.CENTER, + ), + bgcolor=ft.Colors.BLUE_GREY_200, + controls_padding=ft.Padding.symmetric(horizontal=10), + collapsed_bgcolor=ft.Colors.BLUE_GREY_200, + affinity=ft.TileAffinity.PLATFORM, + maintain_state=True, + shape=ft.RoundedRectangleBorder(radius=20), + collapsed_shape=ft.StadiumBorder(side=ft.BorderSide(width=2)), + collapsed_text_color=ft.Colors.GREY_800, + text_color=ft.Colors.GREY_800, + controls=[ + ft.ListTile( + title=ft.Text("A sub-tile"), + bgcolor=ft.Colors.BLUE_GREY_200, + shape=ft.RoundedRectangleBorder(radius=20), + ), + ft.ListTile( + title=ft.Text("Another sub-tile"), + bgcolor=ft.Colors.BLUE_GREY_200, + shape=ft.RoundedRectangleBorder(radius=20), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/borders/pyproject.toml b/sdk/python/examples/controls/expansion_tile/borders/pyproject.toml new file mode 100644 index 0000000000..a8a5d91721 --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/borders/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-borders" +version = "1.0.0" +description = "Demonstrates ExpansionTile border and shape changes between collapsed and expanded states." +requires-python = ">=3.10" +keywords = ["expansion tile", "borders", "shape", "collapsed state", "expanded state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Borders" +controls = ["SafeArea", "ExpansionTile", "ListTile", "RoundedRectangleBorder", "StadiumBorder", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["collapsed vs expanded shapes", "custom borders", "tile background styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/expansion_tile/custom_animations.py b/sdk/python/examples/controls/expansion_tile/custom_animations.py deleted file mode 100644 index 14e535c4dc..0000000000 --- a/sdk/python/examples/controls/expansion_tile/custom_animations.py +++ /dev/null @@ -1,45 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.spacing = 20 - - def switch_animation(e: ft.Event[ft.CupertinoSlidingSegmentedButton]): - if e.control.selected_index == 0: - tile.animation_style = None - elif e.control.selected_index == 1: - tile.animation_style = ft.AnimationStyle( - curve=ft.AnimationCurve.BOUNCE_OUT, - duration=ft.Duration(seconds=5), - ) - else: - tile.animation_style = ft.AnimationStyle.no_animation() - - page.add( - ft.CupertinoSlidingSegmentedButton( - selected_index=0, - thumb_color=ft.Colors.BLUE_400, - on_change=switch_animation, - controls=[ - ft.Text("Default animation"), - ft.Text("Custom animation"), - ft.Text("No animation"), - ], - ), - tile := ft.ExpansionTile( - expanded=True, - title=ft.Text( - "Expand/Collapse me while being attentive to the animations!" - ), - controls=[ - ft.ListTile(title=ft.Text("Sub-item 1")), - ft.ListTile(title=ft.Text("Sub-item 2")), - ft.ListTile(title=ft.Text("Sub-item 3")), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/custom_animations/main.py b/sdk/python/examples/controls/expansion_tile/custom_animations/main.py new file mode 100644 index 0000000000..3fd04b24bc --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/custom_animations/main.py @@ -0,0 +1,53 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 20 + + tile = ft.ExpansionTile( + expanded=True, + title=ft.Text("Expand/Collapse me while being attentive to the animations!"), + controls=[ + ft.ListTile(title=ft.Text("Sub-item 1")), + ft.ListTile(title=ft.Text("Sub-item 2")), + ft.ListTile(title=ft.Text("Sub-item 3")), + ], + ) + + def switch_animation(e: ft.Event[ft.CupertinoSlidingSegmentedButton]): + if e.control.selected_index == 0: + tile.animation_style = None + elif e.control.selected_index == 1: + tile.animation_style = ft.AnimationStyle( + curve=ft.AnimationCurve.BOUNCE_OUT, + duration=ft.Duration(seconds=5), + ) + else: + tile.animation_style = ft.AnimationStyle.no_animation() + tile.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.CupertinoSlidingSegmentedButton( + selected_index=0, + thumb_color=ft.Colors.BLUE_400, + on_change=switch_animation, + controls=[ + ft.Text("Default animation"), + ft.Text("Custom animation"), + ft.Text("No animation"), + ], + ), + tile, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/custom_animations/pyproject.toml b/sdk/python/examples/controls/expansion_tile/custom_animations/pyproject.toml new file mode 100644 index 0000000000..8b17b4a2e2 --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/custom_animations/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-custom-animations" +version = "1.0.0" +description = "Switches ExpansionTile animation behavior between default, custom curve, and no animation." +requires-python = ">=3.10" +keywords = ["expansion tile", "animation", "cupertino sliding segmented button", "curve"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Custom animations" +controls = ["SafeArea", "Column", "ExpansionTile", "ListTile", "CupertinoSlidingSegmentedButton", "AnimationStyle", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["animation style switching", "custom animation curve", "disable animations"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/expansion_tile/programmatic_expansion.py b/sdk/python/examples/controls/expansion_tile/programmatic_expansion.py deleted file mode 100644 index 508146dce3..0000000000 --- a/sdk/python/examples/controls/expansion_tile/programmatic_expansion.py +++ /dev/null @@ -1,35 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.spacing = 20 - - def expand_tile(e: ft.Event[ft.FilledButton]): - tile.expanded = True - - def collapse_tile(e: ft.Event[ft.OutlinedButton]): - tile.expanded = False - - page.add( - ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - ft.FilledButton("Expand Tile", on_click=expand_tile), - ft.OutlinedButton("Collapse Tile", on_click=collapse_tile), - ], - ), - tile := ft.ExpansionTile( - title=ft.Text("I am the title of this tile.", weight=ft.FontWeight.BOLD), - subtitle=ft.Text("This is the subtitle."), - affinity=ft.TileAffinity.LEADING, - controls=[ft.Text("👻", size=80)], - expanded=True, - on_change=lambda e: print( - f"Tile was {'expanded' if e.data else 'collapsed'}" - ), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/programmatic_expansion/main.py b/sdk/python/examples/controls/expansion_tile/programmatic_expansion/main.py new file mode 100644 index 0000000000..6ff48ec833 --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/programmatic_expansion/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.spacing = 20 + + tile = ft.ExpansionTile( + title=ft.Text("I am the title of this tile.", weight=ft.FontWeight.BOLD), + subtitle=ft.Text("This is the subtitle."), + affinity=ft.TileAffinity.LEADING, + controls=[ft.Text("👻", size=80)], + expanded=True, + on_change=lambda e: print(f"Tile was {'expanded' if e.data else 'collapsed'}"), + ) + + def expand_tile(_: ft.Event[ft.FilledButton]): + tile.expanded = True + tile.update() + + def collapse_tile(_: ft.Event[ft.OutlinedButton]): + tile.expanded = False + tile.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.FilledButton("Expand Tile", on_click=expand_tile), + ft.OutlinedButton("Collapse Tile", on_click=collapse_tile), + ], + ), + tile, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/programmatic_expansion/pyproject.toml b/sdk/python/examples/controls/expansion_tile/programmatic_expansion/pyproject.toml new file mode 100644 index 0000000000..e6a00cdf0d --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/programmatic_expansion/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-programmatic-expansion" +version = "1.0.0" +description = "Controls ExpansionTile expanded state programmatically with dedicated expand and collapse buttons." +requires-python = ">=3.10" +keywords = ["expansion tile", "programmatic", "expand", "collapse", "buttons"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Programmatic expansion" +controls = ["SafeArea", "Column", "Row", "ExpansionTile", "FilledButton", "OutlinedButton", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["programmatic expansion", "programmatic collapse"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/expansion_tile/theme_mode_toggle.py b/sdk/python/examples/controls/expansion_tile/theme_mode_toggle.py deleted file mode 100644 index 778bdf031f..0000000000 --- a/sdk/python/examples/controls/expansion_tile/theme_mode_toggle.py +++ /dev/null @@ -1,94 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.spacing = 0 - page.padding = 0 - - def handle_switch_change(e: ft.Event[ft.Switch]): - if page.theme_mode == ft.ThemeMode.DARK: - page.theme_mode = ft.ThemeMode.LIGHT - switch.thumb_icon = ft.Icons.LIGHT_MODE - else: - switch.thumb_icon = ft.Icons.DARK_MODE - page.theme_mode = ft.ThemeMode.DARK - page.update() - - def handle_expansion_tile_change(e: ft.Event[ft.ExpansionTile]): - page.show_dialog( - ft.SnackBar( - duration=1000, - content=ft.Text( - value=( - f"ExpansionTile was " - f"{'expanded' if e.data == 'true' else 'collapsed'}" - ) - ), - ) - ) - if e.control.trailing: - e.control.trailing.icon = ( - ft.Icons.ARROW_DROP_DOWN - if e.control.trailing.icon == ft.Icons.ARROW_DROP_DOWN_CIRCLE - else ft.Icons.ARROW_DROP_DOWN_CIRCLE - ) - page.update() - - switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=handle_switch_change) - - page.add( - ft.ExpansionTile( - title=ft.Text("ExpansionTile 1"), - subtitle=ft.Text("Trailing expansion arrow icon"), - bgcolor=ft.Colors.BLUE_GREY_200, - collapsed_bgcolor=ft.Colors.BLUE_GREY_200, - affinity=ft.TileAffinity.PLATFORM, - maintain_state=True, - collapsed_text_color=ft.Colors.RED, - text_color=ft.Colors.RED, - controls=[ - ft.ListTile( - title=ft.Text("This is sub-tile number 1"), - bgcolor=ft.Colors.BLUE_GREY_200, - ) - ], - ), - ft.ExpansionTile( - title=ft.Text("ExpansionTile 2"), - subtitle=ft.Text("Custom expansion arrow icon"), - trailing=ft.Icon(ft.Icons.ARROW_DROP_DOWN), - collapsed_text_color=ft.Colors.GREEN, - text_color=ft.Colors.GREEN, - on_change=handle_expansion_tile_change, - controls=[ft.ListTile(title=ft.Text("This is sub-tile number 2"))], - ), - ft.ExpansionTile( - title=ft.Text("ExpansionTile 3"), - subtitle=ft.Text("Leading expansion arrow icon"), - affinity=ft.TileAffinity.LEADING, - expanded=True, - collapsed_text_color=ft.Colors.BLUE_800, - text_color=ft.Colors.BLUE_200, - controls=[ - ft.ListTile(title=ft.Text("This is sub-tile number 3")), - ft.ListTile(title=ft.Text("This is sub-tile number 4")), - ft.ListTile(title=ft.Text("This is sub-tile number 5")), - ], - ), - ft.Row( - expand=True, - alignment=ft.MainAxisAlignment.END, - controls=[ - ft.Container( - content=switch, - padding=ft.Padding.only(bottom=50), - alignment=ft.Alignment.BOTTOM_RIGHT, - expand=True, - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/theme_mode_toggle/main.py b/sdk/python/examples/controls/expansion_tile/theme_mode_toggle/main.py new file mode 100644 index 0000000000..1dc1710ce8 --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/theme_mode_toggle/main.py @@ -0,0 +1,103 @@ +import flet as ft + + +def main(page: ft.Page): + page.spacing = 0 + page.padding = 0 + + def handle_switch_change(_: ft.Event[ft.Switch]): + if page.theme_mode == ft.ThemeMode.DARK: + page.theme_mode = ft.ThemeMode.LIGHT + switch.thumb_icon = ft.Icons.LIGHT_MODE + else: + switch.thumb_icon = ft.Icons.DARK_MODE + page.theme_mode = ft.ThemeMode.DARK + switch.update() + + def handle_expansion_tile_change(e: ft.Event[ft.ExpansionTile]): + page.show_dialog( + ft.SnackBar( + duration=1000, + content=ft.Text( + value=( + f"ExpansionTile was " + f"{'expanded' if e.data == 'true' else 'collapsed'}" + ) + ), + ) + ) + if e.control.trailing: + e.control.trailing.icon = ( + ft.Icons.ARROW_DROP_DOWN + if e.control.trailing.icon == ft.Icons.ARROW_DROP_DOWN_CIRCLE + else ft.Icons.ARROW_DROP_DOWN_CIRCLE + ) + e.control.trailing.update() + + switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=handle_switch_change) + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=0, + controls=[ + ft.ExpansionTile( + title=ft.Text("ExpansionTile 1"), + subtitle=ft.Text("Trailing expansion arrow icon"), + bgcolor=ft.Colors.BLUE_GREY_200, + collapsed_bgcolor=ft.Colors.BLUE_GREY_200, + affinity=ft.TileAffinity.PLATFORM, + maintain_state=True, + collapsed_text_color=ft.Colors.RED, + text_color=ft.Colors.RED, + controls=[ + ft.ListTile( + title=ft.Text("This is sub-tile number 1"), + bgcolor=ft.Colors.BLUE_GREY_200, + ) + ], + ), + ft.ExpansionTile( + title=ft.Text("ExpansionTile 2"), + subtitle=ft.Text("Custom expansion arrow icon"), + trailing=ft.Icon(ft.Icons.ARROW_DROP_DOWN), + collapsed_text_color=ft.Colors.GREEN, + text_color=ft.Colors.GREEN, + on_change=handle_expansion_tile_change, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 2")) + ], + ), + ft.ExpansionTile( + title=ft.Text("ExpansionTile 3"), + subtitle=ft.Text("Leading expansion arrow icon"), + affinity=ft.TileAffinity.LEADING, + expanded=True, + collapsed_text_color=ft.Colors.BLUE_800, + text_color=ft.Colors.BLUE_200, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 3")), + ft.ListTile(title=ft.Text("This is sub-tile number 4")), + ft.ListTile(title=ft.Text("This is sub-tile number 5")), + ], + ), + ft.Row( + expand=True, + alignment=ft.MainAxisAlignment.END, + controls=[ + ft.Container( + padding=ft.Padding.only(bottom=50), + alignment=ft.Alignment.BOTTOM_RIGHT, + expand=True, + content=switch, + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/expansion_tile/theme_mode_toggle/pyproject.toml b/sdk/python/examples/controls/expansion_tile/theme_mode_toggle/pyproject.toml new file mode 100644 index 0000000000..5f5ccd2e34 --- /dev/null +++ b/sdk/python/examples/controls/expansion_tile/theme_mode_toggle/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-theme-mode-toggle" +version = "1.0.0" +description = "Combines ExpansionTile layouts with a switch to toggle page theme mode and icon state." +requires-python = ">=3.10" +keywords = ["expansion tile", "theme mode", "toggle", "switch", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Theme mode toggle" +controls = ["SafeArea", "Column", "Row", "ExpansionTile", "ListTile", "Switch", "SnackBar", "Text", "Icon"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["theme toggle", "expansion change feedback", "custom tile colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/expansionpanellist.md b/sdk/python/packages/flet/docs/controls/expansionpanellist.md index 09fdb92c7a..ec9f1c5fc4 100644 --- a/sdk/python/packages/flet/docs/controls/expansionpanellist.md +++ b/sdk/python/packages/flet/docs/controls/expansionpanellist.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/expansion_panel_list/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/expansiontile.md b/sdk/python/packages/flet/docs/controls/expansiontile.md index 7c45eeb2b4..27ee54bc78 100644 --- a/sdk/python/packages/flet/docs/controls/expansiontile.md +++ b/sdk/python/packages/flet/docs/controls/expansiontile.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/expansion_tile ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", width="80%") }} @@ -21,25 +21,25 @@ example_images: ../test-images/examples/material/golden/macos/expansion_tile ## Programmatic expansion/collapse ```python ---8<-- "{{ examples }}/programmatic_expansion.py" +--8<-- "{{ examples }}/programmatic_expansion/main.py" ``` ## Custom animations ```python ---8<-- "{{ examples }}/custom_animations.py" +--8<-- "{{ examples }}/custom_animations/main.py" ``` ### Theme mode toggle ```python ---8<-- "{{ examples }}/theme_mode_toggle.py" +--8<-- "{{ examples }}/theme_mode_toggle/main.py" ``` ### Borders ```python ---8<-- "{{ examples }}/borders.py" +--8<-- "{{ examples }}/borders/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/expansion_tile/basic.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/expansion_tile/basic.png index e7d4ae17dbf6c59cc92bd4635ed025d9a12a46b3..4a19f7a2fe84ae141df4bfe2637a283d45add7a1 100644 GIT binary patch delta 60269 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 delta 60349 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 sGmPRK@c9}+XqP!M;SY9g%SAHl+d1*$CK#$ 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 Ac>n+a diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_expansion_tile.py b/sdk/python/packages/flet/integration_tests/examples/material/test_expansion_tile.py index 85dd1972fc..29c0200460 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_expansion_tile.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_expansion_tile.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.expansion_tile import basic +from examples.controls.expansion_tile.basic import main as basic @pytest.mark.asyncio(loop_scope="function") From 74d414a050ca5a383bbcc682228dea01e26133b9 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 12:52:33 -0700 Subject: [PATCH 49/96] Move CupertinoAlertDialog docs and update nav Rename cupertinoalertdialog.md to controls/cupertinoalertdialog/index.md to make the alert dialog a directory index and remove an obsolete Examples link in cupertinodialogaction.md. Update mkdocs.yml to point to the new index path and nest CupertinoDialogAction under CupertinoAlertDialog (removing the previous standalone nav entry). This groups related Cupertino dialog docs together for clearer navigation. --- .../index.md} | 0 .../packages/flet/docs/controls/cupertinodialogaction.md | 4 ---- sdk/python/packages/flet/mkdocs.yml | 5 +++-- 3 files changed, 3 insertions(+), 6 deletions(-) rename sdk/python/packages/flet/docs/controls/{cupertinoalertdialog.md => cupertinoalertdialog/index.md} (100%) diff --git a/sdk/python/packages/flet/docs/controls/cupertinoalertdialog.md b/sdk/python/packages/flet/docs/controls/cupertinoalertdialog/index.md similarity index 100% rename from sdk/python/packages/flet/docs/controls/cupertinoalertdialog.md rename to sdk/python/packages/flet/docs/controls/cupertinoalertdialog/index.md diff --git a/sdk/python/packages/flet/docs/controls/cupertinodialogaction.md b/sdk/python/packages/flet/docs/controls/cupertinodialogaction.md index 3a0efb5d44..f3f92a2f64 100644 --- a/sdk/python/packages/flet/docs/controls/cupertinodialogaction.md +++ b/sdk/python/packages/flet/docs/controls/cupertinodialogaction.md @@ -2,8 +2,4 @@ class_name: flet.CupertinoDialogAction --- -## Examples - -See [these](cupertinoalertdialog.md#examples). - {{ class_all_options(class_name) }} diff --git a/sdk/python/packages/flet/mkdocs.yml b/sdk/python/packages/flet/mkdocs.yml index ece12d4578..c3050bb143 100644 --- a/sdk/python/packages/flet/mkdocs.yml +++ b/sdk/python/packages/flet/mkdocs.yml @@ -325,7 +325,9 @@ nav: - controls/cupertinoactionsheet/index.md - CupertinoActionSheetAction: controls/cupertinoactionsheetaction.md - CupertinoActivityIndicator: controls/cupertinoactivityindicator.md - - CupertinoAlertDialog: controls/cupertinoalertdialog.md + - CupertinoAlertDialog: + - controls/cupertinoalertdialog/index.md + - CupertinoDialogAction: controls/cupertinodialogaction.md - CupertinoAppBar: controls/cupertinoappbar.md - CupertinoBottomSheet: controls/cupertinobottomsheet.md - CupertinoButton: controls/cupertinobutton.md @@ -334,7 +336,6 @@ nav: - controls/cupertinocontextmenu/index.md - CupertinoContextMenuAction: controls/cupertinocontextmenuaction.md - CupertinoDatePicker: controls/cupertinodatepicker.md - - CupertinoDialogAction: controls/cupertinodialogaction.md - CupertinoFilledButton: controls/cupertinofilledbutton.md - CupertinoListTile: controls/cupertinolisttile.md - CupertinoNavigationBar: controls/cupertinonavigationbar.md From ee1add3e7b8025c72c968b282b2131cee9f6acd3 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 13:24:11 -0700 Subject: [PATCH 50/96] Organize examples into main/ and add pyprojects Move example scripts into per-example main.py files (under a main/ subdir) and add pyproject.toml metadata for each example. Update examples to wrap content in SafeArea and add if __name__ == '__main__' guards; apply minor code fixes (use local_delta.x/y, targeted control.update calls, expand/safe-area adjustments). Remove the old top-level example files and update documentation includes to point to the new "*/main.py" paths. --- .../examples/controls/filled_button/basic.py | 14 ----- .../controls/filled_button/basic/main.py | 24 +++++++ .../filled_button/basic/pyproject.toml | 26 ++++++++ .../controls/filled_tonal_button/basic.py | 14 ----- .../filled_tonal_button/basic/main.py | 24 +++++++ .../filled_tonal_button/basic/pyproject.toml | 26 ++++++++ .../floating_action_button/handling_clicks.py | 53 ---------------- .../handling_clicks/main.py | 63 +++++++++++++++++++ .../handling_clicks/pyproject.toml | 26 ++++++++ .../gesture_detector/draggable_containers.py | 46 -------------- .../draggable_containers/main.py | 53 ++++++++++++++++ .../draggable_containers/pyproject.toml | 26 ++++++++ .../gesture_detector/handling_events.py | 31 --------- .../gesture_detector/handling_events/main.py | 38 +++++++++++ .../handling_events/pyproject.toml | 26 ++++++++ .../main.py} | 28 ++++++--- .../mouse_cursors/pyproject.toml | 26 ++++++++ .../gesture_detector/window_drag_area.py | 27 -------- .../gesture_detector/window_drag_area/main.py | 33 ++++++++++ .../window_drag_area/pyproject.toml | 26 ++++++++ .../controls/grid_view/photo_gallery.py | 30 --------- .../controls/grid_view/photo_gallery/main.py | 34 ++++++++++ .../grid_view/photo_gallery/pyproject.toml | 26 ++++++++ .../flet/docs/controls/filledbutton.md | 2 +- .../flet/docs/controls/filledtonalbutton.md | 2 +- .../docs/controls/floatingactionbutton.md | 2 +- .../flet/docs/controls/gesturedetector.md | 8 +-- .../packages/flet/docs/controls/gridview.md | 2 +- 28 files changed, 505 insertions(+), 231 deletions(-) delete mode 100644 sdk/python/examples/controls/filled_button/basic.py create mode 100644 sdk/python/examples/controls/filled_button/basic/main.py create mode 100644 sdk/python/examples/controls/filled_button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/filled_tonal_button/basic.py create mode 100644 sdk/python/examples/controls/filled_tonal_button/basic/main.py create mode 100644 sdk/python/examples/controls/filled_tonal_button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/floating_action_button/handling_clicks.py create mode 100644 sdk/python/examples/controls/floating_action_button/handling_clicks/main.py create mode 100644 sdk/python/examples/controls/floating_action_button/handling_clicks/pyproject.toml delete mode 100644 sdk/python/examples/controls/gesture_detector/draggable_containers.py create mode 100644 sdk/python/examples/controls/gesture_detector/draggable_containers/main.py create mode 100644 sdk/python/examples/controls/gesture_detector/draggable_containers/pyproject.toml delete mode 100644 sdk/python/examples/controls/gesture_detector/handling_events.py create mode 100644 sdk/python/examples/controls/gesture_detector/handling_events/main.py create mode 100644 sdk/python/examples/controls/gesture_detector/handling_events/pyproject.toml rename sdk/python/examples/controls/gesture_detector/{mouse_cursors.py => mouse_cursors/main.py} (50%) create mode 100644 sdk/python/examples/controls/gesture_detector/mouse_cursors/pyproject.toml delete mode 100644 sdk/python/examples/controls/gesture_detector/window_drag_area.py create mode 100644 sdk/python/examples/controls/gesture_detector/window_drag_area/main.py create mode 100644 sdk/python/examples/controls/gesture_detector/window_drag_area/pyproject.toml delete mode 100644 sdk/python/examples/controls/grid_view/photo_gallery.py create mode 100644 sdk/python/examples/controls/grid_view/photo_gallery/main.py create mode 100644 sdk/python/examples/controls/grid_view/photo_gallery/pyproject.toml diff --git a/sdk/python/examples/controls/filled_button/basic.py b/sdk/python/examples/controls/filled_button/basic.py deleted file mode 100644 index 0f3db59374..0000000000 --- a/sdk/python/examples/controls/filled_button/basic.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "FilledButton Example" - - page.add( - ft.FilledButton(content="Filled button"), - ft.FilledButton(content="Disabled button", disabled=True), - ft.FilledButton(content="Button with icon", icon=ft.Icons.ADD_OUTLINED), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/filled_button/basic/main.py b/sdk/python/examples/controls/filled_button/basic/main.py new file mode 100644 index 0000000000..611921f80e --- /dev/null +++ b/sdk/python/examples/controls/filled_button/basic/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "FilledButton Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.FilledButton(content="Filled button"), + ft.FilledButton(content="Disabled button", disabled=True), + ft.FilledButton( + content="Button with icon", + icon=ft.Icons.ADD_OUTLINED, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/filled_button/basic/pyproject.toml b/sdk/python/examples/controls/filled_button/basic/pyproject.toml new file mode 100644 index 0000000000..d516fe6611 --- /dev/null +++ b/sdk/python/examples/controls/filled_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "filled-button-basic" +version = "1.0.0" +description = "Shows enabled, disabled, and icon variants of FilledButton in a simple vertical layout." +requires-python = ">=3.10" +keywords = ["filled button", "button states", "icon button", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/FilledButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "FilledButton"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["enabled and disabled states", "button with icon"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/filled_tonal_button/basic.py b/sdk/python/examples/controls/filled_tonal_button/basic.py deleted file mode 100644 index 28335a7927..0000000000 --- a/sdk/python/examples/controls/filled_tonal_button/basic.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "FilledTonalButton Example" - - page.add( - ft.FilledTonalButton(content="Filled tonal button"), - ft.FilledTonalButton(content="Disabled button", disabled=True), - ft.FilledTonalButton(content="Button with icon", icon=ft.Icons.ADD_OUTLINED), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/filled_tonal_button/basic/main.py b/sdk/python/examples/controls/filled_tonal_button/basic/main.py new file mode 100644 index 0000000000..75b3855d51 --- /dev/null +++ b/sdk/python/examples/controls/filled_tonal_button/basic/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "FilledTonalButton Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.FilledTonalButton(content="Filled tonal button"), + ft.FilledTonalButton(content="Disabled button", disabled=True), + ft.FilledTonalButton( + content="Button with icon", + icon=ft.Icons.ADD_OUTLINED, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/filled_tonal_button/basic/pyproject.toml b/sdk/python/examples/controls/filled_tonal_button/basic/pyproject.toml new file mode 100644 index 0000000000..de96406766 --- /dev/null +++ b/sdk/python/examples/controls/filled_tonal_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "filled-tonal-button-basic" +version = "1.0.0" +description = "Demonstrates FilledTonalButton variants including disabled and icon button states." +requires-python = ">=3.10" +keywords = ["filled tonal button", "button states", "icon button", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/FilledTonalButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "FilledTonalButton"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["enabled and disabled states", "button with icon"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/floating_action_button/handling_clicks.py b/sdk/python/examples/controls/floating_action_button/handling_clicks.py deleted file mode 100644 index d60358f08f..0000000000 --- a/sdk/python/examples/controls/floating_action_button/handling_clicks.py +++ /dev/null @@ -1,53 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Floating Action Button" - page.theme_mode = ft.ThemeMode.LIGHT - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.padding = 0 - page.scroll = ft.ScrollMode.HIDDEN - - # keeps track of the number of tiles already added - count = 1 - - def handle_fab_click(e: ft.Event[ft.FloatingActionButton]): - nonlocal count # to modify the count variable found in the outer scope - page.add( - ft.ListTile( - title=ft.Text(f"Tile {count}"), - bgcolor=ft.Colors.TEAL_300, - leading=ft.Icon( - ft.Icons.CIRCLE_OUTLINED, color=ft.Colors.DEEP_ORANGE_300 - ), - on_click=lambda x: print(x.control.title.value + " was clicked!"), - ) - ) - page.show_dialog(ft.SnackBar(ft.Text("Tile was added successfully!"))) - count += 1 - - page.floating_action_button = ft.FloatingActionButton( - icon=ft.Icons.ADD, - on_click=handle_fab_click, - bgcolor=ft.Colors.LIME_300, - ) - - page.add( - ft.Container( - bgcolor=ft.Colors.BLUE, - padding=ft.Padding.all(20), - content=ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - ft.Text( - value="Floating Action Button Example", - style=ft.TextStyle(size=20, weight=ft.FontWeight.W_500), - ) - ], - ), - ), - ft.Text("Press the FAB to add a tile!"), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/floating_action_button/handling_clicks/main.py b/sdk/python/examples/controls/floating_action_button/handling_clicks/main.py new file mode 100644 index 0000000000..d879b2f0ef --- /dev/null +++ b/sdk/python/examples/controls/floating_action_button/handling_clicks/main.py @@ -0,0 +1,63 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Floating Action Button" + page.theme_mode = ft.ThemeMode.LIGHT + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.padding = 0 + page.scroll = ft.ScrollMode.HIDDEN + + count = 1 + + def handle_fab_click(e: ft.Event[ft.FloatingActionButton]): + nonlocal count + page.add( + ft.ListTile( + title=ft.Text(f"Tile {count}"), + bgcolor=ft.Colors.TEAL_300, + leading=ft.Icon( + ft.Icons.CIRCLE_OUTLINED, + color=ft.Colors.DEEP_ORANGE_300, + ), + on_click=lambda x: print(x.control.title.value + " was clicked!"), + ) + ) + page.show_dialog(ft.SnackBar(ft.Text("Tile was added successfully!"))) + count += 1 + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, + on_click=handle_fab_click, + bgcolor=ft.Colors.LIME_300, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + bgcolor=ft.Colors.BLUE, + padding=ft.Padding.all(20), + content=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + value="Floating Action Button Example", + style=ft.TextStyle( + size=20, + weight=ft.FontWeight.W_500, + ), + ) + ], + ), + ), + ft.Text("Press the FAB to add a tile!"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/floating_action_button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/floating_action_button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..1a136b3c09 --- /dev/null +++ b/sdk/python/examples/controls/floating_action_button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "floating-action-button-handling-clicks" +version = "1.0.0" +description = "Adds list tiles with a FloatingActionButton click and shows a SnackBar confirmation." +requires-python = ">=3.10" +keywords = ["floating action button", "list tile", "click handling", "snackbar"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/FloatingActionButton"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "Container", "Row", "Text", "FloatingActionButton", "ListTile", "SnackBar", "Icon"] +layout_pattern = "feed" +complexity = "basic" +features = ["floating action button click", "dynamic list updates", "snackbar feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/gesture_detector/draggable_containers.py b/sdk/python/examples/controls/gesture_detector/draggable_containers.py deleted file mode 100644 index 7b11d7d52d..0000000000 --- a/sdk/python/examples/controls/gesture_detector/draggable_containers.py +++ /dev/null @@ -1,46 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_pan_update1(e: ft.DragUpdateEvent[ft.GestureDetector]): - container = e.control.parent - container.top = max(0.0, container.top + e.local_delta.y) - container.left = max(0.0, container.left + e.local_delta.x) - container.update() - - def handle_pan_update2(e: ft.DragUpdateEvent[ft.GestureDetector]): - e.control.top = max(0.0, e.control.top + e.local_delta.y) - e.control.left = max(0.0, e.control.left + e.local_delta.x) - e.control.update() - - page.add( - ft.Stack( - width=1000, - height=500, - controls=[ - ft.Container( - bgcolor=ft.Colors.AMBER, - width=50, - height=50, - left=0, - top=0, - content=ft.GestureDetector( - mouse_cursor=ft.MouseCursor.MOVE, - drag_interval=50, - on_pan_update=handle_pan_update1, - ), - ), - ft.GestureDetector( - mouse_cursor=ft.MouseCursor.MOVE, - drag_interval=10, - on_vertical_drag_update=handle_pan_update2, - left=100, - top=100, - content=ft.Container(bgcolor=ft.Colors.BLUE, width=50, height=50), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/gesture_detector/draggable_containers/main.py b/sdk/python/examples/controls/gesture_detector/draggable_containers/main.py new file mode 100644 index 0000000000..3ceae2d653 --- /dev/null +++ b/sdk/python/examples/controls/gesture_detector/draggable_containers/main.py @@ -0,0 +1,53 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_pan_update1(e: ft.DragUpdateEvent[ft.GestureDetector]): + container = e.control.parent + container.top = max(0.0, container.top + e.local_delta.y) + container.left = max(0.0, container.left + e.local_delta.x) + container.update() + + def handle_pan_update2(e: ft.DragUpdateEvent[ft.GestureDetector]): + e.control.top = max(0.0, e.control.top + e.local_delta.y) + e.control.left = max(0.0, e.control.left + e.local_delta.x) + e.control.update() + + page.add( + ft.SafeArea( + content=ft.Stack( + width=1000, + height=500, + controls=[ + ft.Container( + bgcolor=ft.Colors.AMBER, + width=50, + height=50, + left=0, + top=0, + content=ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=10, + on_pan_update=handle_pan_update1, + ), + ), + ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=10, + on_vertical_drag_update=handle_pan_update2, + left=100, + top=100, + content=ft.Container( + bgcolor=ft.Colors.BLUE, + width=50, + height=50, + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/gesture_detector/draggable_containers/pyproject.toml b/sdk/python/examples/controls/gesture_detector/draggable_containers/pyproject.toml new file mode 100644 index 0000000000..b412691782 --- /dev/null +++ b/sdk/python/examples/controls/gesture_detector/draggable_containers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "gesture-detector-draggable-containers" +version = "1.0.0" +description = "Drags nested and standalone GestureDetector controls inside a Stack using pan updates." +requires-python = ">=3.10" +keywords = ["gesture detector", "drag", "pan update", "stack", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/GestureDetector"] + +[tool.flet.metadata] +title = "Draggable containers" +controls = ["SafeArea", "Stack", "Container", "GestureDetector"] +layout_pattern = "canvas" +complexity = "basic" +features = ["free dragging", "nested gesture detector", "position updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/gesture_detector/handling_events.py b/sdk/python/examples/controls/gesture_detector/handling_events.py deleted file mode 100644 index e35643cca7..0000000000 --- a/sdk/python/examples/controls/gesture_detector/handling_events.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.GestureDetector( - content=ft.Container(bgcolor=ft.Colors.GREEN, width=200, height=200), - hover_interval=50, - on_tap=lambda e: print(e), - on_tap_down=lambda e: print(e), - on_tap_up=lambda e: print(e), - on_secondary_tap=lambda e: print(e), - on_secondary_tap_down=lambda e: print(e), - on_secondary_tap_up=lambda e: print(e), - on_long_press_start=lambda e: print(e), - on_long_press_end=lambda e: print(e), - on_secondary_long_press_start=lambda e: print(e), - on_secondary_long_press_end=lambda e: print(e), - on_double_tap=lambda e: print(e), - on_double_tap_down=lambda e: print(e), - on_pan_start=lambda e: print(e), - on_pan_update=lambda e: print(e), - on_pan_end=lambda e: print(e), - on_hover=lambda e: print(e), - on_enter=lambda e: print(e), - on_exit=lambda e: print(e), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/gesture_detector/handling_events/main.py b/sdk/python/examples/controls/gesture_detector/handling_events/main.py new file mode 100644 index 0000000000..22ce866537 --- /dev/null +++ b/sdk/python/examples/controls/gesture_detector/handling_events/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.GestureDetector( + hover_interval=50, + on_tap=lambda e: print(e), + on_tap_down=lambda e: print(e), + on_tap_up=lambda e: print(e), + on_secondary_tap=lambda e: print(e), + on_secondary_tap_down=lambda e: print(e), + on_secondary_tap_up=lambda e: print(e), + on_long_press_start=lambda e: print(e), + on_long_press_end=lambda e: print(e), + on_secondary_long_press_start=lambda e: print(e), + on_secondary_long_press_end=lambda e: print(e), + on_double_tap=lambda e: print(e), + on_double_tap_down=lambda e: print(e), + on_pan_start=lambda e: print(e), + on_pan_update=lambda e: print(e), + on_pan_end=lambda e: print(e), + on_hover=lambda e: print(e), + on_enter=lambda e: print(e), + on_exit=lambda e: print(e), + content=ft.Container( + bgcolor=ft.Colors.GREEN, + width=200, + height=200, + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/gesture_detector/handling_events/pyproject.toml b/sdk/python/examples/controls/gesture_detector/handling_events/pyproject.toml new file mode 100644 index 0000000000..c753db7140 --- /dev/null +++ b/sdk/python/examples/controls/gesture_detector/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "gesture-detector-handling-events" +version = "1.0.0" +description = "Logs tap, press, pan, hover, and enter/exit callbacks from a single GestureDetector." +requires-python = ">=3.10" +keywords = ["gesture detector", "events", "tap", "pan", "hover"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/GestureDetector"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "GestureDetector", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["multi-gesture callbacks", "hover and pointer callbacks"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/gesture_detector/mouse_cursors.py b/sdk/python/examples/controls/gesture_detector/mouse_cursors/main.py similarity index 50% rename from sdk/python/examples/controls/gesture_detector/mouse_cursors.py rename to sdk/python/examples/controls/gesture_detector/mouse_cursors/main.py index 3fc1c567af..f0321d16c2 100644 --- a/sdk/python/examples/controls/gesture_detector/mouse_cursors.py +++ b/sdk/python/examples/controls/gesture_detector/mouse_cursors/main.py @@ -5,8 +5,8 @@ def main(page: ft.Page): def on_pan_update(event: ft.DragUpdateEvent[ft.GestureDetector]): - container.top = max(0.0, container.top + event.delta_y) - container.left = max(0.0, container.left + event.delta_x) + container.top = max(0.0, container.top + event.local_delta.y) + container.left = max(0.0, container.left + event.local_delta.x) container.update() gesture_detector = ft.GestureDetector( @@ -15,24 +15,36 @@ def on_pan_update(event: ft.DragUpdateEvent[ft.GestureDetector]): on_pan_update=on_pan_update, ) container = ft.Container( - content=gesture_detector, bgcolor=ft.Colors.AMBER, width=150, height=150, left=0, top=0, + content=gesture_detector, ) def handle_button_click(e: ft.Event[ft.Button]): gesture_detector.mouse_cursor = random.choice(list(ft.MouseCursor)) text.value = f"Mouse Cursor: {gesture_detector.mouse_cursor}" - page.update() + gesture_detector.update() + text.update() page.add( - ft.Stack(controls=[container], width=1000, height=500), - ft.Button("Change mouse Cursor", on_click=handle_button_click), - text := ft.Text(f"Mouse Cursor: {gesture_detector.mouse_cursor}"), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Stack( + width=1000, + height=500, + controls=[container], + ), + ft.Button("Change mouse Cursor", on_click=handle_button_click), + text := ft.Text(f"Mouse Cursor: {gesture_detector.mouse_cursor}"), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/gesture_detector/mouse_cursors/pyproject.toml b/sdk/python/examples/controls/gesture_detector/mouse_cursors/pyproject.toml new file mode 100644 index 0000000000..14df3ff2e1 --- /dev/null +++ b/sdk/python/examples/controls/gesture_detector/mouse_cursors/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "gesture-detector-mouse-cursors" +version = "1.0.0" +description = "Randomizes GestureDetector mouse cursors and drags the target container in a Stack." +requires-python = ">=3.10" +keywords = ["gesture detector", "mouse cursor", "drag", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/GestureDetector"] + +[tool.flet.metadata] +title = "Mouse cursors" +controls = ["SafeArea", "Column", "Stack", "Container", "GestureDetector", "Button", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["cursor switching", "drag interaction", "live status text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/gesture_detector/window_drag_area.py b/sdk/python/examples/controls/gesture_detector/window_drag_area.py deleted file mode 100644 index b93b627f15..0000000000 --- a/sdk/python/examples/controls/gesture_detector/window_drag_area.py +++ /dev/null @@ -1,27 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def on_pan_update(e: ft.DragUpdateEvent[ft.GestureDetector]): - page.window.left += e.global_delta.x - page.window.top += e.global_delta.y - page.update() - - page.add( - ft.Stack( - width=1000, - height=500, - controls=[ - ft.GestureDetector( - mouse_cursor=ft.MouseCursor.MOVE, - on_pan_update=on_pan_update, - left=200, - top=200, - content=ft.Container(bgcolor=ft.Colors.PINK, width=50, height=50), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/gesture_detector/window_drag_area/main.py b/sdk/python/examples/controls/gesture_detector/window_drag_area/main.py new file mode 100644 index 0000000000..19221a2d2c --- /dev/null +++ b/sdk/python/examples/controls/gesture_detector/window_drag_area/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + def on_pan_update(e: ft.DragUpdateEvent[ft.GestureDetector]): + page.window.left += e.global_delta.x + page.window.top += e.global_delta.y + + page.add( + ft.SafeArea( + content=ft.Stack( + width=1000, + height=500, + controls=[ + ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + on_pan_update=on_pan_update, + left=200, + top=200, + content=ft.Container( + bgcolor=ft.Colors.PINK, + width=50, + height=50, + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/gesture_detector/window_drag_area/pyproject.toml b/sdk/python/examples/controls/gesture_detector/window_drag_area/pyproject.toml new file mode 100644 index 0000000000..d59165524f --- /dev/null +++ b/sdk/python/examples/controls/gesture_detector/window_drag_area/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "gesture-detector-window-drag-area" +version = "1.0.0" +description = "Moves the app window by dragging a GestureDetector handle control." +requires-python = ">=3.10" +keywords = ["gesture detector", "window", "drag", "desktop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/GestureDetector"] + +[tool.flet.metadata] +title = "Window drag area" +controls = ["SafeArea", "Stack", "GestureDetector", "Container"] +layout_pattern = "canvas" +complexity = "basic" +features = ["window dragging", "global drag delta"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/grid_view/photo_gallery.py b/sdk/python/examples/controls/grid_view/photo_gallery.py deleted file mode 100644 index bbeb1dae1f..0000000000 --- a/sdk/python/examples/controls/grid_view/photo_gallery.py +++ /dev/null @@ -1,30 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "GridView Example" - page.theme_mode = ft.ThemeMode.DARK - page.padding = 50 - - page.add( - ft.GridView( - expand=1, - runs_count=5, - max_extent=150, - child_aspect_ratio=1.0, - spacing=5, - run_spacing=5, - controls=[ - ft.Image( - src=f"https://picsum.photos/150/150?{i}", - fit=ft.BoxFit.NONE, - repeat=ft.ImageRepeat.NO_REPEAT, - border_radius=ft.BorderRadius.all(10), - ) - for i in range(0, 60) - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/grid_view/photo_gallery/main.py b/sdk/python/examples/controls/grid_view/photo_gallery/main.py new file mode 100644 index 0000000000..ea96f88d95 --- /dev/null +++ b/sdk/python/examples/controls/grid_view/photo_gallery/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "GridView Example" + page.theme_mode = ft.ThemeMode.DARK + page.padding = 50 + + page.add( + ft.SafeArea( + expand=True, + content=ft.GridView( + expand=True, + runs_count=5, + max_extent=150, + child_aspect_ratio=1.0, + spacing=5, + run_spacing=5, + controls=[ + ft.Image( + src=f"https://picsum.photos/150/150?{i}", + fit=ft.BoxFit.NONE, + repeat=ft.ImageRepeat.NO_REPEAT, + border_radius=ft.BorderRadius.all(10), + ) + for i in range(0, 60) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/grid_view/photo_gallery/pyproject.toml b/sdk/python/examples/controls/grid_view/photo_gallery/pyproject.toml new file mode 100644 index 0000000000..4cb1c16f4c --- /dev/null +++ b/sdk/python/examples/controls/grid_view/photo_gallery/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "grid-view-photo-gallery" +version = "1.0.0" +description = "Renders a responsive GridView photo gallery with remote images and spacing configuration." +requires-python = ">=3.10" +keywords = ["grid view", "photo gallery", "images", "responsive layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/GridView"] + +[tool.flet.metadata] +title = "Photo gallery" +controls = ["SafeArea", "GridView", "Image"] +layout_pattern = "gallery" +complexity = "basic" +features = ["remote image grid", "responsive runs and extent", "rounded thumbnails"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/filledbutton.md b/sdk/python/packages/flet/docs/controls/filledbutton.md index 493c66e55b..ea05dd45b9 100644 --- a/sdk/python/packages/flet/docs/controls/filledbutton.md +++ b/sdk/python/packages/flet/docs/controls/filledbutton.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/filled_button/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/filledtonalbutton.md b/sdk/python/packages/flet/docs/controls/filledtonalbutton.md index 8dd3a4f5bf..28f7652193 100644 --- a/sdk/python/packages/flet/docs/controls/filledtonalbutton.md +++ b/sdk/python/packages/flet/docs/controls/filledtonalbutton.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/filled_tonal_button/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/floatingactionbutton.md b/sdk/python/packages/flet/docs/controls/floatingactionbutton.md index bf4fbc319c..d67fb92335 100644 --- a/sdk/python/packages/flet/docs/controls/floatingactionbutton.md +++ b/sdk/python/packages/flet/docs/controls/floatingactionbutton.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/floating_action_button/media ### Handling clicks ```python ---8<-- "{{ examples }}/handling_clicks.py" +--8<-- "{{ examples }}/handling_clicks/main.py" ``` {{ image(example_media + "/handling_clicks.gif", alt="handling-clicks", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/gesturedetector.md b/sdk/python/packages/flet/docs/controls/gesturedetector.md index 6b8590aac9..ae8a65e132 100644 --- a/sdk/python/packages/flet/docs/controls/gesturedetector.md +++ b/sdk/python/packages/flet/docs/controls/gesturedetector.md @@ -15,7 +15,7 @@ example_images: ../examples/controls/gesture_detector/media ### Handling events ```python ---8<-- "{{ examples }}/handling_events.py" +--8<-- "{{ examples }}/handling_events/main.py" ``` ### Draggable containers @@ -26,7 +26,7 @@ The sample also shows that GestureDetector can have a child control (blue contai inside another control (yellow container) giving the same results. ```python ---8<-- "{{ examples }}/draggable_containers.py" +--8<-- "{{ examples }}/draggable_containers/main.py" ``` {{ image(example_images + "/draggable_containers.gif", alt="draggable-containers", width="80%") }} @@ -35,13 +35,13 @@ inside another control (yellow container) giving the same results. ### Window drag area ```python ---8<-- "{{ examples }}/window_drag_area.py" +--8<-- "{{ examples }}/window_drag_area/main.py" ``` ### Mouse Cursors ```python ---8<-- "{{ examples }}/mouse_cursors.py" +--8<-- "{{ examples }}/mouse_cursors/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/gridview.md b/sdk/python/packages/flet/docs/controls/gridview.md index c8d72b98f0..67435f3222 100644 --- a/sdk/python/packages/flet/docs/controls/gridview.md +++ b/sdk/python/packages/flet/docs/controls/gridview.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/grid_view/media ### Photo gallery ```python ---8<-- "{{ examples }}/photo_gallery.py" +--8<-- "{{ examples }}/photo_gallery/main.py" ``` {{ image(example_media + "/photo_gallery.png", alt="photo-gallery", width="80%") }} From f6364109998191d48eba51922583f49e673362a9 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 13:36:03 -0700 Subject: [PATCH 51/96] Restructure hero examples and add metadata Move hero example scripts into package-style folders (basic/main.py, gallery/main.py) and remove the old __init__.py. Add pyproject.toml metadata for both basic and gallery examples so they can be discovered/packaged by the Flet gallery tooling. Update example code layout (wrap pages in SafeArea with inner Container/Column) and adjust docs to point to the new example paths. Update integration test import to load basic.main accordingly. --- sdk/python/examples/controls/hero/__init__.py | 0 .../controls/hero/{basic.py => basic/main.py} | 66 +++++++++-------- .../controls/hero/basic/pyproject.toml | 26 +++++++ .../hero/{gallery.py => gallery/main.py} | 72 ++++++++++--------- .../controls/hero/gallery/pyproject.toml | 26 +++++++ .../packages/flet/docs/controls/hero.md | 4 +- .../examples/core/test_hero.py | 2 +- 7 files changed, 130 insertions(+), 66 deletions(-) delete mode 100644 sdk/python/examples/controls/hero/__init__.py rename sdk/python/examples/controls/hero/{basic.py => basic/main.py} (63%) create mode 100644 sdk/python/examples/controls/hero/basic/pyproject.toml rename sdk/python/examples/controls/hero/{gallery.py => gallery/main.py} (78%) create mode 100644 sdk/python/examples/controls/hero/gallery/pyproject.toml diff --git a/sdk/python/examples/controls/hero/__init__.py b/sdk/python/examples/controls/hero/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/hero/basic.py b/sdk/python/examples/controls/hero/basic/main.py similarity index 63% rename from sdk/python/examples/controls/hero/basic.py rename to sdk/python/examples/controls/hero/basic/main.py index 69ecad6088..cb3ba79d46 100644 --- a/sdk/python/examples/controls/hero/basic.py +++ b/sdk/python/examples/controls/hero/basic/main.py @@ -56,24 +56,27 @@ def build_home_view() -> ft.View: route="/", appbar=ft.AppBar(title=ft.Text("Hero animation")), controls=[ - ft.Container( + ft.SafeArea( expand=True, - alignment=ft.Alignment.CENTER, - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - spacing=20, - controls=[ - ft.Text("Tap the card to navigate"), - ft.GestureDetector( - mouse_cursor=ft.MouseCursor.CLICK, - on_tap=go_to_details, - content=ft.Hero( - tag=hero_tag, - content=build_card(130, "Open details"), + content=ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text("Tap the card to navigate"), + ft.GestureDetector( + mouse_cursor=ft.MouseCursor.CLICK, + on_tap=go_to_details, + content=ft.Hero( + tag=hero_tag, + content=build_card(130, "Open details"), + ), ), - ), - ], + ], + ), ), ) ], @@ -84,21 +87,24 @@ def build_details_view() -> ft.View: route="/details", appbar=ft.AppBar(title=ft.Text("Details")), controls=[ - ft.Container( + ft.SafeArea( expand=True, - alignment=ft.Alignment.CENTER, - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - spacing=20, - controls=[ - ft.Hero( - tag=hero_tag, - transition_on_user_gestures=True, - content=build_card(280, "Details"), - ), - ft.Button("Back", on_click=go_home), - ], + content=ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Hero( + tag=hero_tag, + transition_on_user_gestures=True, + content=build_card(280, "Details"), + ), + ft.Button("Back", on_click=go_home), + ], + ), ), ) ], diff --git a/sdk/python/examples/controls/hero/basic/pyproject.toml b/sdk/python/examples/controls/hero/basic/pyproject.toml new file mode 100644 index 0000000000..736bedf137 --- /dev/null +++ b/sdk/python/examples/controls/hero/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "hero-basic" +version = "1.0.0" +description = "Demonstrates Hero animation between home and details views with a shared tagged card." +requires-python = ">=3.10" +keywords = ["hero", "animation", "route transition", "navigation", "gesture"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Hero"] + +[tool.flet.metadata] +title = "Basic" +controls = ["View", "SafeArea", "Container", "Column", "GestureDetector", "Hero", "AppBar", "Button", "Text", "Icon"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["hero route transition", "shared hero tag", "view navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/hero/gallery.py b/sdk/python/examples/controls/hero/gallery/main.py similarity index 78% rename from sdk/python/examples/controls/hero/gallery.py rename to sdk/python/examples/controls/hero/gallery/main.py index 0139e4c3ca..5acb56eca3 100644 --- a/sdk/python/examples/controls/hero/gallery.py +++ b/sdk/python/examples/controls/hero/gallery/main.py @@ -141,19 +141,22 @@ def build_home_view() -> ft.View: route="/", appbar=ft.AppBar(title=ft.Text("Hero gallery")), controls=[ - ft.Column( + ft.SafeArea( expand=True, - spacing=10, - scroll=ft.ScrollMode.AUTO, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text( - "Each card has a unique Hero tag. " - "Open any item to see a matched transition.", - color=ft.Colors.ON_SURFACE_VARIANT, - ), - *rows, - ], + content=ft.Column( + expand=True, + spacing=10, + scroll=ft.ScrollMode.AUTO, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text( + "Each card has a unique Hero tag. " + "Open any item to see a matched transition.", + color=ft.Colors.ON_SURFACE_VARIANT, + ), + *rows, + ], + ), ) ], ) @@ -163,30 +166,33 @@ def build_details_view(product: dict) -> ft.View: route=f"/product/{product['id']}", appbar=ft.AppBar(title=ft.Text(product["name"])), controls=[ - ft.Column( + ft.SafeArea( expand=True, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - spacing=16, - scroll=ft.ScrollMode.AUTO, - controls=[ - ft.Container(height=8), - build_hero_tile(product, 220), - ft.Text( - product["subtitle"], - size=20, - weight=ft.FontWeight.W_600, - text_align=ft.TextAlign.CENTER, - ), - ft.Container( - width=520, - content=ft.Text( - product["description"], + content=ft.Column( + expand=True, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=16, + scroll=ft.ScrollMode.AUTO, + controls=[ + ft.Container(height=8), + build_hero_tile(product, 220), + ft.Text( + product["subtitle"], + size=20, + weight=ft.FontWeight.W_600, text_align=ft.TextAlign.CENTER, - color=ft.Colors.ON_SURFACE_VARIANT, ), - ), - ft.Button("Back to gallery", on_click=back_to_gallery), - ], + ft.Container( + width=520, + content=ft.Text( + product["description"], + text_align=ft.TextAlign.CENTER, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ), + ft.Button("Back to gallery", on_click=back_to_gallery), + ], + ), ) ], ) diff --git a/sdk/python/examples/controls/hero/gallery/pyproject.toml b/sdk/python/examples/controls/hero/gallery/pyproject.toml new file mode 100644 index 0000000000..d5fa75ca01 --- /dev/null +++ b/sdk/python/examples/controls/hero/gallery/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "hero-gallery" +version = "1.0.0" +description = "Shows a gallery of items with unique Hero tags and animated transitions to detail views." +requires-python = ">=3.10" +keywords = ["hero", "gallery", "animation", "navigation", "cards"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Hero"] + +[tool.flet.metadata] +title = "Gallery" +controls = ["View", "SafeArea", "Column", "Row", "Container", "Card", "GestureDetector", "Hero", "AppBar", "Button", "Text", "Icon"] +layout_pattern = "gallery" +complexity = "basic" +features = ["multiple hero tags", "list-to-details transition", "scrollable gallery"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/hero.md b/sdk/python/packages/flet/docs/controls/hero.md index 150bdcc61b..3bab57fc44 100644 --- a/sdk/python/packages/flet/docs/controls/hero.md +++ b/sdk/python/packages/flet/docs/controls/hero.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/core/golden/macos/hero ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.gif", width="80%") }} @@ -19,7 +19,7 @@ example_images: ../test-images/examples/core/golden/macos/hero ### Gallery ```python ---8<-- "{{ examples }}/gallery.py" +--8<-- "{{ examples }}/gallery/main.py" ``` diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_hero.py b/sdk/python/packages/flet/integration_tests/examples/core/test_hero.py index 09142d76d9..2ef30273b7 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_hero.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_hero.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.hero import basic +from examples.controls.hero.basic import main as basic @pytest.mark.parametrize( From 266628db952eaa7f377e93f4ba20bd3d5cce8cac Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 15:00:49 -0700 Subject: [PATCH 52/96] Restructure Python examples and add pyproject Move and reorganize many SDK Python example scripts into per-example main.py files and add pyproject.toml metadata for each example. Wrap example UIs in SafeArea, add __main__ guards (ft.run(main)), fix minor runtime issues (call control.update() where needed, update image/src updates, rename loop variable), and remove the old top-level example files. Also update related docs for Icon, IconButton and Image controls. --- sdk/python/examples/controls/icon/basic.py | 41 ------- .../examples/controls/icon/basic/main.py | 67 +++++++++++ .../controls/icon/basic/pyproject.toml | 26 +++++ .../controls/icon_button/handling_clicks.py | 22 ---- .../icon_button/handling_clicks/main.py | 29 +++++ .../handling_clicks/pyproject.toml | 26 +++++ .../controls/icon_button/selected_icon.py | 31 ----- .../icon_button/selected_icon/main.py | 34 ++++++ .../icon_button/selected_icon/pyproject.toml | 26 +++++ .../examples/controls/icon_button/variants.py | 104 ----------------- .../controls/icon_button/variants/main.py | 107 ++++++++++++++++++ .../icon_button/variants/pyproject.toml | 26 +++++ .../{dynamic_svg.py => dynamic_svg/main.py} | 7 +- .../controls/image/dynamic_svg/pyproject.toml | 26 +++++ sdk/python/examples/controls/image/fade_in.py | 35 ------ .../examples/controls/image/fade_in/main.py | 43 +++++++ .../controls/image/fade_in/pyproject.toml | 26 +++++ sdk/python/examples/controls/image/gallery.py | 33 ------ .../image/gallery/assets/app_icon_512.png | Bin 0 -> 21589 bytes .../examples/controls/image/gallery/main.py | 43 +++++++ .../controls/image/gallery/pyproject.toml | 26 +++++ .../main.py} | 50 ++++---- .../image/gapless_playback/pyproject.toml | 26 +++++ .../examples/controls/image/lucide_icons.py | 22 ---- .../controls/image/lucide_icons/main.py | 29 +++++ .../image/lucide_icons/pyproject.toml | 26 +++++ .../main.py} | 31 +++-- .../image/src_base64_and_bytes/pyproject.toml | 26 +++++ .../{static_svg.py => static_svg/main.py} | 51 ++++++--- .../controls/image/static_svg/pyproject.toml | 26 +++++ .../packages/flet/docs/controls/icon.md | 2 +- .../packages/flet/docs/controls/iconbutton.md | 4 +- .../packages/flet/docs/controls/image.md | 14 +-- 33 files changed, 736 insertions(+), 349 deletions(-) delete mode 100644 sdk/python/examples/controls/icon/basic.py create mode 100644 sdk/python/examples/controls/icon/basic/main.py create mode 100644 sdk/python/examples/controls/icon/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/icon_button/handling_clicks.py create mode 100644 sdk/python/examples/controls/icon_button/handling_clicks/main.py create mode 100644 sdk/python/examples/controls/icon_button/handling_clicks/pyproject.toml delete mode 100644 sdk/python/examples/controls/icon_button/selected_icon.py create mode 100644 sdk/python/examples/controls/icon_button/selected_icon/main.py create mode 100644 sdk/python/examples/controls/icon_button/selected_icon/pyproject.toml delete mode 100644 sdk/python/examples/controls/icon_button/variants.py create mode 100644 sdk/python/examples/controls/icon_button/variants/main.py create mode 100644 sdk/python/examples/controls/icon_button/variants/pyproject.toml rename sdk/python/examples/controls/image/{dynamic_svg.py => dynamic_svg/main.py} (80%) create mode 100644 sdk/python/examples/controls/image/dynamic_svg/pyproject.toml delete mode 100644 sdk/python/examples/controls/image/fade_in.py create mode 100644 sdk/python/examples/controls/image/fade_in/main.py create mode 100644 sdk/python/examples/controls/image/fade_in/pyproject.toml delete mode 100644 sdk/python/examples/controls/image/gallery.py create mode 100644 sdk/python/examples/controls/image/gallery/assets/app_icon_512.png create mode 100644 sdk/python/examples/controls/image/gallery/main.py create mode 100644 sdk/python/examples/controls/image/gallery/pyproject.toml rename sdk/python/examples/controls/image/{gapless_playback.py => gapless_playback/main.py} (52%) create mode 100644 sdk/python/examples/controls/image/gapless_playback/pyproject.toml delete mode 100644 sdk/python/examples/controls/image/lucide_icons.py create mode 100644 sdk/python/examples/controls/image/lucide_icons/main.py create mode 100644 sdk/python/examples/controls/image/lucide_icons/pyproject.toml rename sdk/python/examples/controls/image/{src_base64_and_bytes.py => src_base64_and_bytes/main.py} (75%) create mode 100644 sdk/python/examples/controls/image/src_base64_and_bytes/pyproject.toml rename sdk/python/examples/controls/image/{static_svg.py => static_svg/main.py} (63%) create mode 100644 sdk/python/examples/controls/image/static_svg/pyproject.toml diff --git a/sdk/python/examples/controls/icon/basic.py b/sdk/python/examples/controls/icon/basic.py deleted file mode 100644 index 2ae5b4eb1b..0000000000 --- a/sdk/python/examples/controls/icon/basic.py +++ /dev/null @@ -1,41 +0,0 @@ -from typing import cast - -import flet as ft - - -def main(page: ft.Page): - page.add( - # material - ft.Row( - controls=[ - ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), - ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN_400, size=30), - ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE, size=50), - ft.Icon(ft.Icons.SETTINGS, color="#c1c1c1"), - ] - ), - # cupertino - ft.Row( - controls=[ - ft.Icon(ft.CupertinoIcons.PROFILE_CIRCLED, color=ft.Colors.PINK), - ft.Icon( - icon=cast(ft.CupertinoIcons, ft.CupertinoIcons.random()), - color=ft.Colors.GREEN_400, - size=30, - ), - ft.Icon( - icon=cast(ft.CupertinoIcons, ft.CupertinoIcons.random()), - color=ft.Colors.BLUE, - size=50, - ), - ft.Icon( - icon=cast(ft.CupertinoIcons, ft.CupertinoIcons.random()), - color="#c1c1c1", - ), - ] - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/icon/basic/main.py b/sdk/python/examples/controls/icon/basic/main.py new file mode 100644 index 0000000000..e6269a2e42 --- /dev/null +++ b/sdk/python/examples/controls/icon/basic/main.py @@ -0,0 +1,67 @@ +from typing import cast + +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + # material + ft.Row( + controls=[ + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), + ft.Icon( + ft.Icons.AUDIOTRACK, + color=ft.Colors.GREEN_400, + size=30, + ), + ft.Icon( + ft.Icons.BEACH_ACCESS, + color=ft.Colors.BLUE, + size=50, + ), + ft.Icon(ft.Icons.SETTINGS, color="#c1c1c1"), + ] + ), + # cupertino + ft.Row( + controls=[ + ft.Icon( + ft.CupertinoIcons.PROFILE_CIRCLED, + color=ft.Colors.PINK, + ), + ft.Icon( + icon=cast( + ft.CupertinoIcons, + ft.CupertinoIcons.random(), + ), + color=ft.Colors.GREEN_400, + size=30, + ), + ft.Icon( + icon=cast( + ft.CupertinoIcons, + ft.CupertinoIcons.random(), + ), + color=ft.Colors.BLUE, + size=50, + ), + ft.Icon( + icon=cast( + ft.CupertinoIcons, + ft.CupertinoIcons.random(), + ), + color="#c1c1c1", + ), + ] + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/icon/basic/pyproject.toml b/sdk/python/examples/controls/icon/basic/pyproject.toml new file mode 100644 index 0000000000..4c927ec0ca --- /dev/null +++ b/sdk/python/examples/controls/icon/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "icon-basic" +version = "1.0.0" +description = "Displays Material and Cupertino icons with different sizes and colors." +requires-python = ">=3.10" +keywords = ["icon", "material icons", "cupertino icons", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Icon"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Row", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["material icons", "cupertino icons", "icon color and size"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/icon_button/handling_clicks.py b/sdk/python/examples/controls/icon_button/handling_clicks.py deleted file mode 100644 index b306db4706..0000000000 --- a/sdk/python/examples/controls/icon_button/handling_clicks.py +++ /dev/null @@ -1,22 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "IconButton Example" - - def button_clicked(e: ft.Event[ft.IconButton]): - button.data += 1 - message.value = f"Button clicked {button.data} time(s)" - page.update() - - page.add( - button := ft.IconButton( - icon=ft.Icons.PLAY_CIRCLE_FILL_OUTLINED, - data=0, - on_click=button_clicked, - ), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/icon_button/handling_clicks/main.py b/sdk/python/examples/controls/icon_button/handling_clicks/main.py new file mode 100644 index 0000000000..a93ad915de --- /dev/null +++ b/sdk/python/examples/controls/icon_button/handling_clicks/main.py @@ -0,0 +1,29 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "IconButton Example" + + def button_clicked(e: ft.Event[ft.IconButton]): + button.data += 1 + message.value = f"Button clicked {button.data} time(s)" + message.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + button := ft.IconButton( + icon=ft.Icons.PLAY_CIRCLE_FILL_OUTLINED, + data=0, + on_click=button_clicked, + ), + message := ft.Text(), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/icon_button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/icon_button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..8fd6e7bd26 --- /dev/null +++ b/sdk/python/examples/controls/icon_button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "icon-button-handling-clicks" +version = "1.0.0" +description = "Counts IconButton clicks and updates a text status message." +requires-python = ">=3.10" +keywords = ["icon button", "click handling", "events", "counter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/IconButton"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "IconButton", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["click callback", "live click counter"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/icon_button/selected_icon.py b/sdk/python/examples/controls/icon_button/selected_icon.py deleted file mode 100644 index 8a0a7b2c5c..0000000000 --- a/sdk/python/examples/controls/icon_button/selected_icon.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "IconButton Example" - page.padding = 10 - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - def handle_click(e: ft.Event[ft.IconButton]): - e.control.selected = not e.control.selected - e.control.update() - - page.add( - ft.IconButton( - icon=ft.Icons.BATTERY_1_BAR, - selected_icon=ft.Icons.BATTERY_FULL, - scale=5, - on_click=handle_click, - selected=False, - style=ft.ButtonStyle( - color={ - ft.ControlState.SELECTED: ft.Colors.GREEN, - ft.ControlState.DEFAULT: ft.Colors.RED, - } - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/icon_button/selected_icon/main.py b/sdk/python/examples/controls/icon_button/selected_icon/main.py new file mode 100644 index 0000000000..51da3b112c --- /dev/null +++ b/sdk/python/examples/controls/icon_button/selected_icon/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "IconButton Example" + page.padding = 10 + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + def handle_click(e: ft.Event[ft.IconButton]): + e.control.selected = not e.control.selected + e.control.update() + + page.add( + ft.SafeArea( + content=ft.IconButton( + icon=ft.Icons.BATTERY_1_BAR, + selected_icon=ft.Icons.BATTERY_FULL, + scale=5, + on_click=handle_click, + selected=False, + style=ft.ButtonStyle( + color={ + ft.ControlState.SELECTED: ft.Colors.GREEN, + ft.ControlState.DEFAULT: ft.Colors.RED, + } + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/icon_button/selected_icon/pyproject.toml b/sdk/python/examples/controls/icon_button/selected_icon/pyproject.toml new file mode 100644 index 0000000000..6544e68bce --- /dev/null +++ b/sdk/python/examples/controls/icon_button/selected_icon/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "icon-button-selected-icon" +version = "1.0.0" +description = "Toggles IconButton selected state and switches between default and selected icons." +requires-python = ">=3.10" +keywords = ["icon button", "selected icon", "toggle", "button style"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/IconButton"] + +[tool.flet.metadata] +title = "Selected icon" +controls = ["SafeArea", "IconButton", "ButtonStyle"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["selected state toggle", "selected icon", "state-based colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/icon_button/variants.py b/sdk/python/examples/controls/icon_button/variants.py deleted file mode 100644 index 754208aa16..0000000000 --- a/sdk/python/examples/controls/icon_button/variants.py +++ /dev/null @@ -1,104 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "IconButton variants" - page.padding = 10 - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - def toggle_icon_button(e): - e.control.selected = not e.control.selected - - page.add( - ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - spacing=50, - controls=[ - # Normal buttons column (enabled only) - ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - spacing=20, - controls=[ - ft.Text( - "Normal", - theme_style=ft.TextThemeStyle.BODY_MEDIUM, - ), - ft.IconButton( - icon=ft.Icons.FILTER_DRAMA, - ), - ft.FilledIconButton( - icon=ft.Icons.FILTER_DRAMA, - ), - ft.FilledTonalIconButton( - icon=ft.Icons.FILTER_DRAMA, - ), - ft.OutlinedIconButton( - icon=ft.Icons.FILTER_DRAMA, - ), - ], - ), - # Disabled buttons column - ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - spacing=20, - controls=[ - ft.Text( - "Disabled", - theme_style=ft.TextThemeStyle.BODY_MEDIUM, - ), - ft.IconButton( - icon=ft.Icons.FILTER_DRAMA, - disabled=True, - ), - ft.FilledIconButton( - icon=ft.Icons.FILTER_DRAMA, - disabled=True, - ), - ft.FilledTonalIconButton( - icon=ft.Icons.FILTER_DRAMA, - disabled=True, - ), - ft.OutlinedIconButton( - icon=ft.Icons.FILTER_DRAMA, - disabled=True, - ), - ], - ), - # Toggle buttons column - ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - spacing=20, - controls=[ - ft.Text( - "Toggle", - theme_style=ft.TextThemeStyle.BODY_MEDIUM, - ), - ft.IconButton( - icon=ft.Icons.FILTER_DRAMA, - selected=False, - on_click=toggle_icon_button, - ), - ft.FilledIconButton( - icon=ft.Icons.FILTER_DRAMA, - selected=False, - on_click=toggle_icon_button, - ), - ft.FilledTonalIconButton( - icon=ft.Icons.FILTER_DRAMA, - selected=False, - on_click=toggle_icon_button, - ), - ft.OutlinedIconButton( - icon=ft.Icons.FILTER_DRAMA, - selected=False, - on_click=toggle_icon_button, - ), - ], - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/icon_button/variants/main.py b/sdk/python/examples/controls/icon_button/variants/main.py new file mode 100644 index 0000000000..07738941ab --- /dev/null +++ b/sdk/python/examples/controls/icon_button/variants/main.py @@ -0,0 +1,107 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "IconButton variants" + page.padding = 10 + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + def toggle_icon_button(e): + e.control.selected = not e.control.selected + + page.add( + ft.SafeArea( + content=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + spacing=50, + controls=[ + # Normal buttons column (enabled only) + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text( + "Normal", + theme_style=ft.TextThemeStyle.BODY_MEDIUM, + ), + ft.IconButton( + icon=ft.Icons.FILTER_DRAMA, + ), + ft.FilledIconButton( + icon=ft.Icons.FILTER_DRAMA, + ), + ft.FilledTonalIconButton( + icon=ft.Icons.FILTER_DRAMA, + ), + ft.OutlinedIconButton( + icon=ft.Icons.FILTER_DRAMA, + ), + ], + ), + # Disabled buttons column + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text( + "Disabled", + theme_style=ft.TextThemeStyle.BODY_MEDIUM, + ), + ft.IconButton( + icon=ft.Icons.FILTER_DRAMA, + disabled=True, + ), + ft.FilledIconButton( + icon=ft.Icons.FILTER_DRAMA, + disabled=True, + ), + ft.FilledTonalIconButton( + icon=ft.Icons.FILTER_DRAMA, + disabled=True, + ), + ft.OutlinedIconButton( + icon=ft.Icons.FILTER_DRAMA, + disabled=True, + ), + ], + ), + # Toggle buttons column + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text( + "Toggle", + theme_style=ft.TextThemeStyle.BODY_MEDIUM, + ), + ft.IconButton( + icon=ft.Icons.FILTER_DRAMA, + selected=False, + on_click=toggle_icon_button, + ), + ft.FilledIconButton( + icon=ft.Icons.FILTER_DRAMA, + selected=False, + on_click=toggle_icon_button, + ), + ft.FilledTonalIconButton( + icon=ft.Icons.FILTER_DRAMA, + selected=False, + on_click=toggle_icon_button, + ), + ft.OutlinedIconButton( + icon=ft.Icons.FILTER_DRAMA, + selected=False, + on_click=toggle_icon_button, + ), + ], + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/icon_button/variants/pyproject.toml b/sdk/python/examples/controls/icon_button/variants/pyproject.toml new file mode 100644 index 0000000000..163fd07c2c --- /dev/null +++ b/sdk/python/examples/controls/icon_button/variants/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "icon-button-variants" +version = "1.0.0" +description = "Compares normal, disabled, and toggle variants across IconButton style families." +requires-python = ">=3.10" +keywords = ["icon button", "variants", "filled", "outlined", "toggle"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/IconButton"] + +[tool.flet.metadata] +title = "Variants" +controls = ["SafeArea", "Row", "Column", "Text", "IconButton", "FilledIconButton", "FilledTonalIconButton", "OutlinedIconButton"] +layout_pattern = "comparison" +complexity = "basic" +features = ["variant comparison", "disabled states", "toggle buttons"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/image/dynamic_svg.py b/sdk/python/examples/controls/image/dynamic_svg/main.py similarity index 80% rename from sdk/python/examples/controls/image/dynamic_svg.py rename to sdk/python/examples/controls/image/dynamic_svg/main.py index 7ebccb4ba2..f7fbf83804 100644 --- a/sdk/python/examples/controls/image/dynamic_svg.py +++ b/sdk/python/examples/controls/image/dynamic_svg/main.py @@ -13,13 +13,14 @@ async def main(page: ft.Page): """ img = ft.Image(src=svg_image.format(0, 0)) - page.add(img) + page.add(ft.SafeArea(content=img)) - for c in range(0, 10): + for _ in range(0, 10): for i in range(0, 10): img.src = svg_image.format(i * 10, i * 10) img.update() await asyncio.sleep(0.1) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/image/dynamic_svg/pyproject.toml b/sdk/python/examples/controls/image/dynamic_svg/pyproject.toml new file mode 100644 index 0000000000..9b980ea1ea --- /dev/null +++ b/sdk/python/examples/controls/image/dynamic_svg/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-dynamic-svg" +version = "1.0.0" +description = "Animates an inline SVG image by updating ellipse dimensions over time." +requires-python = ">=3.10" +keywords = ["image", "svg", "dynamic svg", "animation", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Displaying a dynamic SVG image" +controls = ["SafeArea", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["inline svg generation", "async animation loop", "dynamic image updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/image/fade_in.py b/sdk/python/examples/controls/image/fade_in.py deleted file mode 100644 index d92a620668..0000000000 --- a/sdk/python/examples/controls/image/fade_in.py +++ /dev/null @@ -1,35 +0,0 @@ -import time - -import flet as ft - - -def main(page: ft.Page): - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def show_random(e: ft.Event[ft.Button]): - image.src = f"https://picsum.photos/320/200?random={time.time()}" # random - - page.add( - image := ft.Image( - src="https://picsum.photos/320/200?random=1", - width=360, - height=220, - fit=ft.BoxFit.COVER, - # solid blue image as bas64 - placeholder_src="data:image/png;base64,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", # noqa: E501 - placeholder_fade_out_animation=ft.Animation( - duration=ft.Duration(milliseconds=900), - curve=ft.AnimationCurve.EASE_OUT, - ), - fade_in_animation=ft.Animation( - duration=ft.Duration(milliseconds=700), - curve=ft.AnimationCurve.EASE_IN_OUT, - ), - ), - ft.Button("Show random image", on_click=show_random), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/image/fade_in/main.py b/sdk/python/examples/controls/image/fade_in/main.py new file mode 100644 index 0000000000..1fc7a187de --- /dev/null +++ b/sdk/python/examples/controls/image/fade_in/main.py @@ -0,0 +1,43 @@ +import time + +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def show_random(e: ft.Event[ft.Button]): + image.src = f"https://picsum.photos/320/200?random={time.time()}" # random + image.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + image := ft.Image( + src="https://picsum.photos/320/200?random=1", + width=360, + height=220, + fit=ft.BoxFit.COVER, + # solid blue image as bas64 + placeholder_src="data:image/png;base64,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", # noqa: E501 + placeholder_fade_out_animation=ft.Animation( + duration=ft.Duration(milliseconds=900), + curve=ft.AnimationCurve.EASE_OUT, + ), + fade_in_animation=ft.Animation( + duration=ft.Duration(milliseconds=700), + curve=ft.AnimationCurve.EASE_IN_OUT, + ), + ), + ft.Button("Show random image", on_click=show_random), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/image/fade_in/pyproject.toml b/sdk/python/examples/controls/image/fade_in/pyproject.toml new file mode 100644 index 0000000000..6ce30c1956 --- /dev/null +++ b/sdk/python/examples/controls/image/fade_in/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-fade-in" +version = "1.0.0" +description = "Loads random network images with placeholder and fade-in animations." +requires-python = ">=3.10" +keywords = ["image", "fade in", "placeholder", "animation", "network"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Fade-in images with a placeholder" +controls = ["SafeArea", "Column", "Image", "Button", "Animation", "Duration"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["placeholder image", "fade-in animation", "dynamic image source"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/image/gallery.py b/sdk/python/examples/controls/image/gallery.py deleted file mode 100644 index fb6d6bc2ce..0000000000 --- a/sdk/python/examples/controls/image/gallery.py +++ /dev/null @@ -1,33 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Image Example" - page.theme_mode = ft.ThemeMode.LIGHT - page.padding = 50 - - page.add( - ft.Image( - src="app_icon_512.png", - width=100, - height=100, - fit=ft.BoxFit.CONTAIN, - ), - gallery := ft.Row(expand=1, wrap=False, scroll=ft.ScrollMode.ALWAYS), - ) - - for i in range(0, 30): - gallery.controls.append( - ft.Image( - src=f"https://picsum.photos/200/200?{i}", - width=200, - height=200, - fit=ft.BoxFit.NONE, - repeat=ft.ImageRepeat.NO_REPEAT, - border_radius=ft.BorderRadius.all(10), - ) - ) - page.update() - - -ft.run(main) diff --git a/sdk/python/examples/controls/image/gallery/assets/app_icon_512.png b/sdk/python/examples/controls/image/gallery/assets/app_icon_512.png new file mode 100644 index 0000000000000000000000000000000000000000..f89a749adafe1a1306e9034cbb156ab99d2d5c1c GIT binary patch literal 21589 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 AD*ylh literal 0 HcmV?d00001 diff --git a/sdk/python/examples/controls/image/gallery/main.py b/sdk/python/examples/controls/image/gallery/main.py new file mode 100644 index 0000000000..4aacd340d1 --- /dev/null +++ b/sdk/python/examples/controls/image/gallery/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Image Example" + page.theme_mode = ft.ThemeMode.LIGHT + page.padding = 50 + + gallery = ft.Row(expand=True, wrap=False, scroll=ft.ScrollMode.ALWAYS) + + for i in range(0, 30): + gallery.controls.append( + ft.Image( + src=f"https://picsum.photos/200/200?{i}", + width=200, + height=200, + fit=ft.BoxFit.NONE, + repeat=ft.ImageRepeat.NO_REPEAT, + border_radius=ft.BorderRadius.all(10), + ) + ) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Image( + src="assets/app_icon_512.png", + width=100, + height=100, + fit=ft.BoxFit.CONTAIN, + ), + gallery, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/image/gallery/pyproject.toml b/sdk/python/examples/controls/image/gallery/pyproject.toml new file mode 100644 index 0000000000..b82b3765f2 --- /dev/null +++ b/sdk/python/examples/controls/image/gallery/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-gallery" +version = "1.0.0" +description = "Shows a local app icon and a horizontally scrollable gallery of remote images." +requires-python = ">=3.10" +keywords = ["image", "gallery", "scroll", "assets", "network images"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Image gallery" +controls = ["SafeArea", "Column", "Row", "Image"] +layout_pattern = "gallery" +complexity = "basic" +features = ["local asset image", "horizontal scrolling", "network image thumbnails"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/image/gapless_playback.py b/sdk/python/examples/controls/image/gapless_playback/main.py similarity index 52% rename from sdk/python/examples/controls/image/gapless_playback.py rename to sdk/python/examples/controls/image/gapless_playback/main.py index 0a3c4bc5fc..a6edc789f2 100644 --- a/sdk/python/examples/controls/image/gapless_playback.py +++ b/sdk/python/examples/controls/image/gapless_playback/main.py @@ -47,28 +47,40 @@ def next_photo(e: ft.Event[ft.Button]): new_src = get_new_image_src() image_with_gapless.src = new_src image_without_gapless.src = new_src - page.update() + image_with_gapless.update() + image_without_gapless.update() page.appbar = ft.AppBar(title="Gapless Playback Showcase") page.add( - ft.Text( - "Click 'Load next photo' to switch both images to a new URL.\n" - "The left/top image keeps showing the previous frame while loading the " - "next one. This is referred to as gapless playback.", - text_align=ft.TextAlign.CENTER, - ), - ft.Row( - wrap=True, - spacing=20, - run_spacing=20, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - image_panel("gapless_playback=True", image_with_gapless), - image_panel("gapless_playback=False", image_without_gapless), - ], - ), - ft.FilledButton("Load next photo", on_click=next_photo), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Click 'Load next photo' to switch both images to a new URL.\n" + "The left/top image keeps showing the previous frame while " + "loading " + "the next one. This is referred to as gapless playback.", + text_align=ft.TextAlign.CENTER, + ), + ft.Row( + wrap=True, + spacing=20, + run_spacing=20, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + image_panel("gapless_playback=True", image_with_gapless), + image_panel( + "gapless_playback=False", + image_without_gapless, + ), + ], + ), + ft.FilledButton("Load next photo", on_click=next_photo), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/image/gapless_playback/pyproject.toml b/sdk/python/examples/controls/image/gapless_playback/pyproject.toml new file mode 100644 index 0000000000..c2b1ef33b8 --- /dev/null +++ b/sdk/python/examples/controls/image/gapless_playback/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-gapless-playback" +version = "1.0.0" +description = "Compares Image gapless playback enabled vs disabled while switching sources." +requires-python = ">=3.10" +keywords = ["image", "gapless playback", "comparison", "network images"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Gapless playback when changing image sources" +controls = ["SafeArea", "Column", "Row", "Container", "Text", "Image", "FilledButton", "AppBar"] +layout_pattern = "comparison" +complexity = "basic" +features = ["gapless playback comparison", "dynamic image source switching"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/image/lucide_icons.py b/sdk/python/examples/controls/image/lucide_icons.py deleted file mode 100644 index 0301648aa6..0000000000 --- a/sdk/python/examples/controls/image/lucide_icons.py +++ /dev/null @@ -1,22 +0,0 @@ -import flet as ft - -""" -- Browse Lucide icons: https://lucide.dev/ -- Copy SVG and use it as value for `Image.src` -""" - - -def main(page: ft.Page): - page.add( - ft.Image( - src='', - color=ft.Colors.PINK, - ), - ft.Image( - src='', - color=ft.Colors.GREEN, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/image/lucide_icons/main.py b/sdk/python/examples/controls/image/lucide_icons/main.py new file mode 100644 index 0000000000..b21abe75e2 --- /dev/null +++ b/sdk/python/examples/controls/image/lucide_icons/main.py @@ -0,0 +1,29 @@ +import flet as ft + +""" +- Browse Lucide icons: https://lucide.dev/ +- Copy SVG and use it as value for `Image.src` +""" + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Image( + src='', # noqa: E501 + color=ft.Colors.PINK, + ), + ft.Image( + src='', # noqa: E501 + color=ft.Colors.GREEN, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/image/lucide_icons/pyproject.toml b/sdk/python/examples/controls/image/lucide_icons/pyproject.toml new file mode 100644 index 0000000000..70fce26f51 --- /dev/null +++ b/sdk/python/examples/controls/image/lucide_icons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-lucide-icons" +version = "1.0.0" +description = "Shows Lucide SVG icons rendered through Image with custom colors." +requires-python = ">=3.10" +keywords = ["image", "lucide", "svg icons", "inline svg"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Displaying a Lucide icon" +controls = ["SafeArea", "Row", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["inline svg icons", "icon color styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/image/src_base64_and_bytes.py b/sdk/python/examples/controls/image/src_base64_and_bytes/main.py similarity index 75% rename from sdk/python/examples/controls/image/src_base64_and_bytes.py rename to sdk/python/examples/controls/image/src_base64_and_bytes/main.py index 8d3895505b..be4ab3b798 100644 --- a/sdk/python/examples/controls/image/src_base64_and_bytes.py +++ b/sdk/python/examples/controls/image/src_base64_and_bytes/main.py @@ -5,22 +5,29 @@ def main(page: ft.Page): # image as base64 string - base64_src = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" + base64_src = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" # noqa: E501 # image as bytes bytes_src = base64.b64decode(base64_src) page.add( - ft.Image( - src=base64_src, - width=100, - height=100, - ), - ft.Image( - src=bytes_src, - width=100, - height=100, - ), + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Image( + src=base64_src, + width=100, + height=100, + ), + ft.Image( + src=bytes_src, + width=100, + height=100, + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/image/src_base64_and_bytes/pyproject.toml b/sdk/python/examples/controls/image/src_base64_and_bytes/pyproject.toml new file mode 100644 index 0000000000..accbac2bbd --- /dev/null +++ b/sdk/python/examples/controls/image/src_base64_and_bytes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-src-base64-and-bytes" +version = "1.0.0" +description = "Renders images from base64 string and decoded byte data sources." +requires-python = ">=3.10" +keywords = ["image", "base64", "bytes", "binary data"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Displaying images from base64 strings and byte data" +controls = ["SafeArea", "Row", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["base64 image source", "bytes image source"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/image/static_svg.py b/sdk/python/examples/controls/image/static_svg/main.py similarity index 63% rename from sdk/python/examples/controls/image/static_svg.py rename to sdk/python/examples/controls/image/static_svg/main.py index fd2e3b5ae1..c8cca29797 100644 --- a/sdk/python/examples/controls/image/static_svg.py +++ b/sdk/python/examples/controls/image/static_svg/main.py @@ -35,24 +35,41 @@ def main(page: ft.Page): """ page.add( - ft.Image( - src="https://raw.githubusercontent.com/dnfield/flutter_svg/master/packages/flutter_svg/example/assets/wikimedia/Firefox_Logo_2017.svg", - width=200, - height=200, - ), - ft.Image(src=svg_image, width=100, height=100, color=ft.Colors.RED), - ft.Image(src=svg_image, width=100, height=100, color=ft.Colors.BLUE), - ft.Container( - bgcolor=ft.Colors.BLACK_87, - border_radius=5, - content=ft.Image( - src=svg_image, - width=100, - height=100, - color=ft.Colors.WHITE, + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Image( + src="https://raw.githubusercontent.com/dnfield/flutter_svg/master/packages/flutter_svg/example/assets/wikimedia/Firefox_Logo_2017.svg", + width=200, + height=200, + ), + ft.Image( + src=svg_image, + width=100, + height=100, + color=ft.Colors.RED, + ), + ft.Image( + src=svg_image, + width=100, + height=100, + color=ft.Colors.BLUE, + ), + ft.Container( + bgcolor=ft.Colors.BLACK_87, + border_radius=5, + content=ft.Image( + src=svg_image, + width=100, + height=100, + color=ft.Colors.WHITE, + ), + ), + ], ), - ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/image/static_svg/pyproject.toml b/sdk/python/examples/controls/image/static_svg/pyproject.toml new file mode 100644 index 0000000000..ca8cd772f6 --- /dev/null +++ b/sdk/python/examples/controls/image/static_svg/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-static-svg" +version = "1.0.0" +description = "Displays static SVG images from network and inline SVG strings with color overrides." +requires-python = ">=3.10" +keywords = ["image", "svg", "static svg", "inline svg", "color"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Displaying a static SVG image" +controls = ["SafeArea", "Column", "Image", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["network svg", "inline svg", "svg color tinting"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/icon.md b/sdk/python/packages/flet/docs/controls/icon.md index c18f5d03a7..de568efd9d 100644 --- a/sdk/python/packages/flet/docs/controls/icon.md +++ b/sdk/python/packages/flet/docs/controls/icon.md @@ -17,7 +17,7 @@ visit our [icons browser](https://examples.flet.dev/icons_browser/) ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/iconbutton.md b/sdk/python/packages/flet/docs/controls/iconbutton.md index b3a61b2eab..485e4bc9ab 100644 --- a/sdk/python/packages/flet/docs/controls/iconbutton.md +++ b/sdk/python/packages/flet/docs/controls/iconbutton.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/icon_button/media ### Handling clicks ```python ---8<-- "{{ examples }}/handling_clicks.py" +--8<-- "{{ examples }}/handling_clicks/main.py" ``` {{ image(example_media + "/handling_clicks.gif", alt="handling-clicks", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/icon_button/media ### Selected icon ```python ---8<-- "{{ examples }}/selected_icon.py" +--8<-- "{{ examples }}/selected_icon/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/image.md b/sdk/python/packages/flet/docs/controls/image.md index d133e6937c..1d13190d6c 100644 --- a/sdk/python/packages/flet/docs/controls/image.md +++ b/sdk/python/packages/flet/docs/controls/image.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/image/media ### Image gallery ```python ---8<-- "{{ examples }}/gallery.py" +--8<-- "{{ examples }}/gallery/main.py" ``` {{ image(example_media + "/gallery.gif", width="80%") }} @@ -22,31 +22,31 @@ example_media: ../examples/controls/image/media ### Fade-in images with a placeholder ```python ---8<-- "{{ examples }}/fade_in.py" +--8<-- "{{ examples }}/fade_in/main.py" ``` ### Displaying images from base64 strings and byte data ```python ---8<-- "{{ examples }}/src_base64_and_bytes.py" +--8<-- "{{ examples }}/src_base64_and_bytes/main.py" ``` ### Displaying a static SVG image ```python ---8<-- "{{ examples }}/static_svg.py" +--8<-- "{{ examples }}/static_svg/main.py" ``` ### Displaying a dynamic SVG image ```python ---8<-- "{{ examples }}/dynamic_svg.py" +--8<-- "{{ examples }}/dynamic_svg/main.py" ``` ### Displaying a Lucide icon ```python ---8<-- "{{ examples }}/lucide_icons.py" +--8<-- "{{ examples }}/lucide_icons/main.py" ``` ### Gapless playback when changing image sources @@ -57,7 +57,7 @@ image loads. With [`gapless_playback`][flet.Image.gapless_playback] set to `Fals briefly be empty, causing a flicker/blink effect. ```python ---8<-- "{{ examples }}/gapless_playback.py" +--8<-- "{{ examples }}/gapless_playback/main.py" ``` {{ class_members(class_name) }} From 35ac8077faf3dccfe046128215aa8709644c7518 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 16:24:02 -0700 Subject: [PATCH 53/96] Restructure Python examples into main modules Replace many single-file example scripts with package-style examples: delete legacy .py example files and add main.py entrypoints plus pyproject.toml metadata for each example. Wrap UIs in SafeArea/Column, add explicit .update() calls where needed, and adjust layout/control usage. Add bursting_flet asset (icon-192.png). Also update related docs and an integration test to reflect the new examples structure. --- .../interactive_viewer/handling_events.py | 20 ---- .../handling_events/main.py | 21 ++++ .../handling_events/pyproject.toml | 26 +++++ .../interactive_viewer/transformations.py | 51 ---------- .../transformations/main.py | 58 +++++++++++ .../transformations/pyproject.toml | 26 +++++ .../controls/keyboard_listener/detect_keys.py | 26 ----- .../keyboard_listener/detect_keys/main.py | 35 +++++++ .../detect_keys/pyproject.toml | 26 +++++ .../controls/layout_control/animate_align.py | 26 ----- .../layout_control/animate_align/main.py | 32 ++++++ .../animate_align/pyproject.toml | 26 +++++ .../controls/layout_control/animate_margin.py | 28 ------ .../layout_control/animate_margin/main.py | 37 +++++++ .../animate_margin/pyproject.toml | 26 +++++ .../controls/layout_control/animate_offset.py | 25 ----- .../layout_control/animate_offset/main.py | 32 ++++++ .../animate_offset/pyproject.toml | 26 +++++ .../layout_control/animate_opacity.py | 24 ----- .../layout_control/animate_opacity/main.py | 31 ++++++ .../animate_opacity/pyproject.toml | 26 +++++ .../layout_control/animate_position.py | 43 -------- .../layout_control/animate_position/main.py | 53 ++++++++++ .../animate_position/pyproject.toml | 26 +++++ .../layout_control/animate_rotation.py | 30 ------ .../layout_control/animate_rotation/main.py | 39 ++++++++ .../animate_rotation/pyproject.toml | 26 +++++ .../controls/layout_control/animate_scale.py | 29 ------ .../layout_control/animate_scale/main.py | 37 +++++++ .../animate_scale/pyproject.toml | 26 +++++ .../controls/layout_control/bursting_flet.py | 32 ------ .../bursting_flet/assets/icon-192.png | Bin 0 -> 6622 bytes .../layout_control/bursting_flet/main.py | 41 ++++++++ .../bursting_flet/pyproject.toml | 26 +++++ .../examples/controls/layout_control/flip.py | 41 -------- .../controls/layout_control/flip/main.py | 49 +++++++++ .../layout_control/flip/pyproject.toml | 26 +++++ .../layout_control/image_slideshow.py | 37 ------- .../layout_control/image_slideshow/main.py | 44 +++++++++ .../image_slideshow/pyproject.toml | 26 +++++ .../layout_control/matrix4_transform.py | 81 --------------- .../layout_control/matrix4_transform/main.py | 93 ++++++++++++++++++ .../matrix4_transform/pyproject.toml | 26 +++++ .../controls/layout_control/offset.py | 65 ------------ .../controls/layout_control/offset/main.py | 71 +++++++++++++ .../layout_control/offset/pyproject.toml | 26 +++++ .../controls/layout_control/rocket.py | 45 --------- .../controls/layout_control/rocket/main.py | 48 +++++++++ .../layout_control/rocket/pyproject.toml | 26 +++++ .../controls/layout_control/rotate.py | 27 ----- .../controls/layout_control/rotate/main.py | 29 ++++++ .../layout_control/rotate/pyproject.toml | 26 +++++ .../examples/controls/layout_control/scale.py | 26 ----- .../controls/layout_control/scale/main.py | 28 ++++++ .../layout_control/scale/pyproject.toml | 26 +++++ .../controls/layout_control/switcher.py | 39 -------- .../controls/layout_control/switcher/main.py | 52 ++++++++++ .../layout_control/switcher/pyproject.toml | 26 +++++ .../flet/docs/controls/interactiveviewer.md | 4 +- .../flet/docs/controls/keyboardlistener.md | 2 +- .../flet/docs/controls/layoutcontrol.md | 10 +- .../packages/flet/docs/cookbook/animations.md | 10 +- .../examples/core/test_layout_control.py | 3 +- 63 files changed, 1339 insertions(+), 709 deletions(-) delete mode 100644 sdk/python/examples/controls/interactive_viewer/handling_events.py create mode 100644 sdk/python/examples/controls/interactive_viewer/handling_events/main.py create mode 100644 sdk/python/examples/controls/interactive_viewer/handling_events/pyproject.toml delete mode 100644 sdk/python/examples/controls/interactive_viewer/transformations.py create mode 100644 sdk/python/examples/controls/interactive_viewer/transformations/main.py create mode 100644 sdk/python/examples/controls/interactive_viewer/transformations/pyproject.toml delete mode 100644 sdk/python/examples/controls/keyboard_listener/detect_keys.py create mode 100644 sdk/python/examples/controls/keyboard_listener/detect_keys/main.py create mode 100644 sdk/python/examples/controls/keyboard_listener/detect_keys/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/animate_align.py create mode 100644 sdk/python/examples/controls/layout_control/animate_align/main.py create mode 100644 sdk/python/examples/controls/layout_control/animate_align/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/animate_margin.py create mode 100644 sdk/python/examples/controls/layout_control/animate_margin/main.py create mode 100644 sdk/python/examples/controls/layout_control/animate_margin/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/animate_offset.py create mode 100644 sdk/python/examples/controls/layout_control/animate_offset/main.py create mode 100644 sdk/python/examples/controls/layout_control/animate_offset/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/animate_opacity.py create mode 100644 sdk/python/examples/controls/layout_control/animate_opacity/main.py create mode 100644 sdk/python/examples/controls/layout_control/animate_opacity/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/animate_position.py create mode 100644 sdk/python/examples/controls/layout_control/animate_position/main.py create mode 100644 sdk/python/examples/controls/layout_control/animate_position/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/animate_rotation.py create mode 100644 sdk/python/examples/controls/layout_control/animate_rotation/main.py create mode 100644 sdk/python/examples/controls/layout_control/animate_rotation/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/animate_scale.py create mode 100644 sdk/python/examples/controls/layout_control/animate_scale/main.py create mode 100644 sdk/python/examples/controls/layout_control/animate_scale/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/bursting_flet.py create mode 100644 sdk/python/examples/controls/layout_control/bursting_flet/assets/icon-192.png create mode 100644 sdk/python/examples/controls/layout_control/bursting_flet/main.py create mode 100644 sdk/python/examples/controls/layout_control/bursting_flet/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/flip.py create mode 100644 sdk/python/examples/controls/layout_control/flip/main.py create mode 100644 sdk/python/examples/controls/layout_control/flip/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/image_slideshow.py create mode 100644 sdk/python/examples/controls/layout_control/image_slideshow/main.py create mode 100644 sdk/python/examples/controls/layout_control/image_slideshow/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/matrix4_transform.py create mode 100644 sdk/python/examples/controls/layout_control/matrix4_transform/main.py create mode 100644 sdk/python/examples/controls/layout_control/matrix4_transform/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/offset.py create mode 100644 sdk/python/examples/controls/layout_control/offset/main.py create mode 100644 sdk/python/examples/controls/layout_control/offset/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/rocket.py create mode 100644 sdk/python/examples/controls/layout_control/rocket/main.py create mode 100644 sdk/python/examples/controls/layout_control/rocket/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/rotate.py create mode 100644 sdk/python/examples/controls/layout_control/rotate/main.py create mode 100644 sdk/python/examples/controls/layout_control/rotate/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/scale.py create mode 100644 sdk/python/examples/controls/layout_control/scale/main.py create mode 100644 sdk/python/examples/controls/layout_control/scale/pyproject.toml delete mode 100644 sdk/python/examples/controls/layout_control/switcher.py create mode 100644 sdk/python/examples/controls/layout_control/switcher/main.py create mode 100644 sdk/python/examples/controls/layout_control/switcher/pyproject.toml diff --git a/sdk/python/examples/controls/interactive_viewer/handling_events.py b/sdk/python/examples/controls/interactive_viewer/handling_events.py deleted file mode 100644 index 0aa1c3b8fe..0000000000 --- a/sdk/python/examples/controls/interactive_viewer/handling_events.py +++ /dev/null @@ -1,20 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.InteractiveViewer( - min_scale=0.1, - max_scale=15, - boundary_margin=ft.Margin.all(20), - on_interaction_start=lambda e: print(e), - on_interaction_end=lambda e: print(e), - on_interaction_update=lambda e: print(e), - content=ft.Image( - src="https://picsum.photos/500/500", - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/interactive_viewer/handling_events/main.py b/sdk/python/examples/controls/interactive_viewer/handling_events/main.py new file mode 100644 index 0000000000..7acd572406 --- /dev/null +++ b/sdk/python/examples/controls/interactive_viewer/handling_events/main.py @@ -0,0 +1,21 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.InteractiveViewer( + min_scale=0.1, + max_scale=15, + boundary_margin=ft.Margin.all(20), + on_interaction_start=lambda e: print(e), + on_interaction_end=lambda e: print(e), + on_interaction_update=lambda e: print(e), + content=ft.Image(src="https://picsum.photos/500/500"), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/interactive_viewer/handling_events/pyproject.toml b/sdk/python/examples/controls/interactive_viewer/handling_events/pyproject.toml new file mode 100644 index 0000000000..6ea1bbbeb7 --- /dev/null +++ b/sdk/python/examples/controls/interactive_viewer/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "interactive-viewer-handling-events" +version = "1.0.0" +description = "Logs start, update, and end callbacks while panning and zooming an InteractiveViewer image." +requires-python = ">=3.10" +keywords = ["interactive viewer", "events", "zoom", "pan", "image"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/InteractiveViewer"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "InteractiveViewer", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["interaction event callbacks", "pinch zoom", "panning"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/interactive_viewer/transformations.py b/sdk/python/examples/controls/interactive_viewer/transformations.py deleted file mode 100644 index 4ffb2d71fc..0000000000 --- a/sdk/python/examples/controls/interactive_viewer/transformations.py +++ /dev/null @@ -1,51 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - async def handle_zoom_in(e: ft.Event[ft.Button]): - await i.zoom(1.2) - - async def handle_zoom_out(e: ft.Event[ft.Button]): - await i.zoom(0.8) - - async def handle_pan(e: ft.Event[ft.Button]): - await i.pan(dx=50, dy=50) - - async def handle_reset(e: ft.Event[ft.Button]): - await i.reset() - - async def handle_reset_slow(e: ft.Event[ft.Button]): - await i.reset(animation_duration=ft.Duration(seconds=2)) - - async def handle_save_state(e: ft.Event[ft.Button]): - await i.save_state() - - async def handle_restore_state(e: ft.Event[ft.Button]): - await i.restore_state() - - page.add( - i := ft.InteractiveViewer( - min_scale=0.1, - max_scale=5, - boundary_margin=ft.Margin.all(20), - content=ft.Image(src="https://picsum.photos/500/500"), - ), - ft.Row( - wrap=True, - controls=[ - ft.Button("Zoom In", on_click=handle_zoom_in), - ft.Button("Zoom Out", on_click=handle_zoom_out), - ft.Button("Pan", on_click=handle_pan), - ft.Button("Save State", on_click=handle_save_state), - ft.Button("Restore State", on_click=handle_restore_state), - ft.Button("Reset (instant)", on_click=handle_reset), - ft.Button("Reset (slow)", on_click=handle_reset_slow), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/interactive_viewer/transformations/main.py b/sdk/python/examples/controls/interactive_viewer/transformations/main.py new file mode 100644 index 0000000000..70366436d0 --- /dev/null +++ b/sdk/python/examples/controls/interactive_viewer/transformations/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + async def handle_zoom_in(e: ft.Event[ft.Button]): + await i.zoom(1.2) + + async def handle_zoom_out(e: ft.Event[ft.Button]): + await i.zoom(0.8) + + async def handle_pan(e: ft.Event[ft.Button]): + await i.pan(dx=50, dy=50) + + async def handle_reset(e: ft.Event[ft.Button]): + await i.reset() + + async def handle_reset_slow(e: ft.Event[ft.Button]): + await i.reset(animation_duration=ft.Duration(seconds=2)) + + async def handle_save_state(e: ft.Event[ft.Button]): + await i.save_state() + + async def handle_restore_state(e: ft.Event[ft.Button]): + await i.restore_state() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + i := ft.InteractiveViewer( + min_scale=0.1, + max_scale=5, + boundary_margin=ft.Margin.all(20), + content=ft.Image(src="https://picsum.photos/500/500"), + ), + ft.Row( + wrap=True, + controls=[ + ft.Button("Zoom In", on_click=handle_zoom_in), + ft.Button("Zoom Out", on_click=handle_zoom_out), + ft.Button("Pan", on_click=handle_pan), + ft.Button("Save State", on_click=handle_save_state), + ft.Button("Restore State", on_click=handle_restore_state), + ft.Button("Reset (instant)", on_click=handle_reset), + ft.Button("Reset (slow)", on_click=handle_reset_slow), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/interactive_viewer/transformations/pyproject.toml b/sdk/python/examples/controls/interactive_viewer/transformations/pyproject.toml new file mode 100644 index 0000000000..6c02a8375f --- /dev/null +++ b/sdk/python/examples/controls/interactive_viewer/transformations/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "interactive-viewer-transformations" +version = "1.0.0" +description = "Applies InteractiveViewer programmatic zoom, pan, save/restore state, and reset actions." +requires-python = ">=3.10" +keywords = ["interactive viewer", "transformations", "zoom", "pan", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/InteractiveViewer"] + +[tool.flet.metadata] +title = "Programmatic transformations" +controls = ["SafeArea", "Column", "Row", "InteractiveViewer", "Image", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["programmatic zoom", "programmatic pan", "save and restore state", "animated reset"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/keyboard_listener/detect_keys.py b/sdk/python/examples/controls/keyboard_listener/detect_keys.py deleted file mode 100644 index 1a2655b151..0000000000 --- a/sdk/python/examples/controls/keyboard_listener/detect_keys.py +++ /dev/null @@ -1,26 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - pressed_keys = set() - - def key_down(e: ft.KeyDownEvent): - pressed_keys.add(e.key) - keys.controls = [ft.Text(k, size=20) for k in pressed_keys] - - def key_up(e: ft.KeyUpEvent): - pressed_keys.remove(e.key) - keys.controls = [ft.Text(k, size=20) for k in pressed_keys] - - page.add( - ft.Text("Press any keys..."), - ft.KeyboardListener( - content=(keys := ft.Row()), - autofocus=True, - on_key_down=key_down, - on_key_up=key_up, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/keyboard_listener/detect_keys/main.py b/sdk/python/examples/controls/keyboard_listener/detect_keys/main.py new file mode 100644 index 0000000000..c251f16bbc --- /dev/null +++ b/sdk/python/examples/controls/keyboard_listener/detect_keys/main.py @@ -0,0 +1,35 @@ +import flet as ft + + +async def main(page: ft.Page): + pressed_keys = set() + + def key_down(e: ft.KeyDownEvent): + pressed_keys.add(e.key) + keys.controls = [ft.Text(k, size=20) for k in pressed_keys] + keys.update() + + def key_up(e: ft.KeyUpEvent): + pressed_keys.remove(e.key) + keys.controls = [ft.Text(k, size=20) for k in pressed_keys] + keys.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Press any keys..."), + ft.KeyboardListener( + autofocus=True, + on_key_down=key_down, + on_key_up=key_up, + content=(keys := ft.Row()), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/keyboard_listener/detect_keys/pyproject.toml b/sdk/python/examples/controls/keyboard_listener/detect_keys/pyproject.toml new file mode 100644 index 0000000000..ef8e6d6f7d --- /dev/null +++ b/sdk/python/examples/controls/keyboard_listener/detect_keys/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "keyboard-listener-detect-keys" +version = "1.0.0" +description = "Tracks pressed keys with KeyboardListener and shows active keys in real time." +requires-python = ">=3.10" +keywords = ["keyboard listener", "keyboard", "key down", "key up", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/KeyboardListener"] + +[tool.flet.metadata] +title = "Press any keys" +controls = ["SafeArea", "Column", "KeyboardListener", "Row", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["key down and key up handling", "active key list", "keyboard focus"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/animate_align.py b/sdk/python/examples/controls/layout_control/animate_align.py deleted file mode 100644 index 36cb8d9fa5..0000000000 --- a/sdk/python/examples/controls/layout_control/animate_align.py +++ /dev/null @@ -1,26 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate_click(): - txt.align = ft.Alignment.TOP_LEFT - - page.add( - ft.Stack( - width=200, - height=200, - controls=[ - ( - txt := ft.Text( - "Hello, Flet!", - align=ft.Alignment.BOTTOM_RIGHT, - animate_align=1000, - ) - ) - ], - ), - ft.Button("Animate align", on_click=animate_click), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_align/main.py b/sdk/python/examples/controls/layout_control/animate_align/main.py new file mode 100644 index 0000000000..6a79ab3c94 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_align/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_click(e: ft.Event[ft.Button]): + txt.align = ft.Alignment.TOP_LEFT + txt.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Stack( + width=200, + height=200, + controls=[ + txt := ft.Text( + "Hello, Flet!", + align=ft.Alignment.BOTTOM_RIGHT, + animate_align=1000, + ) + ], + ), + ft.Button("Animate align", on_click=animate_click), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_align/pyproject.toml b/sdk/python/examples/controls/layout_control/animate_align/pyproject.toml new file mode 100644 index 0000000000..5a719c7158 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_align/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-align" +version = "1.0.0" +description = "Animates Text alignment within a Stack using animate_align." +requires-python = ">=3.10" +keywords = ["layout control", "animate align", "text", "stack"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate align" +controls = ["SafeArea", "Column", "Stack", "Text", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["alignment animation", "button-triggered transition"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/animate_margin.py b/sdk/python/examples/controls/layout_control/animate_margin.py deleted file mode 100644 index 28d1e34f71..0000000000 --- a/sdk/python/examples/controls/layout_control/animate_margin.py +++ /dev/null @@ -1,28 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate_click(): - c.margin = 0 - txt.margin = ft.Margin.only(left=50, top=70) - - page.add( - c := ft.Container( - width=200, - height=200, - bgcolor=ft.Colors.AMBER, - margin=40, - animate=True, - content=( - txt := ft.Text( - "Hello, Flet!", - margin=20, - animate_margin=1000, - ) - ), - ), - ft.Button("Animate margin", on_click=animate_click), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_margin/main.py b/sdk/python/examples/controls/layout_control/animate_margin/main.py new file mode 100644 index 0000000000..db328a0c9b --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_margin/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_click(e: ft.Event[ft.Button]): + c.margin = 0 + txt.margin = ft.Margin.only(left=50, top=70) + c.update() + txt.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + c := ft.Container( + width=200, + height=200, + bgcolor=ft.Colors.AMBER, + margin=40, + animate=True, + content=( + txt := ft.Text( + "Hello, Flet!", + margin=20, + animate_margin=1000, + ) + ), + ), + ft.Button("Animate margin", on_click=animate_click), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_margin/pyproject.toml b/sdk/python/examples/controls/layout_control/animate_margin/pyproject.toml new file mode 100644 index 0000000000..18b08944a6 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_margin/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-margin" +version = "1.0.0" +description = "Animates container and text margins to show layout spacing transitions." +requires-python = ">=3.10" +keywords = ["layout control", "animate margin", "container", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate margin" +controls = ["SafeArea", "Column", "Container", "Text", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["margin animation", "container animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/animate_offset.py b/sdk/python/examples/controls/layout_control/animate_offset.py deleted file mode 100644 index 0d9e6b5bfe..0000000000 --- a/sdk/python/examples/controls/layout_control/animate_offset.py +++ /dev/null @@ -1,25 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate(e: ft.Event[ft.Button]): - container.offset = ft.Offset(0, 0) - container.update() - - page.add( - container := ft.Container( - width=150, - height=150, - bgcolor=ft.Colors.BLUE, - border_radius=ft.BorderRadius.all(10), - offset=ft.Offset(x=-1.1, y=0), - animate_offset=ft.Animation( - duration=600, - curve=ft.AnimationCurve.BOUNCE_OUT, - ), - ), - ft.Button("Reveal!", on_click=animate), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_offset/main.py b/sdk/python/examples/controls/layout_control/animate_offset/main.py new file mode 100644 index 0000000000..e66a89701b --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_offset/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + container.offset = ft.Offset(0, 0) + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + container := ft.Container( + width=150, + height=150, + bgcolor=ft.Colors.BLUE, + border_radius=ft.BorderRadius.all(10), + offset=ft.Offset(x=-1.1, y=0), + animate_offset=ft.Animation( + duration=600, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + ft.Button("Reveal!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_offset/pyproject.toml b/sdk/python/examples/controls/layout_control/animate_offset/pyproject.toml new file mode 100644 index 0000000000..6937d6d1aa --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_offset/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-offset" +version = "1.0.0" +description = "Reveals a container by animating its offset from off-screen to visible." +requires-python = ">=3.10" +keywords = ["layout control", "animate offset", "container", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate offset" +controls = ["SafeArea", "Column", "Container", "Button", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["offset animation", "slide-in reveal"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/animate_opacity.py b/sdk/python/examples/controls/layout_control/animate_opacity.py deleted file mode 100644 index 9f1f6492f9..0000000000 --- a/sdk/python/examples/controls/layout_control/animate_opacity.py +++ /dev/null @@ -1,24 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate_opacity(e: ft.Event[ft.Button]): - container.opacity = 0 if container.opacity == 1 else 1 - container.update() - - page.add( - container := ft.Container( - width=150, - height=150, - bgcolor=ft.Colors.BLUE, - border_radius=10, - animate_opacity=300, - ), - ft.Button( - content="Animate opacity", - on_click=animate_opacity, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_opacity/main.py b/sdk/python/examples/controls/layout_control/animate_opacity/main.py new file mode 100644 index 0000000000..b5e28999f8 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_opacity/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_opacity(e: ft.Event[ft.Button]): + container.opacity = 0 if container.opacity == 1 else 1 + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + container := ft.Container( + width=150, + height=150, + bgcolor=ft.Colors.BLUE, + border_radius=10, + animate_opacity=300, + ), + ft.Button( + content="Animate opacity", + on_click=animate_opacity, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_opacity/pyproject.toml b/sdk/python/examples/controls/layout_control/animate_opacity/pyproject.toml new file mode 100644 index 0000000000..e573462b70 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_opacity/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-opacity" +version = "1.0.0" +description = "Toggles a container between visible and transparent states with animate_opacity." +requires-python = ">=3.10" +keywords = ["layout control", "animate opacity", "container", "fade"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate opacity" +controls = ["SafeArea", "Column", "Container", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["opacity animation", "fade toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/animate_position.py b/sdk/python/examples/controls/layout_control/animate_position.py deleted file mode 100644 index 3cdfee2cca..0000000000 --- a/sdk/python/examples/controls/layout_control/animate_position.py +++ /dev/null @@ -1,43 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate_container(e: ft.Event[ft.Button]): - c1.top = 20 - c1.left = 200 - c2.top = 100 - c2.left = 40 - c3.top = 180 - c3.left = 100 - page.update() - - page.add( - ft.Stack( - height=400, - controls=[ - c1 := ft.Container( - width=50, height=50, bgcolor="red", animate_position=1000 - ), - c2 := ft.Container( - width=50, - height=50, - bgcolor="green", - top=60, - left=0, - animate_position=500, - ), - c3 := ft.Container( - width=50, - height=50, - bgcolor="blue", - top=120, - left=0, - animate_position=1000, - ), - ], - ), - ft.Button("Animate!", on_click=animate_container), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_position/main.py b/sdk/python/examples/controls/layout_control/animate_position/main.py new file mode 100644 index 0000000000..56474d8504 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_position/main.py @@ -0,0 +1,53 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_container(e: ft.Event[ft.Button]): + c1.top = 20 + c1.left = 200 + c2.top = 100 + c2.left = 40 + c3.top = 180 + c3.left = 100 + stack.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + stack := ft.Stack( + height=400, + controls=[ + c1 := ft.Container( + width=50, + height=50, + bgcolor="red", + animate_position=1000, + ), + c2 := ft.Container( + width=50, + height=50, + bgcolor="green", + top=60, + left=0, + animate_position=500, + ), + c3 := ft.Container( + width=50, + height=50, + bgcolor="blue", + top=120, + left=0, + animate_position=1000, + ), + ], + ), + ft.Button("Animate!", on_click=animate_container), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_position/pyproject.toml b/sdk/python/examples/controls/layout_control/animate_position/pyproject.toml new file mode 100644 index 0000000000..b393a63ec4 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_position/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-position" +version = "1.0.0" +description = "Animates top/left positions of multiple containers inside a Stack." +requires-python = ">=3.10" +keywords = ["layout control", "animate position", "stack", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate position" +controls = ["SafeArea", "Column", "Stack", "Container", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["position animation", "multi-control movement"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/animate_rotation.py b/sdk/python/examples/controls/layout_control/animate_rotation.py deleted file mode 100644 index ef7921cb04..0000000000 --- a/sdk/python/examples/controls/layout_control/animate_rotation.py +++ /dev/null @@ -1,30 +0,0 @@ -from math import pi - -import flet as ft - - -def main(page: ft.Page): - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.spacing = 30 - - def animate(e: ft.Event[ft.Button]): - container.rotate.angle += pi / 2 - page.update() - - page.add( - container := ft.Container( - width=100, - height=70, - bgcolor=ft.Colors.BLUE, - border_radius=5, - rotate=ft.Rotate(angle=0, alignment=ft.Alignment.CENTER), - animate_rotation=ft.Animation( - duration=300, curve=ft.AnimationCurve.BOUNCE_OUT - ), - ), - ft.Button("Animate!", on_click=animate), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_rotation/main.py b/sdk/python/examples/controls/layout_control/animate_rotation/main.py new file mode 100644 index 0000000000..ac3adda8ce --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_rotation/main.py @@ -0,0 +1,39 @@ +from math import pi + +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 30 + + def animate(e: ft.Event[ft.Button]): + container.rotate.angle += pi / 2 + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + container := ft.Container( + width=100, + height=70, + bgcolor=ft.Colors.BLUE, + border_radius=5, + rotate=ft.Rotate(angle=0, alignment=ft.Alignment.CENTER), + animate_rotation=ft.Animation( + duration=300, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + ft.Button("Animate!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_rotation/pyproject.toml b/sdk/python/examples/controls/layout_control/animate_rotation/pyproject.toml new file mode 100644 index 0000000000..62256eecaa --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_rotation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-rotation" +version = "1.0.0" +description = "Rotates a container in quarter turns with animate_rotation and bounce curve." +requires-python = ">=3.10" +keywords = ["layout control", "animate rotation", "container", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate rotation" +controls = ["SafeArea", "Column", "Container", "Button", "Rotate", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["rotation animation", "incremental angle updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/animate_scale.py b/sdk/python/examples/controls/layout_control/animate_scale.py deleted file mode 100644 index 828c69ee8b..0000000000 --- a/sdk/python/examples/controls/layout_control/animate_scale.py +++ /dev/null @@ -1,29 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.spacing = 30 - - def animate(e: ft.Event[ft.Button]): - container.scale = 2 if container.scale == 1 else 1 - page.update() - - page.add( - container := ft.Container( - width=100, - height=100, - bgcolor=ft.Colors.BLUE, - border_radius=5, - scale=1, - animate_scale=ft.Animation( - duration=600, - curve=ft.AnimationCurve.BOUNCE_OUT, - ), - ), - ft.Button("Animate!", on_click=animate), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_scale/main.py b/sdk/python/examples/controls/layout_control/animate_scale/main.py new file mode 100644 index 0000000000..abd4cfa7cd --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_scale/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 30 + + def animate(e: ft.Event[ft.Button]): + container.scale = 2 if container.scale == 1 else 1 + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + container := ft.Container( + width=100, + height=100, + bgcolor=ft.Colors.BLUE, + border_radius=5, + scale=1, + animate_scale=ft.Animation( + duration=600, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + ft.Button("Animate!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/animate_scale/pyproject.toml b/sdk/python/examples/controls/layout_control/animate_scale/pyproject.toml new file mode 100644 index 0000000000..a95f5e19aa --- /dev/null +++ b/sdk/python/examples/controls/layout_control/animate_scale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-scale" +version = "1.0.0" +description = "Animates container scale between normal and enlarged sizes." +requires-python = ">=3.10" +keywords = ["layout control", "animate scale", "container", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate scale" +controls = ["SafeArea", "Column", "Container", "Button", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["scale animation", "toggle scaling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/bursting_flet.py b/sdk/python/examples/controls/layout_control/bursting_flet.py deleted file mode 100644 index 19cb334506..0000000000 --- a/sdk/python/examples/controls/layout_control/bursting_flet.py +++ /dev/null @@ -1,32 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def animate(e: ft.Event[ft.Button]): - image.scale = 30 - image.opacity = 0 - image.update() - - page.add( - ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - image := ft.Image( - src="icon-192.png", - width=100, - height=100, - scale=1.0, - animate_scale=ft.Animation(300, ft.AnimationCurve.EASE_IN_QUINT), - opacity=1.0, - animate_opacity=ft.Animation(300, ft.AnimationCurve.EASE_IN_QUINT), - ), - ft.Button("Boom!", on_click=animate), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/bursting_flet/assets/icon-192.png b/sdk/python/examples/controls/layout_control/bursting_flet/assets/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..65da3b95714aabb579c7bd1e5a7a5dc6d1512d43 GIT binary patch literal 6622 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 literal 0 HcmV?d00001 diff --git a/sdk/python/examples/controls/layout_control/bursting_flet/main.py b/sdk/python/examples/controls/layout_control/bursting_flet/main.py new file mode 100644 index 0000000000..9106c60f9e --- /dev/null +++ b/sdk/python/examples/controls/layout_control/bursting_flet/main.py @@ -0,0 +1,41 @@ +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def animate(e: ft.Event[ft.Button]): + image.scale = 30 + image.opacity = 0 + image.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + image := ft.Image( + src="icon-192.png", + width=100, + height=100, + scale=1.0, + animate_scale=ft.Animation( + 300, + ft.AnimationCurve.EASE_IN_QUINT, + ), + opacity=1.0, + animate_opacity=ft.Animation( + 300, + ft.AnimationCurve.EASE_IN_QUINT, + ), + ), + ft.Button("Boom!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/bursting_flet/pyproject.toml b/sdk/python/examples/controls/layout_control/bursting_flet/pyproject.toml new file mode 100644 index 0000000000..49921d2d3c --- /dev/null +++ b/sdk/python/examples/controls/layout_control/bursting_flet/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-bursting-flet" +version = "1.0.0" +description = "Creates a burst effect by rapidly scaling and fading the Flet icon image." +requires-python = ">=3.10" +keywords = ["layout control", "image", "scale", "opacity", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Bursting flet" +controls = ["SafeArea", "Column", "Image", "Button", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["combined scale and opacity animations", "asset image animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/flip.py b/sdk/python/examples/controls/layout_control/flip.py deleted file mode 100644 index 815706a062..0000000000 --- a/sdk/python/examples/controls/layout_control/flip.py +++ /dev/null @@ -1,41 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.spacing = 20 - - def toggle_x(e: ft.Event[ft.Button]): - card.flip.flip_x = not card.flip.flip_x - page.update() - - def toggle_y(e: ft.Event[ft.Button]): - card.flip.flip_y = not card.flip.flip_y - page.update() - - page.add( - card := ft.Container( - width=220, - height=120, - bgcolor=ft.Colors.BLUE_300, - border_radius=16, - alignment=ft.Alignment.CENTER, - content=ft.Text("Flip me", size=24, weight=ft.FontWeight.BOLD), - flip=ft.Flip( - flip_x=False, - flip_y=False, - filter_quality=ft.FilterQuality.MEDIUM, - ), - ), - ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - ft.Button("Toggle X", on_click=toggle_x), - ft.Button("Toggle Y", on_click=toggle_y), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/flip/main.py b/sdk/python/examples/controls/layout_control/flip/main.py new file mode 100644 index 0000000000..3abd87179e --- /dev/null +++ b/sdk/python/examples/controls/layout_control/flip/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 20 + + def toggle_x(e: ft.Event[ft.Button]): + card.flip.flip_x = not card.flip.flip_x + card.update() + + def toggle_y(e: ft.Event[ft.Button]): + card.flip.flip_y = not card.flip.flip_y + card.update() + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=20, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + card := ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.BLUE_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Flip me", size=24, weight=ft.FontWeight.BOLD), + flip=ft.Flip( + flip_x=False, + flip_y=False, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Button("Toggle X", on_click=toggle_x), + ft.Button("Toggle Y", on_click=toggle_y), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/flip/pyproject.toml b/sdk/python/examples/controls/layout_control/flip/pyproject.toml new file mode 100644 index 0000000000..683de547da --- /dev/null +++ b/sdk/python/examples/controls/layout_control/flip/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-flip" +version = "1.0.0" +description = "Toggles flip_x and flip_y on a card using LayoutControl flip transform." +requires-python = ">=3.10" +keywords = ["layout control", "flip", "transform", "card"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Flip" +controls = ["SafeArea", "Column", "Container", "Text", "Flip", "Row", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["flip_x toggle", "flip_y toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/image_slideshow.py b/sdk/python/examples/controls/layout_control/image_slideshow.py deleted file mode 100644 index 5f14ae33f3..0000000000 --- a/sdk/python/examples/controls/layout_control/image_slideshow.py +++ /dev/null @@ -1,37 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate(e: ft.Event[ft.Button]): - image1.left = 400 if image1.left == 0 else 0 - image2.left = 0 if image2.left == -400 else -400 - page.update() - - page.add( - ft.Stack( - width=200, - height=300, - controls=[ - image1 := ft.Image( - src="https://picsum.photos/200/300?1", - left=0, - animate_position=ft.Animation( - duration=300, - curve=ft.AnimationCurve.BOUNCE_OUT, - ), - ), - image2 := ft.Image( - src="https://picsum.photos/200/300?2", - left=-400, - animate_position=ft.Animation( - duration=300, - curve=ft.AnimationCurve.BOUNCE_OUT, - ), - ), - ], - ), - ft.Button("Slide!", on_click=animate), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/image_slideshow/main.py b/sdk/python/examples/controls/layout_control/image_slideshow/main.py new file mode 100644 index 0000000000..c6f1d01d35 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/image_slideshow/main.py @@ -0,0 +1,44 @@ +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + image1.left = 400 if image1.left == 0 else 0 + image2.left = 0 if image2.left == -400 else -400 + stack.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + stack := ft.Stack( + width=200, + height=300, + controls=[ + image1 := ft.Image( + src="https://picsum.photos/200/300?1", + left=0, + animate_position=ft.Animation( + duration=300, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + image2 := ft.Image( + src="https://picsum.photos/200/300?2", + left=-400, + animate_position=ft.Animation( + duration=300, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + ], + ), + ft.Button("Slide!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/image_slideshow/pyproject.toml b/sdk/python/examples/controls/layout_control/image_slideshow/pyproject.toml new file mode 100644 index 0000000000..459e6a669f --- /dev/null +++ b/sdk/python/examples/controls/layout_control/image_slideshow/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-image-slideshow" +version = "1.0.0" +description = "Slides two images horizontally using animated left position changes." +requires-python = ">=3.10" +keywords = ["layout control", "image slideshow", "animate position", "stack"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Image slideshow" +controls = ["SafeArea", "Column", "Stack", "Image", "Button", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["sliding images", "position animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/matrix4_transform.py b/sdk/python/examples/controls/layout_control/matrix4_transform.py deleted file mode 100644 index acaa6bf075..0000000000 --- a/sdk/python/examples/controls/layout_control/matrix4_transform.py +++ /dev/null @@ -1,81 +0,0 @@ -from math import pi - -import flet as ft - - -def card(title: str, color: str, matrix: ft.Matrix4) -> ft.Container: - return ft.Container( - width=220, - height=130, - border_radius=18, - bgcolor=color, - padding=12, - content=ft.Text(title, size=18, weight=ft.FontWeight.BOLD), - transform=ft.Transform( - matrix=matrix, - alignment=ft.Alignment.CENTER, - filter_quality=ft.FilterQuality.MEDIUM, - ), - ) - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.scroll = ft.ScrollMode.AUTO - page.spacing = 20 - - perspective_tilt = ( - ft.Matrix4.identity() - .set_entry(3, 2, 0.0018) - .rotate_x(-0.35) - .rotate_y(0.45) - .translate(0, -10, 0) - ) - - skew_and_rotate = ft.Matrix4.skew_y(0.28).rotate_z(-pi / 14) - - mirrored_spin = ft.Matrix4.diagonal3_values(-1, 1, 1).rotate_z(pi / 10) - - mix = ft.Matrix4.translation_values(24, -8, 0).multiply( - ft.Matrix4.rotation_z(pi / 16).scale(0.9, 0.9) - ) - - page.add( - ft.Text("Matrix4 transform recording + replay", size=24), - ft.ResponsiveRow( - controls=[ - ft.Container( - col={"sm": 6, "md": 3}, - content=card( - "Perspective tilt", - ft.Colors.CYAN_300, - perspective_tilt, - ), - ), - ft.Container( - col={"sm": 6, "md": 3}, - content=card( - "Skew + rotate", - ft.Colors.AMBER_300, - skew_and_rotate, - ), - ), - ft.Container( - col={"sm": 6, "md": 3}, - content=card( - "Mirror + spin", - ft.Colors.PINK_200, - mirrored_spin, - ), - ), - ft.Container( - col={"sm": 6, "md": 3}, - content=card("Multiply chain", ft.Colors.LIGHT_GREEN_300, mix), - ), - ] - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/matrix4_transform/main.py b/sdk/python/examples/controls/layout_control/matrix4_transform/main.py new file mode 100644 index 0000000000..1b72aad9ef --- /dev/null +++ b/sdk/python/examples/controls/layout_control/matrix4_transform/main.py @@ -0,0 +1,93 @@ +from math import pi + +import flet as ft + + +def card(title: str, color: str, matrix: ft.Matrix4) -> ft.Container: + return ft.Container( + width=220, + height=130, + border_radius=18, + bgcolor=color, + padding=12, + content=ft.Text(title, size=18, weight=ft.FontWeight.BOLD), + transform=ft.Transform( + matrix=matrix, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.scroll = ft.ScrollMode.AUTO + page.spacing = 20 + + perspective_tilt = ( + ft.Matrix4.identity() + .set_entry(3, 2, 0.0018) + .rotate_x(-0.35) + .rotate_y(0.45) + .translate(0, -10, 0) + ) + + skew_and_rotate = ft.Matrix4.skew_y(0.28).rotate_z(-pi / 14) + + mirrored_spin = ft.Matrix4.diagonal3_values(-1, 1, 1).rotate_z(pi / 10) + + mix = ft.Matrix4.translation_values(24, -8, 0).multiply( + ft.Matrix4.rotation_z(pi / 16).scale(0.9, 0.9) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=20, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Matrix4 transform recording + replay", size=24), + ft.ResponsiveRow( + controls=[ + ft.Container( + col={"sm": 6, "md": 3}, + content=card( + "Perspective tilt", + ft.Colors.CYAN_300, + perspective_tilt, + ), + ), + ft.Container( + col={"sm": 6, "md": 3}, + content=card( + "Skew + rotate", + ft.Colors.AMBER_300, + skew_and_rotate, + ), + ), + ft.Container( + col={"sm": 6, "md": 3}, + content=card( + "Mirror + spin", + ft.Colors.PINK_200, + mirrored_spin, + ), + ), + ft.Container( + col={"sm": 6, "md": 3}, + content=card( + "Multiply chain", + ft.Colors.LIGHT_GREEN_300, + mix, + ), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/matrix4_transform/pyproject.toml b/sdk/python/examples/controls/layout_control/matrix4_transform/pyproject.toml new file mode 100644 index 0000000000..2021b0a6e5 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/matrix4_transform/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-matrix4-transform" +version = "1.0.0" +description = "Demonstrates Matrix4 perspective, skew, mirror, and chained transforms on cards." +requires-python = ">=3.10" +keywords = ["layout control", "matrix4", "transform", "perspective", "skew"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Matrix4 Transform" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "Text", "Transform", "Matrix4"] +layout_pattern = "comparison" +complexity = "basic" +features = ["perspective transform", "skew and rotation", "matrix multiply chain"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/offset.py b/sdk/python/examples/controls/layout_control/offset.py deleted file mode 100644 index 530d464658..0000000000 --- a/sdk/python/examples/controls/layout_control/offset.py +++ /dev/null @@ -1,65 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.add( - ft.Stack( - width=460, - height=260, - controls=[ - ft.Text( - "Offset translates by control size.", - left=12, - top=8, - size=16, - color=ft.Colors.ON_SURFACE_VARIANT, - ), - ft.Container( - left=30, - top=70, - width=170, - height=90, - border_radius=16, - bgcolor=ft.Colors.BLUE_100, - border=ft.Border.all(2, ft.Colors.BLUE_GREY_400), - alignment=ft.Alignment.CENTER, - content=ft.Text("Original", size=20, color=ft.Colors.BLUE_GREY_700), - ), - ft.Container( - left=30, - top=70, - width=170, - height=90, - border_radius=16, - bgcolor=ft.Colors.AMBER_300, - alignment=ft.Alignment.CENTER, - content=ft.Text("Offset", size=26, weight=ft.FontWeight.BOLD), - offset=ft.Offset( - x=1.05, - y=0.55, - filter_quality=ft.FilterQuality.MEDIUM, - ), - ), - ft.Icon( - ft.Icons.ARROW_RIGHT_ALT_ROUNDED, - left=212, - top=82, - size=44, - color=ft.Colors.BLUE_GREY_600, - ), - ft.Text( - "offset = Offset(1.05, 0.55)", - left=194, - top=222, - size=14, - color=ft.Colors.ON_SURFACE_VARIANT, - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/offset/main.py b/sdk/python/examples/controls/layout_control/offset/main.py new file mode 100644 index 0000000000..cfd44c59a9 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/offset/main.py @@ -0,0 +1,71 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.add( + ft.SafeArea( + content=ft.Stack( + width=460, + height=260, + controls=[ + ft.Text( + "Offset translates by control size.", + left=12, + top=8, + size=16, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ft.Container( + left=30, + top=70, + width=170, + height=90, + border_radius=16, + bgcolor=ft.Colors.BLUE_100, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_400), + alignment=ft.Alignment.CENTER, + content=ft.Text( + "Original", + size=20, + color=ft.Colors.BLUE_GREY_700, + ), + ), + ft.Container( + left=30, + top=70, + width=170, + height=90, + border_radius=16, + bgcolor=ft.Colors.AMBER_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("Offset", size=26, weight=ft.FontWeight.BOLD), + offset=ft.Offset( + x=1.05, + y=0.55, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ft.Icon( + ft.Icons.ARROW_RIGHT_ALT_ROUNDED, + left=212, + top=82, + size=44, + color=ft.Colors.BLUE_GREY_600, + ), + ft.Text( + "offset = Offset(1.05, 0.55)", + left=194, + top=222, + size=14, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/offset/pyproject.toml b/sdk/python/examples/controls/layout_control/offset/pyproject.toml new file mode 100644 index 0000000000..e1d069ba1d --- /dev/null +++ b/sdk/python/examples/controls/layout_control/offset/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-offset" +version = "1.0.0" +description = "Visualizes Offset translation relative to control size with labeled overlays." +requires-python = ">=3.10" +keywords = ["layout control", "offset", "transform", "stack"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Offset" +controls = ["SafeArea", "Stack", "Container", "Text", "Icon", "Offset"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["offset translation", "visual offset comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/rocket.py b/sdk/python/examples/controls/layout_control/rocket.py deleted file mode 100644 index 67b2db9920..0000000000 --- a/sdk/python/examples/controls/layout_control/rocket.py +++ /dev/null @@ -1,45 +0,0 @@ -from math import pi - -import flet as ft - - -def main(page: ft.Page): - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def animate(e: ft.Event[ft.Button]): - container.rotate.angle -= 0.5 * pi - container.content.scale = 2.0 if container.content.scale == 1.0 else 1.0 - container.content.opacity = 0.4 if container.content.scale == 1.0 else 1.0 - page.update() - - page.add( - ft.Column( - alignment=ft.MainAxisAlignment.SPACE_BETWEEN, - height=300, - controls=[ - container := ft.Container( - width=120, - height=70, - alignment=ft.Alignment.CENTER_RIGHT, - rotate=ft.Rotate(0, alignment=ft.Alignment.CENTER_LEFT), - animate_rotation=ft.Animation(duration=1000), - content=ft.Container( - scale=1.0, - animate_scale=1000, - opacity=1.0, - animate_opacity=True, - content=ft.Icon( - ft.Icons.ROCKET, - size=40, - color=ft.Colors.BLACK, - ), - ), - ), - ft.Button("Launch!", on_click=animate), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/rocket/main.py b/sdk/python/examples/controls/layout_control/rocket/main.py new file mode 100644 index 0000000000..edc1573306 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/rocket/main.py @@ -0,0 +1,48 @@ +from math import pi + +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def animate(e: ft.Event[ft.Button]): + container.rotate.angle -= 0.5 * pi + container.content.scale = 2.0 if container.content.scale == 1.0 else 1.0 + container.content.opacity = 0.4 if container.content.scale == 1.0 else 1.0 + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + height=300, + controls=[ + container := ft.Container( + width=120, + height=70, + alignment=ft.Alignment.CENTER_RIGHT, + rotate=ft.Rotate(0, alignment=ft.Alignment.CENTER_LEFT), + animate_rotation=ft.Animation(duration=1000), + content=ft.Container( + scale=1.0, + animate_scale=1000, + opacity=1.0, + animate_opacity=True, + content=ft.Icon( + ft.Icons.ROCKET, + size=40, + color=ft.Colors.BLACK, + ), + ), + ), + ft.Button("Launch!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/rocket/pyproject.toml b/sdk/python/examples/controls/layout_control/rocket/pyproject.toml new file mode 100644 index 0000000000..af5a85a9b6 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/rocket/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-rocket" +version = "1.0.0" +description = "Launch animation combining rotation, scale, and opacity on a rocket icon." +requires-python = ">=3.10" +keywords = ["layout control", "rocket", "rotation", "scale", "opacity"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Rocket" +controls = ["SafeArea", "Column", "Container", "Icon", "Button", "Rotate", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["combined transform animation", "icon launch effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/rotate.py b/sdk/python/examples/controls/layout_control/rotate.py deleted file mode 100644 index 23c355ab35..0000000000 --- a/sdk/python/examples/controls/layout_control/rotate.py +++ /dev/null @@ -1,27 +0,0 @@ -from math import pi - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.add( - ft.Container( - width=220, - height=120, - bgcolor=ft.Colors.BLUE_300, - border_radius=16, - alignment=ft.Alignment.CENTER, - content=ft.Text("Rotate", size=28, weight=ft.FontWeight.BOLD), - rotate=ft.Rotate( - angle=pi / 10, - alignment=ft.Alignment.CENTER, - filter_quality=ft.FilterQuality.MEDIUM, - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/rotate/main.py b/sdk/python/examples/controls/layout_control/rotate/main.py new file mode 100644 index 0000000000..5b84f976e9 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/rotate/main.py @@ -0,0 +1,29 @@ +from math import pi + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.add( + ft.SafeArea( + content=ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.BLUE_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Rotate", size=28, weight=ft.FontWeight.BOLD), + rotate=ft.Rotate( + angle=pi / 10, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/rotate/pyproject.toml b/sdk/python/examples/controls/layout_control/rotate/pyproject.toml new file mode 100644 index 0000000000..b670cf878a --- /dev/null +++ b/sdk/python/examples/controls/layout_control/rotate/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-rotate" +version = "1.0.0" +description = "Applies a fixed rotation transform to a container using Rotate." +requires-python = ">=3.10" +keywords = ["layout control", "rotate", "transform", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Rotate" +controls = ["SafeArea", "Container", "Text", "Rotate"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["static rotation transform"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/scale.py b/sdk/python/examples/controls/layout_control/scale.py deleted file mode 100644 index 0b226daa95..0000000000 --- a/sdk/python/examples/controls/layout_control/scale.py +++ /dev/null @@ -1,26 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.add( - ft.Container( - width=220, - height=120, - bgcolor=ft.Colors.GREEN_300, - border_radius=16, - alignment=ft.Alignment.CENTER, - content=ft.Text("Scale", size=28, weight=ft.FontWeight.BOLD), - scale=ft.Scale( - scale_x=1.18, - scale_y=0.82, - alignment=ft.Alignment.CENTER, - filter_quality=ft.FilterQuality.MEDIUM, - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/scale/main.py b/sdk/python/examples/controls/layout_control/scale/main.py new file mode 100644 index 0000000000..469eaa2112 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/scale/main.py @@ -0,0 +1,28 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.add( + ft.SafeArea( + content=ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.GREEN_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Scale", size=28, weight=ft.FontWeight.BOLD), + scale=ft.Scale( + scale_x=1.18, + scale_y=0.82, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/scale/pyproject.toml b/sdk/python/examples/controls/layout_control/scale/pyproject.toml new file mode 100644 index 0000000000..94014411a5 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/scale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-scale" +version = "1.0.0" +description = "Applies non-uniform scaling to a container using Scale transform." +requires-python = ">=3.10" +keywords = ["layout control", "scale", "transform", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Scale" +controls = ["SafeArea", "Container", "Text", "Scale"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["static scale transform", "non-uniform scaling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/layout_control/switcher.py b/sdk/python/examples/controls/layout_control/switcher.py deleted file mode 100644 index 4795c29be2..0000000000 --- a/sdk/python/examples/controls/layout_control/switcher.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def animate(e: ft.Event[ft.Button]): - shader.rotate = 1 - shader.scale = 3 - page.update() - - page.add( - ft.Stack( - width=500, - height=300, - controls=[ - shader := ft.ShaderMask( - blend_mode=ft.BlendMode.COLOR_BURN, - border_radius=5, - animate_rotation=300, - animate_scale=ft.Animation(600, ft.AnimationCurve.BOUNCE_OUT), - shader=ft.RadialGradient( - center=ft.Alignment.TOP_LEFT, - radius=1.0, - colors=[ft.Colors.YELLOW, ft.Colors.DEEP_ORANGE_900], - tile_mode=ft.GradientTileMode.CLAMP, - ), - content=ft.Image( - src="https://picsum.photos/140/100?1", - width=140, - height=100, - fit=ft.BoxFit.FILL, - ), - ) - ], - ), - ft.Button("Animate!", on_click=animate), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/switcher/main.py b/sdk/python/examples/controls/layout_control/switcher/main.py new file mode 100644 index 0000000000..3e5530824c --- /dev/null +++ b/sdk/python/examples/controls/layout_control/switcher/main.py @@ -0,0 +1,52 @@ +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + shader.rotate = 1 + shader.scale = 3 + shader.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Stack( + width=500, + height=300, + controls=[ + shader := ft.ShaderMask( + blend_mode=ft.BlendMode.COLOR_BURN, + border_radius=5, + animate_rotation=300, + animate_scale=ft.Animation( + 600, + ft.AnimationCurve.BOUNCE_OUT, + ), + shader=ft.RadialGradient( + center=ft.Alignment.TOP_LEFT, + radius=1.0, + colors=[ + ft.Colors.YELLOW, + ft.Colors.DEEP_ORANGE_900, + ], + tile_mode=ft.GradientTileMode.CLAMP, + ), + content=ft.Image( + src="https://picsum.photos/140/100?1", + width=140, + height=100, + fit=ft.BoxFit.FILL, + ), + ) + ], + ), + ft.Button("Animate!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/layout_control/switcher/pyproject.toml b/sdk/python/examples/controls/layout_control/switcher/pyproject.toml new file mode 100644 index 0000000000..a22e038460 --- /dev/null +++ b/sdk/python/examples/controls/layout_control/switcher/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-switcher" +version = "1.0.0" +description = "Animates ShaderMask rotation and scale over an image with gradient shader." +requires-python = ">=3.10" +keywords = ["layout control", "shader mask", "rotation", "scale", "image"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Switcher" +controls = ["SafeArea", "Column", "Stack", "ShaderMask", "Image", "Button", "RadialGradient"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["shader mask animation", "rotation and scale animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/interactiveviewer.md b/sdk/python/packages/flet/docs/controls/interactiveviewer.md index 0f9fc41d1a..40218644a5 100644 --- a/sdk/python/packages/flet/docs/controls/interactiveviewer.md +++ b/sdk/python/packages/flet/docs/controls/interactiveviewer.md @@ -12,13 +12,13 @@ examples: ../../examples/controls/interactive_viewer ### Handling events ```python ---8<-- "{{ examples }}/handling_events.py" +--8<-- "{{ examples }}/handling_events/main.py" ``` ### Programmatic transformations ```python ---8<-- "{{ examples }}/transformations.py" +--8<-- "{{ examples }}/transformations/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/keyboardlistener.md b/sdk/python/packages/flet/docs/controls/keyboardlistener.md index a293db45df..f599ff3f25 100644 --- a/sdk/python/packages/flet/docs/controls/keyboardlistener.md +++ b/sdk/python/packages/flet/docs/controls/keyboardlistener.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/keyboard_listener ### Press any keys ```python ---8<-- "{{ examples }}/detect_keys.py" +--8<-- "{{ examples }}/detect_keys/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/layoutcontrol.md b/sdk/python/packages/flet/docs/controls/layoutcontrol.md index 5ac52aba8e..280d534585 100644 --- a/sdk/python/packages/flet/docs/controls/layoutcontrol.md +++ b/sdk/python/packages/flet/docs/controls/layoutcontrol.md @@ -12,7 +12,7 @@ example_images_examples: ../test-images/examples/core/golden/macos/layout_contro ### Flip ```python ---8<-- "{{ examples }}/flip.py" +--8<-- "{{ examples }}/flip/main.py" ``` {{ image(example_images + "/flip.png", width="80%") }} @@ -20,7 +20,7 @@ example_images_examples: ../test-images/examples/core/golden/macos/layout_contro ### Rotate ```python ---8<-- "{{ examples }}/rotate.py" +--8<-- "{{ examples }}/rotate/main.py" ``` {{ image(example_images + "/rotate.png", width="80%") }} @@ -36,7 +36,7 @@ example_images_examples: ../test-images/examples/core/golden/macos/layout_contro ### Scale ```python ---8<-- "{{ examples }}/scale.py" +--8<-- "{{ examples }}/scale/main.py" ``` {{ image(example_images + "/scale.png", width="80%") }} @@ -44,7 +44,7 @@ example_images_examples: ../test-images/examples/core/golden/macos/layout_contro ### Offset ```python ---8<-- "{{ examples }}/offset.py" +--8<-- "{{ examples }}/offset/main.py" ``` {{ image(example_images + "/offset.png", width="80%") }} @@ -52,7 +52,7 @@ example_images_examples: ../test-images/examples/core/golden/macos/layout_contro ### Matrix4 Transform ```python ---8<-- "{{ examples }}/matrix4_transform.py" +--8<-- "{{ examples }}/matrix4_transform/main.py" ``` {{ image(example_images_examples + "/matrix4_transform.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/cookbook/animations.md b/sdk/python/packages/flet/docs/cookbook/animations.md index d0c646cfaf..a6d84bafdc 100644 --- a/sdk/python/packages/flet/docs/cookbook/animations.md +++ b/sdk/python/packages/flet/docs/cookbook/animations.md @@ -40,7 +40,7 @@ Setting control's `animate_opacity` to either `True`, number or an instance of ` enables implicit animation of [`Control.opacity`][flet.Control.opacity] property. ```python ---8<-- "../../examples/controls/layout_control/animate_opacity.py" +--8<-- "../../examples/controls/layout_control/animate_opacity/main.py" ``` {{ image("../examples/controls/layout_control/media/animate_opacity.gif", alt="animate-opacity", width="80%") }} @@ -52,7 +52,7 @@ Setting control's `animate_rotation` to either `True`, number or an instance of enables implicit animation of [`LayoutControl.rotate`][flet.LayoutControl.rotate] property. ```python ---8<-- "../../examples/controls/constrained-control/animate_rotation.py" +--8<-- "../../examples/controls/layout_control/animate_rotation/main.py" ``` {{ image("../examples/controls/layout_control/media/animate_rotation.gif", alt="animate-rotation", width="80%") }} @@ -64,7 +64,7 @@ Setting control's `animate_scale` to either `True`, number or an instance of `An enables implicit animation of [`LayoutControl.scale`][flet.LayoutControl.scale] property. ```python ---8<-- "../../examples/controls/layout_control/animate_scale.py" +--8<-- "../../examples/controls/layout_control/animate_scale/main.py" ``` {{ image("../examples/controls/layout_control/media/animate_scale.gif", alt="animate-scale", width="80%") }} @@ -82,7 +82,7 @@ a horizontal translation of one quarter the width of the control. Offset animation is used for various sliding effects: ```python ---8<-- "../../examples/controls/layout_control/animate_offset.py" +--8<-- "../../examples/controls/layout_control/animate_offset/main.py" ``` {{ image("../examples/controls/layout_control/media/animate_offset.gif", alt="animate-offset", width="80%") }} @@ -103,7 +103,7 @@ Note: - [`Page.overlay`][flet.Page.overlay] list ```python ---8<-- "../../examples/controls/layout_control/animate_position.py" +--8<-- "../../examples/controls/layout_control/animate_position/main.py" ``` {{ image("../examples/controls/layout_control/media/animate_position.gif", alt="animate-position", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_layout_control.py b/sdk/python/packages/flet/integration_tests/examples/core/test_layout_control.py index 8627431742..6cce09452e 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_layout_control.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_layout_control.py @@ -1,7 +1,8 @@ import pytest import flet.testing as ftt -from examples.controls.layout_control import flip, matrix4_transform +from examples.controls.layout_control.flip import main as flip +from examples.controls.layout_control.matrix4_transform import main as matrix4_transform @pytest.mark.parametrize( From 33387537703a58c6f44baa62453af46923209f3b Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 17:23:06 -0700 Subject: [PATCH 54/96] Refactor Python UI examples and add metadata Reorganize and standardize several Python example apps: move standalone example scripts into main.py entrypoints, wrap UI content in SafeArea, and add pyproject.toml metadata for gallery integration. Updated ListTile and ListView examples (including using lv.update() for dynamic updates and small layout tweaks). Replace old Lottie example with a new example folder, add a sample Lottie asset, and remove obsolete example modules. Also update related docs for ListTile, ListView and Lottie. These changes prepare examples for consistent packaging and gallery tooling. --- .../examples/controls/list_tile/basic.py | 76 ----------------- .../examples/controls/list_tile/basic/main.py | 83 +++++++++++++++++++ .../controls/list_tile/basic/pyproject.toml | 26 ++++++ .../list_view/autoscroll_and_dynamic_items.py | 48 ----------- .../autoscroll_and_dynamic_items/main.py | 52 ++++++++++++ .../pyproject.toml | 26 ++++++ .../examples/controls/lottie/__init__.py | 0 .../examples/controls/lottie/example_1.py | 27 ------ .../lottie/example_1/assets/sample.json | 1 + .../controls/lottie/example_1/main.py | 33 ++++++++ .../controls/lottie/example_1/pyproject.toml | 26 ++++++ .../packages/flet/docs/controls/listtile.md | 2 +- .../packages/flet/docs/controls/listview.md | 2 +- sdk/python/packages/flet/docs/lottie/index.md | 2 +- 14 files changed, 250 insertions(+), 154 deletions(-) delete mode 100644 sdk/python/examples/controls/list_tile/basic.py create mode 100644 sdk/python/examples/controls/list_tile/basic/main.py create mode 100644 sdk/python/examples/controls/list_tile/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items.py create mode 100644 sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items/main.py create mode 100644 sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items/pyproject.toml delete mode 100644 sdk/python/examples/controls/lottie/__init__.py delete mode 100644 sdk/python/examples/controls/lottie/example_1.py create mode 100644 sdk/python/examples/controls/lottie/example_1/assets/sample.json create mode 100644 sdk/python/examples/controls/lottie/example_1/main.py create mode 100644 sdk/python/examples/controls/lottie/example_1/pyproject.toml diff --git a/sdk/python/examples/controls/list_tile/basic.py b/sdk/python/examples/controls/list_tile/basic.py deleted file mode 100644 index 723ed41c39..0000000000 --- a/sdk/python/examples/controls/list_tile/basic.py +++ /dev/null @@ -1,76 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "ListTile Example" - - page.add( - ft.Card( - content=ft.Container( - width=500, - padding=ft.Padding.symmetric(vertical=10), - content=ft.Column( - spacing=0, - controls=[ - ft.ListTile(title=ft.Text("One-line list tile")), - ft.ListTile( - title=ft.Text("One-line dense list tile"), - dense=True, - ), - ft.ListTile( - leading=ft.Icon(ft.Icons.SETTINGS), - title=ft.Text("One-line selected list tile"), - selected=True, - ), - ft.ListTile( - leading=ft.Image( - src="/icons/icon-192.png", - fit=ft.BoxFit.CONTAIN, - ), - title=ft.Text("One-line with leading control"), - ), - ft.ListTile( - title=ft.Text("One-line with trailing control"), - trailing=ft.PopupMenuButton( - icon=ft.Icons.MORE_VERT, - items=[ - ft.PopupMenuItem(content="Item 1"), - ft.PopupMenuItem(content="Item 2"), - ], - ), - ), - ft.ListTile( - leading=ft.Icon(ft.Icons.ALBUM), - title=ft.Text( - value="One-line with leading and trailing controls" - ), - trailing=ft.PopupMenuButton( - icon=ft.Icons.MORE_VERT, - items=[ - ft.PopupMenuItem(content="Item 1"), - ft.PopupMenuItem(content="Item 2"), - ], - ), - ), - ft.ListTile( - leading=ft.Icon(ft.Icons.SNOOZE), - title=ft.Text( - value="Two-line with leading and trailing controls" - ), - subtitle=ft.Text("Here is a second title."), - trailing=ft.PopupMenuButton( - icon=ft.Icons.MORE_VERT, - items=[ - ft.PopupMenuItem(content="Item 1"), - ft.PopupMenuItem(content="Item 2"), - ], - ), - ), - ], - ), - ) - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/list_tile/basic/main.py b/sdk/python/examples/controls/list_tile/basic/main.py new file mode 100644 index 0000000000..c86703a7de --- /dev/null +++ b/sdk/python/examples/controls/list_tile/basic/main.py @@ -0,0 +1,83 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "ListTile Example" + + page.add( + ft.SafeArea( + content=ft.Card( + content=ft.Container( + width=500, + padding=ft.Padding.symmetric(vertical=10), + content=ft.Column( + spacing=0, + controls=[ + ft.ListTile(title=ft.Text("One-line list tile")), + ft.ListTile( + title=ft.Text("One-line dense list tile"), + dense=True, + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.SETTINGS), + title=ft.Text("One-line selected list tile"), + selected=True, + ), + ft.ListTile( + leading=ft.Image( + src="/icons/icon-192.png", + fit=ft.BoxFit.CONTAIN, + ), + title=ft.Text("One-line with leading control"), + ), + ft.ListTile( + title=ft.Text("One-line with trailing control"), + trailing=ft.PopupMenuButton( + icon=ft.Icons.MORE_VERT, + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(content="Item 2"), + ], + ), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.ALBUM), + title=ft.Text( + value=( + "One-line with leading and trailing controls" + ) + ), + trailing=ft.PopupMenuButton( + icon=ft.Icons.MORE_VERT, + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(content="Item 2"), + ], + ), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.SNOOZE), + title=ft.Text( + value=( + "Two-line with leading and trailing controls" + ) + ), + subtitle=ft.Text("Here is a second title."), + trailing=ft.PopupMenuButton( + icon=ft.Icons.MORE_VERT, + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(content="Item 2"), + ], + ), + ), + ], + ), + ) + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/list_tile/basic/pyproject.toml b/sdk/python/examples/controls/list_tile/basic/pyproject.toml new file mode 100644 index 0000000000..5816f01ba3 --- /dev/null +++ b/sdk/python/examples/controls/list_tile/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "list-tile-basic" +version = "1.0.0" +description = "Showcases one-line and two-line ListTile variants with leading/trailing controls and selection state." +requires-python = ">=3.10" +keywords = ["list tile", "material", "popup menu", "selection", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ListTile"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Card", "Container", "Column", "ListTile", "Icon", "Image", "PopupMenuButton", "PopupMenuItem", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["tile variants", "leading and trailing controls", "selected and dense states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items.py b/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items.py deleted file mode 100644 index dc7dabb5ce..0000000000 --- a/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items.py +++ /dev/null @@ -1,48 +0,0 @@ -import asyncio - -import flet as ft - - -async def main(page: ft.Page): - def handle_switch_change(e: ft.Event[ft.Switch]): - lv.auto_scroll = not lv.auto_scroll - page.update() - - lv = ft.ListView( - spacing=10, - padding=20, - width=150, - auto_scroll=True, - controls=[ - ft.Text(f"Line {i}", color=ft.Colors.ON_SECONDARY) for i in range(0, 60) - ], - ) - - page.add( - ft.Row( - expand=True, - vertical_alignment=ft.CrossAxisAlignment.START, - controls=[ - ft.Container( - content=lv, - bgcolor=ft.Colors.GREY_500, - ), - ft.Switch( - thumb_icon=ft.Icons.LIST_OUTLINED, - value=True, - label="Auto-scroll", - label_position=ft.LabelPosition.RIGHT, - on_change=handle_switch_change, - ), - ], - ) - ) - - # add a new item to the ListView every 1 second - for i in range(len(lv.controls), 120): - await asyncio.sleep(1) - lv.controls.append(ft.Text(f"Line {i}", color=ft.Colors.ON_SECONDARY)) - page.update() - - -ft.run(main) diff --git a/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items/main.py b/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items/main.py new file mode 100644 index 0000000000..e1a40ec6ae --- /dev/null +++ b/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items/main.py @@ -0,0 +1,52 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + def handle_switch_change(e: ft.Event[ft.Switch]): + lv.auto_scroll = not lv.auto_scroll + lv.update() + + lv = ft.ListView( + spacing=10, + padding=20, + width=150, + auto_scroll=True, + controls=[ + ft.Text(f"Line {i}", color=ft.Colors.ON_SECONDARY) for i in range(0, 60) + ], + ) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Row( + expand=True, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Container( + bgcolor=ft.Colors.GREY_500, + content=lv, + ), + ft.Switch( + thumb_icon=ft.Icons.LIST_OUTLINED, + value=True, + label="Auto-scroll", + label_position=ft.LabelPosition.RIGHT, + on_change=handle_switch_change, + ), + ], + ), + ) + ) + + # Add a new item to the ListView every second. + for i in range(len(lv.controls), 120): + await asyncio.sleep(1) + lv.controls.append(ft.Text(f"Line {i}", color=ft.Colors.ON_SECONDARY)) + lv.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items/pyproject.toml b/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items/pyproject.toml new file mode 100644 index 0000000000..9e8059c952 --- /dev/null +++ b/sdk/python/examples/controls/list_view/autoscroll_and_dynamic_items/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "list-view-autoscroll-and-dynamic-items" +version = "1.0.0" +description = "Adds new ListView items over time and toggles auto-scroll behavior with a switch." +requires-python = ">=3.10" +keywords = ["list view", "auto scroll", "dynamic items", "async", "switch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ListView"] + +[tool.flet.metadata] +title = "Auto-scrolling and dynamical items addition" +controls = ["SafeArea", "Row", "Container", "ListView", "Text", "Switch"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["auto-scroll toggle", "dynamic list item appending", "async updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/lottie/__init__.py b/sdk/python/examples/controls/lottie/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/lottie/example_1.py b/sdk/python/examples/controls/lottie/example_1.py deleted file mode 100644 index 2479cce046..0000000000 --- a/sdk/python/examples/controls/lottie/example_1.py +++ /dev/null @@ -1,27 +0,0 @@ -import flet_lottie as ftl - -import flet as ft - - -def main(page: ft.Page): - page.add( - ftl.Lottie( - src="https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json", - reverse=False, - animate=True, - error_content=ft.Placeholder(ft.Text("Error loading Lottie")), - on_error=lambda e: print(f"Error loading Lottie: {e.data}"), - ), - ftl.Lottie( - src="sample.json", - reverse=False, - animate=True, - enable_merge_paths=True, - enable_layers_opacity=True, - error_content=ft.Placeholder(ft.Text("Error loading Lottie")), - on_error=lambda e: print(f"Error loading Lottie: {e.data}"), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/lottie/example_1/assets/sample.json b/sdk/python/examples/controls/lottie/example_1/assets/sample.json new file mode 100644 index 0000000000..afd268ea80 --- /dev/null +++ b/sdk/python/examples/controls/lottie/example_1/assets/sample.json @@ -0,0 +1 @@ +{"assets":[],"layers":[{"ddd":0,"ind":0,"ty":4,"nm":"B 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[32.279,-158.917],[6.297,-132.935],[-32.677,-132.935],[-32.677,-184.598],[6.297,-184.598]],"c":true}},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-93.658],[43.156,-67.676]],"c":true}},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[1,1,1,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":26,"op":37,"st":22,"bm":0,"sr":1},{"ddd":0,"ind":1,"ty":4,"nm":"B","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":26,"op":37,"st":22,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"B blue layer 6","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-1.324,-11.343],[2.439,-7.314],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.612,-2.224]],"v":[[-55.603,-180.739],[-55.439,-147.686],[-63.981,-142.398],[-70.654,-190.988],[-63.612,-197.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[9.939,-11.314],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[9.112,-3.724]],"v":[[-32.103,-179.739],[-36.939,-146.686],[-53.481,-139.398],[-60.154,-190.488],[-47.112,-197.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.154,-14.341],[9.939,-11.314],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[9.112,-3.724]],"v":[[-32.103,-179.739],[-36.939,-146.686],[-53.481,-139.398],[-60.154,-190.488],[-47.112,-197.276]],"c":true}],"e":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-11.249,-176.983],[-23.893,-143.184],[-46.891,-138.152],[-50.397,-189.494],[-30.535,-196.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-11.249,-176.983],[-23.893,-143.184],[-46.891,-138.152],[-50.397,-189.494],[-30.535,-196.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[4.397,-174.239],[-14.439,-139.686],[-40.981,-136.898],[-44.654,-188.488],[-18.612,-193.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[4.397,-174.239],[-14.439,-139.686],[-40.981,-136.898],[-44.654,-188.488],[-18.612,-193.276]],"c":true}],"e":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.998,-170.132],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.998,-170.132],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"n":"0_1_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[32.279,-158.917],[6.297,-132.935],[-32.677,-132.935],[-32.677,-184.598],[6.297,-184.598]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[5.931,-1.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-44.931,-50.495],[-55.177,-48.495],[-60.677,-102.158],[-53.931,-106.658],[-42.844,-84.676]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-27.431,-47.995],[-46.177,-46.495],[-51.177,-100.658],[-34.431,-104.658],[-18.344,-87.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-27.431,-47.995],[-46.177,-46.495],[-51.177,-100.658],[-34.431,-104.658],[-18.344,-87.176]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[2.589,13.962]],"v":[[-10.681,-46.995],[-40.427,-45.245],[-43.677,-98.908],[-17.181,-102.408],[3.406,-81.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[2.589,13.962]],"v":[[-10.681,-46.995],[-40.427,-45.245],[-43.677,-98.908],[-17.181,-102.408],[3.406,-81.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[20.156,-76.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[20.156,-76.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[6.902,-43.495],[-34.844,-42.662],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[6.902,-43.495],[-34.844,-42.662],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"n":"0_1_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-93.658],[43.156,-67.676]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[1,1,1,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":16,"op":26,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"B blue layer 5","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[5.759,27.537],[4.508,20.972],[7.96,-31.787],[0,0],[0,0],[-52.303,4.363],[12.713,79.144]],"o":[[-6.241,-30.463],[-18.411,-85.645],[-8.037,32.093],[0,0],[0,0],[17.982,-1.5],[-4.202,-26.16]],"v":[[-23.759,-157.537],[-41.089,-239.855],[-57.963,-260.093],[-97.507,-214.093],[-76.507,-0.5],[-13.982,-7.5],[-8.213,-83.644]],"c":true}],"e":[{"i":[[8.259,26.537],[3.138,21.22],[33.463,-28.907],[0,0],[0,0],[-52.485,0],[6.213,46.144]],"o":[[-3.241,-28.463],[-9.411,-63.645],[-29.686,25.644],[0,0],[0,0],[43.482,0],[-4.959,-36.833]],"v":[[21.241,-163.037],[14.911,-228.855],[-29.963,-255.093],[-95.007,-217.593],[-76.507,-0.5],[17.018,-3.5],[41.787,-87.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[8.259,26.537],[3.138,21.22],[33.463,-28.907],[0,0],[0,0],[-52.485,0],[6.213,46.144]],"o":[[-3.241,-28.463],[-9.411,-63.645],[-29.686,25.644],[0,0],[0,0],[43.482,0],[-4.959,-36.833]],"v":[[21.241,-163.037],[14.911,-228.855],[-29.963,-255.093],[-95.007,-217.593],[-76.507,-0.5],[17.018,-3.5],[41.787,-87.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[37.463,-16.657],[0,0],[0,0],[-26.242,0],[5.463,51.394]],"o":[[3.509,-24.213],[-4.661,-61.895],[-35.537,14.843],[0,0],[0,0],[52.482,4],[-3.676,-32.795]],"v":[[46.741,-144.787],[49.661,-211.605],[-14.963,-245.343],[-91.757,-220.343],[-77.257,-0.75],[21.518,-2],[72.287,-76.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[37.463,-16.657],[0,0],[0,0],[-26.242,0],[5.463,51.394]],"o":[[3.509,-24.213],[-4.661,-61.895],[-35.537,14.843],[0,0],[0,0],[52.482,4],[-3.676,-32.795]],"v":[[46.741,-144.787],[49.661,-211.605],[-14.963,-245.343],[-91.757,-220.343],[-77.257,-0.75],[21.518,-2],[72.287,-76.144]],"c":true}],"e":[{"i":[[23.259,15.537],[2.058,21.352],[34.868,-8.794],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.037,9.593],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[56.241,-133.537],[68.411,-198.355],[-2.963,-239.593],[-88.507,-223.093],[-78.007,-1],[26.018,-0.5],[86.787,-72.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[23.259,15.537],[2.058,21.352],[34.868,-8.794],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.037,9.593],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[56.241,-133.537],[68.411,-198.355],[-2.963,-239.593],[-88.507,-223.093],[-78.007,-1],[26.018,-0.5],[86.787,-72.144]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[36.665,-5.6],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-2.705,-47.408],[-19.018,4.797],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[76.911,-186.105],[5.787,-235.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[36.665,-5.6],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-2.705,-47.408],[-19.018,4.797],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[76.911,-186.105],[5.787,-235.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"n":"0_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":16,"op":26,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":9.771},"p":{"k":[{"i":{"x":0.601,"y":0.889},"o":{"x":0.239,"y":0.067},"n":"0p601_0p889_0p239_0p067","t":9,"s":[241.443,258.888,0],"e":[222.443,251.888,0],"to":[-0.5,-0.33333334326744,0],"ti":[-1.02731943130493,-0.37357068061829,0]},{"i":{"x":0.686,"y":1},"o":{"x":0.239,"y":0.304},"n":"0p686_1_0p239_0p304","t":11,"s":[222.443,251.888,0],"e":[242,259,0],"to":[5.54179763793945,2.01519918441772,0],"ti":[-3.09325051307678,-1.12481832504272,0]},{"t":20.3449832499027}]},"a":{"k":[0,0,0]},"s":{"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":8.999,"s":[-100,100,100],"e":[-128,128,100]},{"t":21.9237344563007}]}},"ao":0,"ip":9.99999961256981,"op":22.7584036290646,"st":-10.5559570491314,"bm":0,"sr":0.96000009775162},{"ddd":0,"ind":5,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":-22.412},"p":{"k":[{"i":{"x":0.592,"y":0.891},"o":{"x":0.257,"y":0.068},"n":"0p592_0p891_0p257_0p068","t":9,"s":[225.656,310.504,0],"e":[206.656,303.504,0],"to":[-0.5,-0.33333334326744,0],"ti":[-1.516930103302,-0.31094110012054,0]},{"i":{"x":0.762,"y":1},"o":{"x":0.257,"y":0.3},"n":"0p762_1_0p257_0p3","t":11,"s":[206.656,303.504,0],"e":[228,308,0],"to":[6.19302797317505,1.26945006847382,0],"ti":[-0.32227402925491,0,0]},{"t":20.3640127778053}]},"a":{"k":[0,0,0]},"s":{"k":[-100,100,100]}},"ao":0,"ip":10.0000003576279,"op":22.5608477592468,"st":-9.35224944353104,"bm":0,"sr":0.95000010728836},{"ddd":0,"ind":6,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":26.915},"p":{"k":[{"i":{"x":0.587,"y":0.894},"o":{"x":0.264,"y":0.068},"n":"0p587_0p894_0p264_0p068","t":10,"s":[228.667,205.657,0],"e":[209.667,198.657,0],"to":[-0.5,-0.33333334326744,0],"ti":[-1.19691395759583,-0.40347543358803,0]},{"i":{"x":0.713,"y":1},"o":{"x":0.264,"y":0.336},"n":"0p713_1_0p264_0p336","t":12,"s":[209.667,198.657,0],"e":[223,204,0],"to":[4.62041616439819,1.55752575397491,0],"ti":[-0.48471575975418,0,0]},{"t":19.0271503602465}]},"a":{"k":[0,0,0]},"s":{"k":[-100,100,100]}},"ao":0,"ip":11.0000006233652,"op":22.5608497237166,"st":-9.35224822411935,"bm":0,"sr":0.95000010728836},{"ddd":0,"ind":7,"ty":4,"nm":"B blue layer 4 shadow","parent":34,"ks":{"o":{"k":5},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[6,3],[35.446,17.154],[1.39,-24.214],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[-35.446,-17.154],[-1.585,27.613],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-94,-266],[-98,-118],[-80,-5],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-5,-22],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[5,22],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-143,-270],[-133,-137],[-118,-11],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[6,3],[0,-5],[-5,-22],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[5,22],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-143,-270],[-133,-137],[-118,-11],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-5,-22],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[5,22],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-178,-280],[-159,-145],[-141,4],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6,3],[0,-5],[-5,-22],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[5,22],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-178,-280],[-159,-145],[-141,4],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-7,-32],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[6.414,29.323],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-158,-284],[-149,-204],[-118,6],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[6,3],[0,-5],[-7,-32],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[6.414,29.323],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-158,-284],[-149,-204],[-118,6],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-0.752,-22.548],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[1,30],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-106,-286],[-115,-276],[-99,-138],[-79,20],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[6,3],[0,-5],[-0.752,-22.548],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[1,30],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-106,-286],[-115,-276],[-99,-138],[-79,20],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-0.752,-22.548],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[1,30],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-388,-298],[-397,-288],[-381,-150],[-361,8],[-401,15],[-379,28],[-341,19],[-356,-228]],"c":true}]},{"t":15}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[3.637,14.035],[-6.562,-18.555],[0,0],[0,0],[0,0],[1.944,58.843],[5.869,46.436],[6.789,29.064]],"o":[[-3.783,-14.599],[12.079,34.152],[0,0],[0,0],[0,0],[-0.327,-9.886],[-2.413,-19.093],[-6.444,-27.588]],"v":[[-100.137,-270.035],[-81.079,-226.152],[-69.301,-172.891],[-65.375,-112.805],[-61.507,1.5],[-65.673,-78.614],[-71.869,-138.936],[-83.556,-205.912]],"c":true}],"e":[{"i":[[1.179,13.587],[-16.316,-11.006],[0,0],[0,0],[0,0],[51.329,28.838],[-0.631,46.436],[1.219,29.821]],"o":[[-1.863,-21.465],[33.579,22.652],[0,0],[0,0],[0,0],[-23.827,-13.386],[0.145,-10.708],[-0.944,-23.088]],"v":[[-180.137,-248.535],[-116.079,-227.152],[-76.301,-169.391],[-71.875,-105.305],[-64.007,0.5],[-127.173,-60.614],[-176.869,-121.436],[-176.556,-181.412]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[1.179,13.587],[-16.316,-11.006],[0,0],[0,0],[0,0],[51.329,28.838],[-0.631,46.436],[1.219,29.821]],"o":[[-1.863,-21.465],[33.579,22.652],[0,0],[0,0],[0,0],[-23.827,-13.386],[0.145,-10.708],[-0.944,-23.088]],"v":[[-180.137,-248.535],[-116.079,-227.152],[-76.301,-169.391],[-71.875,-105.305],[-64.007,0.5],[-127.173,-60.614],[-176.869,-121.436],[-176.556,-181.412]],"c":true}],"e":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[62.482,13.5],[0.713,41.144],[-1.198,29.377]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-23.658,-5.112],[-0.183,-10.545],[1.875,-45.981]],"v":[[-210.589,-237.355],[-131.463,-229.593],[-83.507,-180.593],[-80.113,-142.106],[-67.007,-0.5],[-149.982,-38.5],[-213.713,-83.644],[-211.875,-154.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[62.482,13.5],[0.713,41.144],[-1.198,29.377]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-23.658,-5.112],[-0.183,-10.545],[1.875,-45.981]],"v":[[-210.589,-237.355],[-131.463,-229.593],[-83.507,-180.593],[-80.113,-142.106],[-67.007,-0.5],[-149.982,-38.5],[-213.713,-83.644],[-211.875,-154.519]],"c":true}],"e":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[49.59,6.194],[2.062,42.216],[0.844,29.39]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-24.018,-3],[-0.514,-10.534],[-1.267,-44.142]],"v":[[-219.089,-243.355],[-134.463,-234.593],[-89.007,-187.093],[-84.613,-147.106],[-68.507,-0.5],[-150.482,-30.5],[-213.713,-68.644],[-215.875,-135.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[49.59,6.194],[2.062,42.216],[0.844,29.39]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-24.018,-3],[-0.514,-10.534],[-1.267,-44.142]],"v":[[-219.089,-243.355],[-134.463,-234.593],[-89.007,-187.093],[-84.613,-147.106],[-68.507,-0.5],[-150.482,-30.5],[-213.713,-68.644],[-215.875,-135.019]],"c":true}],"e":[{"i":[[1.979,12.724],[-39.037,-17.407],[0,0],[0,0],[0,0],[49.482,7],[3.213,42.144],[3.102,33.18]],"o":[[-3.911,-25.145],[30.419,13.564],[0,0],[0,0],[0,0],[-13.966,-1.976],[-0.805,-10.559],[-4.66,-49.835]],"v":[[-212.089,-255.355],[-134.463,-244.093],[-94.007,-197.593],[-89.078,-155.355],[-71.007,-0.5],[-128.482,-21.5],[-193.213,-61.644],[-199.771,-135.061]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[1.979,12.724],[-39.037,-17.407],[0,0],[0,0],[0,0],[49.482,7],[3.213,42.144],[3.102,33.18]],"o":[[-3.911,-25.145],[30.419,13.564],[0,0],[0,0],[0,0],[-13.966,-1.976],[-0.805,-10.559],[-4.66,-49.835]],"v":[[-212.089,-255.355],[-134.463,-244.093],[-94.007,-197.593],[-89.078,-155.355],[-71.007,-0.5],[-128.482,-21.5],[-193.213,-61.644],[-199.771,-135.061]],"c":true}],"e":[{"i":[[2.758,12.578],[-32.825,-21.239],[0,0],[0,0],[0,0],[34.982,4],[4.713,44.644],[5.969,34.173]],"o":[[-8.911,-40.645],[27.963,18.093],[0,0],[0,0],[0,0],[-14.013,-1.602],[-1.112,-10.531],[-8.965,-51.327]],"v":[[-179.589,-262.855],[-130.463,-262.593],[-96.507,-222.593],[-91.042,-175.962],[-71.007,-5],[-104.982,-18.5],[-144.713,-64.144],[-156.854,-139.358]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[2.758,12.578],[-32.825,-21.239],[0,0],[0,0],[0,0],[34.982,4],[4.713,44.644],[5.969,34.173]],"o":[[-8.911,-40.645],[27.963,18.093],[0,0],[0,0],[0,0],[-14.013,-1.602],[-1.112,-10.531],[-8.965,-51.327]],"v":[[-179.589,-262.855],[-130.463,-262.593],[-96.507,-222.593],[-91.042,-175.962],[-71.007,-5],[-104.982,-18.5],[-144.713,-64.144],[-156.854,-139.358]],"c":true}],"e":[{"i":[[3.235,12.104],[-17.053,-18.911],[0,0],[3.05,20.138],[0,0],[9.544,-4.956],[7.213,61.144],[5.736,34.461]],"o":[[-17.411,-65.145],[14.963,16.593],[0,0],[-3.05,-20.138],[0,0],[-12.518,6.5],[-1.291,-10.944],[-8.055,-48.393]],"v":[[-114.589,-252.855],[-102.463,-279.593],[-83.507,-232.593],[-72.45,-171.862],[-51.007,-10.5],[-65.982,-2.5],[-81.213,-61.644],[-90.187,-141.969]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[3.235,12.104],[-17.053,-18.911],[0,0],[3.05,20.138],[0,0],[9.544,-4.956],[7.213,61.144],[5.736,34.461]],"o":[[-17.411,-65.145],[14.963,16.593],[0,0],[-3.05,-20.138],[0,0],[-12.518,6.5],[-1.291,-10.944],[-8.055,-48.393]],"v":[[-114.589,-252.855],[-102.463,-279.593],[-83.507,-232.593],[-72.45,-171.862],[-51.007,-10.5],[-65.982,-2.5],[-81.213,-61.644],[-90.187,-141.969]],"c":true}],"e":[{"i":[[2.706,12.59],[7.96,-31.787],[0,0],[0,0],[0,0],[-52.303,4.363],[12.713,79.144],[5.528,26.028]],"o":[[-18.411,-85.645],[-8.037,32.093],[0,0],[0,0],[0,0],[17.982,-1.5],[-1.68,-10.456],[-8.303,-39.094]],"v":[[-41.089,-239.855],[-57.963,-260.093],[-97.507,-214.093],[-93.006,-168.319],[-76.507,-0.5],[-13.982,-7.5],[-8.213,-83.644],[-20.289,-143.83]],"c":true}]},{"t":16}]},"nm":"B"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":10,"op":15,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":8,"ty":4,"nm":"B blue layer 4","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[3.637,14.035],[-6.562,-18.555],[0,0],[0,0],[0,0],[1.944,58.843],[5.869,46.436],[6.789,29.064]],"o":[[-3.783,-14.599],[12.079,34.152],[0,0],[0,0],[0,0],[-0.327,-9.886],[-2.413,-19.093],[-6.444,-27.588]],"v":[[-100.137,-270.035],[-81.079,-226.152],[-69.301,-172.891],[-65.375,-112.805],[-61.507,1.5],[-65.673,-78.614],[-71.869,-138.936],[-83.556,-205.912]],"c":true}],"e":[{"i":[[1.179,13.587],[-16.316,-11.006],[0,0],[0,0],[0,0],[51.329,28.838],[-0.631,46.436],[1.219,29.821]],"o":[[-1.863,-21.465],[33.579,22.652],[0,0],[0,0],[0,0],[-23.827,-13.386],[0.145,-10.708],[-0.944,-23.088]],"v":[[-180.137,-248.535],[-116.079,-227.152],[-76.301,-169.391],[-71.875,-105.305],[-64.007,0.5],[-127.173,-60.614],[-176.869,-121.436],[-176.556,-181.412]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[1.179,13.587],[-16.316,-11.006],[0,0],[0,0],[0,0],[51.329,28.838],[-0.631,46.436],[1.219,29.821]],"o":[[-1.863,-21.465],[33.579,22.652],[0,0],[0,0],[0,0],[-23.827,-13.386],[0.145,-10.708],[-0.944,-23.088]],"v":[[-180.137,-248.535],[-116.079,-227.152],[-76.301,-169.391],[-71.875,-105.305],[-64.007,0.5],[-127.173,-60.614],[-176.869,-121.436],[-176.556,-181.412]],"c":true}],"e":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[62.482,13.5],[0.713,41.144],[-1.198,29.377]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-23.658,-5.112],[-0.183,-10.545],[1.875,-45.981]],"v":[[-210.589,-237.355],[-131.463,-229.593],[-83.507,-180.593],[-80.113,-142.106],[-67.007,-0.5],[-149.982,-38.5],[-213.713,-83.644],[-211.875,-154.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[62.482,13.5],[0.713,41.144],[-1.198,29.377]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-23.658,-5.112],[-0.183,-10.545],[1.875,-45.981]],"v":[[-210.589,-237.355],[-131.463,-229.593],[-83.507,-180.593],[-80.113,-142.106],[-67.007,-0.5],[-149.982,-38.5],[-213.713,-83.644],[-211.875,-154.519]],"c":true}],"e":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[49.59,6.194],[2.062,42.216],[0.844,29.39]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-24.018,-3],[-0.514,-10.534],[-1.267,-44.142]],"v":[[-219.089,-243.355],[-134.463,-234.593],[-89.007,-187.093],[-84.613,-147.106],[-68.507,-0.5],[-150.482,-30.5],[-213.713,-68.644],[-215.875,-135.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[49.59,6.194],[2.062,42.216],[0.844,29.39]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-24.018,-3],[-0.514,-10.534],[-1.267,-44.142]],"v":[[-219.089,-243.355],[-134.463,-234.593],[-89.007,-187.093],[-84.613,-147.106],[-68.507,-0.5],[-150.482,-30.5],[-213.713,-68.644],[-215.875,-135.019]],"c":true}],"e":[{"i":[[1.979,12.724],[-39.037,-17.407],[0,0],[0,0],[0,0],[49.482,7],[3.213,42.144],[3.102,33.18]],"o":[[-3.911,-25.145],[30.419,13.564],[0,0],[0,0],[0,0],[-13.966,-1.976],[-0.805,-10.559],[-4.66,-49.835]],"v":[[-212.089,-255.355],[-134.463,-244.093],[-94.007,-197.593],[-89.078,-155.355],[-71.007,-0.5],[-128.482,-21.5],[-193.213,-61.644],[-199.771,-135.061]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[1.979,12.724],[-39.037,-17.407],[0,0],[0,0],[0,0],[49.482,7],[3.213,42.144],[3.102,33.18]],"o":[[-3.911,-25.145],[30.419,13.564],[0,0],[0,0],[0,0],[-13.966,-1.976],[-0.805,-10.559],[-4.66,-49.835]],"v":[[-212.089,-255.355],[-134.463,-244.093],[-94.007,-197.593],[-89.078,-155.355],[-71.007,-0.5],[-128.482,-21.5],[-193.213,-61.644],[-199.771,-135.061]],"c":true}],"e":[{"i":[[2.758,12.578],[-32.825,-21.239],[0,0],[0,0],[0,0],[34.982,4],[4.713,44.644],[5.969,34.173]],"o":[[-8.911,-40.645],[27.963,18.093],[0,0],[0,0],[0,0],[-14.013,-1.602],[-1.112,-10.531],[-8.965,-51.327]],"v":[[-179.589,-262.855],[-130.463,-262.593],[-96.507,-222.593],[-91.042,-175.962],[-71.007,-5],[-104.982,-18.5],[-144.713,-64.144],[-156.854,-139.358]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[2.758,12.578],[-32.825,-21.239],[0,0],[0,0],[0,0],[34.982,4],[4.713,44.644],[5.969,34.173]],"o":[[-8.911,-40.645],[27.963,18.093],[0,0],[0,0],[0,0],[-14.013,-1.602],[-1.112,-10.531],[-8.965,-51.327]],"v":[[-179.589,-262.855],[-130.463,-262.593],[-96.507,-222.593],[-91.042,-175.962],[-71.007,-5],[-104.982,-18.5],[-144.713,-64.144],[-156.854,-139.358]],"c":true}],"e":[{"i":[[3.235,12.104],[-17.053,-18.911],[0,0],[-3.55,-45.138],[0,0],[4.732,-1.5],[7.213,61.144],[5.736,34.461]],"o":[[-17.411,-65.145],[14.963,16.593],[0,0],[3.168,40.285],[0,0],[-13.445,4.262],[-1.291,-10.944],[-8.055,-48.393]],"v":[[-114.589,-252.855],[-102.463,-279.593],[-83.507,-232.593],[-73.45,-164.862],[-61.507,-3],[-68.482,-0.25],[-81.213,-61.644],[-90.187,-141.969]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[3.235,12.104],[-17.053,-18.911],[0,0],[-3.55,-45.138],[0,0],[4.732,-1.5],[7.213,61.144],[5.736,34.461]],"o":[[-17.411,-65.145],[14.963,16.593],[0,0],[3.168,40.285],[0,0],[-13.445,4.262],[-1.291,-10.944],[-8.055,-48.393]],"v":[[-114.589,-252.855],[-102.463,-279.593],[-83.507,-232.593],[-73.45,-164.862],[-61.507,-3],[-68.482,-0.25],[-81.213,-61.644],[-90.187,-141.969]],"c":true}],"e":[{"i":[[2.706,12.59],[7.96,-31.787],[0,0],[0,0],[0,0],[-52.303,4.363],[12.713,79.144],[5.528,26.028]],"o":[[-18.411,-85.645],[-8.037,32.093],[0,0],[0,0],[0,0],[17.982,-1.5],[-1.68,-10.456],[-8.303,-39.094]],"v":[[-41.089,-239.855],[-57.963,-260.093],[-97.507,-214.093],[-93.006,-168.319],[-76.507,-0.5],[-13.982,-7.5],[-8.213,-83.644],[-20.289,-143.83]],"c":true}]},{"t":16}]},"nm":"B"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":9,"op":16,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":9,"ty":4,"nm":"B blue layer 3","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[20.982,16]],"o":[[0,0],[0,0],[-11.216,-8.553]],"v":[[-78.007,-37.093],[-72.507,0.5],[-84.482,-27.5]],"c":true}},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":14,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":10,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":26.875},"p":{"k":[{"i":{"x":0.663,"y":0.933},"o":{"x":0.334,"y":0.066},"n":"0p663_0p933_0p334_0p066","t":9,"s":[269.705,292.352,0],"e":[250.705,285.352,0],"to":[-0.5,-0.33333334326744,0],"ti":[-0.60055363178253,-0.48845085501671,0]},{"i":{"x":0.685,"y":1},"o":{"x":0.334,"y":0.228},"n":"0p685_1_0p334_0p228","t":11,"s":[250.705,285.352,0],"e":[276,308,0],"to":[9.00963115692139,7.32784128189087,0],"ti":[-0.48727434873581,0,0]},{"t":22.5016243755817}]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"ip":10.0000001490116,"op":24.4098640978336,"st":-11.1670814454556,"bm":0,"sr":0.99000012874603},{"ddd":0,"ind":11,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":-21.596},"p":{"k":[{"i":{"x":0.58,"y":0.829},"o":{"x":0.278,"y":0.114},"n":"0p58_0p829_0p278_0p114","t":9,"s":[217.311,226.631,0],"e":[198.311,219.631,0],"to":[0,0,0],"ti":[-3.21461248397827,3.18686246871948,0]},{"i":{"x":0.726,"y":1},"o":{"x":0.278,"y":0.371},"n":"0p726_1_0p278_0p371","t":11,"s":[198.311,219.631,0],"e":[223,195,0],"to":[8.70546340942383,-8.63031387329102,0],"ti":[-1.45636057853699,0,0]},{"t":21.5996034443378}]},"a":{"k":[0,0,0]},"s":{"k":[100,-100,100]}},"ao":0,"ip":10.0000001490116,"op":24.4098640978336,"st":-11.1670814454556,"bm":0,"sr":0.99000012874603},{"ddd":0,"ind":12,"ty":3,"nm":"null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":16.774},"p":{"k":[{"i":{"x":0.577,"y":0.847},"o":{"x":0.284,"y":0.103},"n":"0p577_0p847_0p284_0p103","t":9,"s":[261.182,221.23,0],"e":[242.182,214.23,0],"to":[0,0,0],"ti":[-3.1457417011261,0.33704376220703,0]},{"i":{"x":0.697,"y":1},"o":{"x":0.284,"y":0.405},"n":"0p697_1_0p284_0p405","t":11,"s":[242.182,214.23,0],"e":[263,212,0],"to":[7.38616800308228,-0.79137516021729,0],"ti":[-3.2727952003479,0.3506566286087,0]},{"t":18.9003057777882}]},"a":{"k":[0,0,0]},"s":{"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":9.9,"s":[100,100,100],"e":[122,122,100]},{"t":20.7004822790623}]}},"ao":0,"ip":10.0000001490116,"op":24.4098640978336,"st":-11.1670814454556,"bm":0,"sr":0.99000012874603},{"ddd":0,"ind":13,"ty":3,"nm":"Null 26","parent":34,"ks":{"o":{"k":0},"r":{"k":-11.144},"p":{"k":[{"i":{"x":0.573,"y":0.757},"o":{"x":0.294,"y":0.167},"n":"0p573_0p757_0p294_0p167","t":9,"s":[267.556,276.269,0],"e":[248.556,269.269,0],"to":[0,0,0],"ti":[-4.61654806137085,2.50612592697144,0]},{"i":{"x":0.699,"y":1},"o":{"x":0.294,"y":0.426},"n":"0p699_1_0p294_0p426","t":11,"s":[248.556,269.269,0],"e":[273,256,0],"to":[9.04685020446777,-4.91114711761475,0],"ti":[-3.86238408088684,2.09672284126282,0]},{"t":17.4897499382496}]},"a":{"k":[0,0,0]},"s":{"k":[100,-100,100]}},"ao":0,"ip":10.0000001490116,"op":21.5510979294777,"st":-11.1670814454556,"bm":0,"sr":0.99000012874603},{"ddd":0,"ind":14,"ty":4,"nm":"B blue layer 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":1,"s":[{"i":[[-1.24,5.104],[0.198,1.892],[0,0],[0,0],[0,0],[-0.804,-2.124],[0.343,-5.77],[-1.462,6.091]],"o":[[1.049,-4.319],[-0.297,-2.847],[0,0],[0,0],[0,0],[0.386,1.02],[0.093,-2.77],[0.816,-3.399]],"v":[[-22.001,-21.919],[-20.415,-30.453],[-22.49,-31.96],[-27.759,-19.513],[-32.548,3.666],[-29.736,4.974],[-28.593,7.27],[-25.53,-6.238]],"c":true}],"e":[{"i":[[-1.032,7.042],[1.743,2.453],[0,0],[0,0],[0,0],[-3.84,-2.615],[-0.171,-9.84],[-1.176,8.399]],"o":[[0.873,-5.959],[-2.624,-3.692],[0,0],[0,0],[0,0],[1.845,1.256],[2.053,-13.363],[0.656,-4.688]],"v":[[-19.587,-23.915],[-19.439,-35.572],[-25.627,-39.562],[-30.78,-20.831],[-37.568,3.797],[-29.696,6.026],[-25.346,16.687],[-22.197,-8.804]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":2,"s":[{"i":[[-1.032,7.042],[1.743,2.453],[0,0],[0,0],[0,0],[-3.84,-2.615],[-0.171,-9.84],[-1.176,8.399]],"o":[[0.873,-5.959],[-2.624,-3.692],[0,0],[0,0],[0,0],[1.845,1.256],[2.053,-13.363],[0.656,-4.688]],"v":[[-19.587,-23.915],[-19.439,-35.572],[-25.627,-39.562],[-30.78,-20.831],[-37.568,3.797],[-29.696,6.026],[-25.346,16.687],[-22.197,-8.804]],"c":true}],"e":[{"i":[[-0.284,9.426],[4.036,2.935],[0,0],[0,0],[0,0],[-7.528,-4.291],[-1.775,-13.654],[-0.23,11.234]],"o":[[0.241,-7.977],[-6.074,-4.417],[0,0],[0,0],[0,0],[6.05,3.449],[0.725,-17.904],[0.128,-6.27]],"v":[[-11.741,-32.523],[-17.536,-48.935],[-30.445,-51.84],[-35.936,-26.366],[-41.832,3.676],[-25.8,5.301],[-13.725,26.404],[-12.128,-11.48]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":3,"s":[{"i":[[-0.284,9.426],[4.036,2.935],[0,0],[0,0],[0,0],[-7.528,-4.291],[-1.775,-13.654],[-0.23,11.234]],"o":[[0.241,-7.977],[-6.074,-4.417],[0,0],[0,0],[0,0],[6.05,3.449],[0.725,-17.904],[0.128,-6.27]],"v":[[-11.741,-32.523],[-17.536,-48.935],[-30.445,-51.84],[-35.936,-26.366],[-41.832,3.676],[-25.8,5.301],[-13.725,26.404],[-12.128,-11.48]],"c":true}],"e":[{"i":[[0.512,9.416],[12.036,5.935],[0,0],[0,0],[0,0],[-10.429,-3.711],[-2.775,-15.904],[1.665,20.58]],"o":[[-0.759,-13.977],[-8.794,-4.337],[0,0],[0,0],[0,0],[11.8,4.199],[-1.275,-18.904],[-0.872,-10.77]],"v":[[-0.741,-42.023],[-15.536,-66.935],[-34.945,-68.34],[-40.936,-29.866],[-44.332,2.676],[-17.3,1.801],[4.275,28.904],[1.372,-13.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0.512,9.416],[12.036,5.935],[0,0],[0,0],[0,0],[-10.429,-3.711],[-2.775,-15.904],[1.665,20.58]],"o":[[-0.759,-13.977],[-8.794,-4.337],[0,0],[0,0],[0,0],[11.8,4.199],[-1.275,-18.904],[-0.872,-10.77]],"v":[[-0.741,-42.023],[-15.536,-66.935],[-34.945,-68.34],[-40.936,-29.866],[-44.332,2.676],[-17.3,1.801],[4.275,28.904],[1.372,-13.73]],"c":true}],"e":[{"i":[[2.118,9.189],[13.168,3.137],[0,0],[0,0],[0,0],[-21.716,-6.523],[-3.775,-12.404],[3.122,20.41]],"o":[[-4.259,-18.477],[-14.964,-3.565],[0,0],[0,0],[0,0],[22.3,6.699],[-2.775,-18.904],[-2.872,-18.77]],"v":[[12.259,-65.023],[-14.536,-90.935],[-40.945,-84.34],[-43.436,-51.366],[-48.332,2.176],[-5.8,-5.199],[26.275,28.404],[16.372,-36.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[2.118,9.189],[13.168,3.137],[0,0],[0,0],[0,0],[-21.716,-6.523],[-3.775,-12.404],[3.122,20.41]],"o":[[-4.259,-18.477],[-14.964,-3.565],[0,0],[0,0],[0,0],[22.3,6.699],[-2.775,-18.904],[-2.872,-18.77]],"v":[[12.259,-65.023],[-14.536,-90.935],[-40.945,-84.34],[-43.436,-51.366],[-48.332,2.176],[-5.8,-5.199],[26.275,28.404],[16.372,-36.73]],"c":true}],"e":[{"i":[[2.118,9.189],[13.533,0.289],[0,0],[0,0],[0,0],[-54.798,-20.458],[-2.775,-7.904],[4.128,20.23]],"o":[[-4.259,-18.477],[-26.464,-0.565],[0,0],[0,0],[0,0],[23.3,8.699],[-0.275,-14.904],[-3.009,-14.743]],"v":[[31.259,-89.523],[-7.536,-119.435],[-46.945,-102.34],[-48.936,-56.366],[-51.832,2.676],[27.2,-12.199],[54.275,22.904],[40.872,-40.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[2.118,9.189],[13.533,0.289],[0,0],[0,0],[0,0],[-54.798,-20.458],[-2.775,-7.904],[4.128,20.23]],"o":[[-4.259,-18.477],[-26.464,-0.565],[0,0],[0,0],[0,0],[23.3,8.699],[-0.275,-14.904],[-3.009,-14.743]],"v":[[31.259,-89.523],[-7.536,-119.435],[-46.945,-102.34],[-48.936,-56.366],[-51.832,2.676],[27.2,-12.199],[54.275,22.904],[40.872,-40.73]],"c":true}],"e":[{"i":[[2.741,9.023],[35.536,-9.065],[0,0],[0,0],[0,0],[-58.271,5.078],[7.345,30.067],[7.32,28.81]],"o":[[-6.003,-19.766],[-38.857,9.912],[0,0],[0,0],[0,0],[72.3,-6.301],[-3.275,-13.404],[-3.372,-13.27]],"v":[[77.259,-132.023],[-1.536,-158.935],[-53.945,-122.34],[-54.436,-66.866],[-54.832,1.176],[23.7,-42.699],[103.275,-31.596],[86.872,-91.23]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[2.741,9.023],[35.536,-9.065],[0,0],[0,0],[0,0],[-58.271,5.078],[7.345,30.067],[7.32,28.81]],"o":[[-6.003,-19.766],[-38.857,9.912],[0,0],[0,0],[0,0],[72.3,-6.301],[-3.275,-13.404],[-3.372,-13.27]],"v":[[77.259,-132.023],[-1.536,-158.935],[-53.945,-122.34],[-54.436,-66.866],[-54.832,1.176],[23.7,-42.699],[103.275,-31.596],[86.872,-91.23]],"c":true}],"e":[{"i":[[2.692,12.158],[14.536,-18.065],[0,0],[0,0],[0,0],[-45.886,36.274],[7.225,30.096],[8.494,27.268]],"o":[[-3.759,-16.977],[-25.14,31.242],[0,0],[0,0],[0,0],[35.8,-28.301],[-2.392,-9.964],[-7.872,-25.27]],"v":[[26.759,-245.023],[-23.036,-213.935],[-60.445,-143.84],[-59.936,-99.866],[-58.832,1.676],[-5.3,-69.199],[64.275,-130.596],[40.372,-201.73]],"c":true}]},{"t":8}]},"nm":"B"},{"ty":"mm","mm":2,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":1,"op":9,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":15,"ty":4,"nm":"B orange layer 3 shadow 2","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-99,-265],[-121,-264],[-133,-219],[-107,10],[-84,33],[-49,13],[-62,-108]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-70,-275],[-92,-274],[-104,-229],[-78,0],[-55,23],[-20,3],[-33,-118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-70,-275],[-92,-274],[-104,-229],[-78,0],[-55,23],[-20,3],[-33,-118]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-25.168,-278.566],[-92,-274],[-104,-229],[-78,0],[-55,23],[22.285,0.453],[-2.338,-146.717]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-25.168,-278.566],[-92,-274],[-104,-229],[-78,0],[-55,23],[22.285,0.453],[-2.338,-146.717]],"c":true}],"e":[{"i":[[16.753,14.499],[0,0],[0,0],[0,0],[0,0],[-3,10],[21.96,31.036]],"o":[[-16.753,-14.499],[0,0],[0,0],[0,0],[0,0],[3,-10],[2.96,-38.964]],"v":[[19.753,-282.501],[-92,-274],[-104,-229],[-78,0],[-55,23],[64.682,-1.606],[39.04,-141.036]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17,"s":[{"i":[[16.753,14.499],[0,0],[0,0],[0,0],[0,0],[-3,10],[21.96,31.036]],"o":[[-16.753,-14.499],[0,0],[0,0],[0,0],[0,0],[3,-10],[2.96,-38.964]],"v":[[19.753,-282.501],[-92,-274],[-104,-229],[-78,0],[-55,23],[64.682,-1.606],[39.04,-141.036]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[24,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[12,-31]],"v":[[67,-296],[-92,-274],[-104,-229],[-78,0],[-55,23],[110,9],[57,-143]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[24,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[12,-31]],"v":[[67,-296],[-92,-274],[-104,-229],[-78,0],[-55,23],[110,9],[57,-143]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[60,-286],[-92,-274],[-104,-229],[-78,0],[-55,23],[104,4],[115,-139]],"c":true}]},{"t":19}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[-17.127,-8.576],[-4.287,-8.856]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[11.982,6],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-46.507,-102.093],[-51.007,3.5],[-21.482,0],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}],"e":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}],"e":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}],"e":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}],"e":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}],"e":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}],"e":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-264.603,-181.739],[-262.939,-148.686],[-267.481,-144.898],[-273.154,-192.488],[-271.112,-195.276]],"c":true}],"e":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-60.603,-177.739],[-58.939,-144.686],[-63.481,-140.898],[-69.154,-188.488],[-67.112,-191.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-60.603,-177.739],[-58.939,-144.686],[-63.481,-140.898],[-69.154,-188.488],[-67.112,-191.276]],"c":true}],"e":[{"i":[[-1.324,-11.343],[4.939,-8.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[6.612,-3.724]],"v":[[-40.603,-178.239],[-44.439,-146.186],[-54.981,-139.898],[-61.654,-188.488],[-53.612,-193.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-1.324,-11.343],[4.939,-8.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[6.612,-3.724]],"v":[[-40.603,-178.239],[-44.439,-146.186],[-54.981,-139.898],[-61.654,-188.488],[-53.612,-193.776]],"c":true}],"e":[{"i":[[-0.897,-12.761],[7.439,-4.314],[0,0],[0,0],[0,0]],"o":[[1.049,14.93],[0,0],[0,0],[0,0],[11.112,-4.224]],"v":[[-22.103,-175.239],[-29.439,-144.686],[-49.481,-139.398],[-53.654,-189.988],[-40.112,-193.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-0.897,-12.761],[7.439,-4.314],[0,0],[0,0],[0,0]],"o":[[1.049,14.93],[0,0],[0,0],[0,0],[11.112,-4.224]],"v":[[-22.103,-175.239],[-29.439,-144.686],[-49.481,-139.398],[-53.654,-189.988],[-40.112,-193.776]],"c":true}],"e":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-5.749,-174.483],[-19.893,-141.684],[-44.391,-137.152],[-47.397,-188.494],[-26.535,-193.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-5.749,-174.483],[-19.893,-141.684],[-44.391,-137.152],[-47.397,-188.494],[-26.535,-193.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[7.397,-171.739],[-12.939,-138.686],[-40.981,-136.898],[-43.154,-187.488],[-17.112,-191.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[7.397,-171.739],[-12.939,-138.686],[-40.981,-136.898],[-43.154,-187.488],[-17.112,-191.276]],"c":true}],"e":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.498,-167.632],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.498,-167.632],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}],"e":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[31.613,-160.417],[4.963,-133.935],[-33.677,-133.268],[-33.677,-186.264],[4.297,-186.598]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[31.613,-160.417],[4.963,-133.935],[-33.677,-133.268],[-33.677,-186.264],[4.297,-186.598]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[32.279,-158.917],[6.297,-132.935],[-32.677,-132.935],[-32.677,-184.598],[6.297,-184.598]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-262.931,-52.995],[-268.677,-50.995],[-274.177,-102.658],[-270.431,-105.658],[-264.344,-84.176]],"c":true}],"e":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-46.431,-52.995],[-52.177,-50.995],[-57.677,-102.658],[-53.931,-105.658],[-47.844,-84.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-46.431,-52.995],[-52.177,-50.995],[-57.677,-102.658],[-53.931,-105.658],[-47.844,-84.176]],"c":true}],"e":[{"i":[[7.931,-3.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-32.931,-51.495],[-45.677,-48.995],[-51.177,-100.658],[-40.431,-104.658],[-26.844,-83.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[7.931,-3.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-32.931,-51.495],[-45.677,-48.995],[-51.177,-100.658],[-40.431,-104.658],[-26.844,-83.176]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-19.931,-48.995],[-40.177,-47.495],[-45.177,-99.158],[-24.431,-103.158],[-6.344,-82.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-19.931,-48.995],[-40.177,-47.495],[-45.177,-99.158],[-24.431,-103.158],[-6.344,-82.676]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[15.681,-1.092],[2.589,13.962]],"v":[[-7.681,-46.495],[-37.927,-44.245],[-41.177,-97.908],[-14.681,-101.408],[8.906,-80.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[15.681,-1.092],[2.589,13.962]],"v":[[-7.681,-46.495],[-37.927,-44.245],[-41.177,-97.908],[-14.681,-101.408],[8.906,-80.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[21.656,-76.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[21.656,-76.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[7.902,-44.495],[-34.344,-44.162],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[7.902,-44.495],[-34.344,-44.162],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.658],[43.156,-67.676]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.658],[43.156,-67.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-93.658],[43.156,-67.676]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":16,"ty":4,"nm":"B orange layer 3 shadow","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-99,-265],[-121,-264],[-133,-219],[-107,10],[-84,33],[-49,13],[-62,-108]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-70,-275],[-92,-274],[-104,-229],[-78,0],[-55,23],[-20,3],[-33,-118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-70,-275],[-92,-274],[-104,-229],[-78,0],[-55,23],[-20,3],[-33,-118]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-25.168,-278.566],[-92,-274],[-104,-229],[-78,0],[-55,23],[22.285,0.453],[-2.338,-146.717]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-25.168,-278.566],[-92,-274],[-104,-229],[-78,0],[-55,23],[22.285,0.453],[-2.338,-146.717]],"c":true}],"e":[{"i":[[16.753,14.499],[0,0],[0,0],[0,0],[0,0],[-3,10],[21.96,31.036]],"o":[[-16.753,-14.499],[0,0],[0,0],[0,0],[0,0],[3,-10],[2.96,-38.964]],"v":[[19.753,-282.501],[-92,-274],[-104,-229],[-78,0],[-55,23],[64.682,-1.606],[39.04,-141.036]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17,"s":[{"i":[[16.753,14.499],[0,0],[0,0],[0,0],[0,0],[-3,10],[21.96,31.036]],"o":[[-16.753,-14.499],[0,0],[0,0],[0,0],[0,0],[3,-10],[2.96,-38.964]],"v":[[19.753,-282.501],[-92,-274],[-104,-229],[-78,0],[-55,23],[64.682,-1.606],[39.04,-141.036]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[24,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[12,-31]],"v":[[67,-296],[-92,-274],[-104,-229],[-78,0],[-55,23],[110,9],[57,-143]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[24,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[12,-31]],"v":[[67,-296],[-92,-274],[-104,-229],[-78,0],[-55,23],[110,9],[57,-143]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[60,-286],[-92,-274],[-104,-229],[-78,0],[-55,23],[104,4],[115,-139]],"c":true}]},{"t":19}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[-17.127,-8.576],[-4.287,-8.856]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[11.982,6],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-46.507,-102.093],[-51.007,3.5],[-21.482,0],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}],"e":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}],"e":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}],"e":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}],"e":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}],"e":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}],"e":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":14,"op":15,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":17,"ty":4,"nm":"B orange layer 5","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[-17.127,-8.576],[-4.287,-8.856]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[11.982,6],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-46.507,-102.093],[-51.007,3.5],[-21.482,0],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}],"e":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}],"e":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}],"e":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}],"e":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}],"e":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}],"e":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-264.603,-181.739],[-262.939,-148.686],[-267.481,-144.898],[-273.154,-192.488],[-271.112,-195.276]],"c":true}],"e":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-60.603,-177.739],[-58.939,-144.686],[-63.481,-140.898],[-69.154,-188.488],[-67.112,-191.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-60.603,-177.739],[-58.939,-144.686],[-63.481,-140.898],[-69.154,-188.488],[-67.112,-191.276]],"c":true}],"e":[{"i":[[-1.324,-11.343],[4.939,-8.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[6.612,-3.724]],"v":[[-40.603,-178.239],[-44.439,-146.186],[-54.981,-139.898],[-61.654,-188.488],[-53.612,-193.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-1.324,-11.343],[4.939,-8.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[6.612,-3.724]],"v":[[-40.603,-178.239],[-44.439,-146.186],[-54.981,-139.898],[-61.654,-188.488],[-53.612,-193.776]],"c":true}],"e":[{"i":[[-0.897,-12.761],[7.439,-4.314],[0,0],[0,0],[0,0]],"o":[[1.049,14.93],[0,0],[0,0],[0,0],[11.112,-4.224]],"v":[[-22.103,-175.239],[-29.439,-144.686],[-49.481,-139.398],[-53.654,-189.988],[-40.112,-193.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-0.897,-12.761],[7.439,-4.314],[0,0],[0,0],[0,0]],"o":[[1.049,14.93],[0,0],[0,0],[0,0],[11.112,-4.224]],"v":[[-22.103,-175.239],[-29.439,-144.686],[-49.481,-139.398],[-53.654,-189.988],[-40.112,-193.776]],"c":true}],"e":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-5.749,-174.483],[-19.893,-141.684],[-44.391,-137.152],[-47.397,-188.494],[-26.535,-193.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-5.749,-174.483],[-19.893,-141.684],[-44.391,-137.152],[-47.397,-188.494],[-26.535,-193.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[7.397,-171.739],[-12.939,-138.686],[-40.981,-136.898],[-43.154,-187.488],[-17.112,-191.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[7.397,-171.739],[-12.939,-138.686],[-40.981,-136.898],[-43.154,-187.488],[-17.112,-191.276]],"c":true}],"e":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.498,-167.632],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.498,-167.632],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}],"e":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[31.613,-160.417],[4.963,-133.935],[-33.677,-133.268],[-33.677,-186.264],[4.297,-186.598]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[31.613,-160.417],[4.963,-133.935],[-33.677,-133.268],[-33.677,-186.264],[4.297,-186.598]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[32.279,-158.917],[6.297,-132.935],[-32.677,-132.935],[-32.677,-184.598],[6.297,-184.598]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-262.931,-52.995],[-268.677,-50.995],[-274.177,-102.658],[-270.431,-105.658],[-264.344,-84.176]],"c":true}],"e":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-46.431,-52.995],[-52.177,-50.995],[-57.677,-102.658],[-53.931,-105.658],[-47.844,-84.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-46.431,-52.995],[-52.177,-50.995],[-57.677,-102.658],[-53.931,-105.658],[-47.844,-84.176]],"c":true}],"e":[{"i":[[7.931,-3.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-32.931,-51.495],[-45.677,-48.995],[-51.177,-100.658],[-40.431,-104.658],[-26.844,-83.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[7.931,-3.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-32.931,-51.495],[-45.677,-48.995],[-51.177,-100.658],[-40.431,-104.658],[-26.844,-83.176]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-19.931,-48.995],[-40.177,-47.495],[-45.177,-99.158],[-24.431,-103.158],[-6.344,-82.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-19.931,-48.995],[-40.177,-47.495],[-45.177,-99.158],[-24.431,-103.158],[-6.344,-82.676]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[15.681,-1.092],[2.589,13.962]],"v":[[-7.681,-46.495],[-37.927,-44.245],[-41.177,-97.908],[-14.681,-101.408],[8.906,-80.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[15.681,-1.092],[2.589,13.962]],"v":[[-7.681,-46.495],[-37.927,-44.245],[-41.177,-97.908],[-14.681,-101.408],[8.906,-80.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[21.656,-76.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[21.656,-76.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[7.902,-44.495],[-34.344,-44.162],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[7.902,-44.495],[-34.344,-44.162],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.658],[43.156,-67.676]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.658],[43.156,-67.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-93.658],[43.156,-67.676]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":18,"ty":4,"nm":"B orange layer 3","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[-17.127,-8.576],[-4.287,-8.856]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[11.982,6],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-46.507,-102.093],[-51.007,3.5],[-21.482,0],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}],"e":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}],"e":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}],"e":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}],"e":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}],"e":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}],"e":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":11,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":19,"ty":4,"nm":"B orange layer 2 shadow","parent":34,"ks":{"o":{"k":5},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[27,-20],[0,0],[-5,-11],[-20,3],[0,21],[-1,63]],"o":[[-10.811,8.008],[0,0],[5,11],[20,-3],[0,-21],[1,-63]],"v":[[-55,-172],[-86,-85],[-92,10],[-95,22],[0,21],[-15,-137]],"c":true}],"e":[{"i":[[27,-20],[0,0],[-5,-11],[-20,3],[0,21],[-1,63]],"o":[[-10.811,8.008],[0,0],[5,11],[20,-3],[0,-21],[1,-63]],"v":[[-55,-172],[-86,-85],[-92,10],[-58,40],[42,28],[20,-147]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[27,-20],[0,0],[-5,-11],[-20,3],[0,21],[-1,63]],"o":[[-10.811,8.008],[0,0],[5,11],[20,-3],[0,-21],[1,-63]],"v":[[-55,-172],[-86,-85],[-92,10],[-58,40],[42,28],[20,-147]],"c":true}],"e":[{"i":[[55,-29],[0,0],[-5,-11],[-20,3],[0,21],[28,61]],"o":[[-55,29],[0,0],[5,11],[20,-3],[0,-21],[-26.285,-57.263]],"v":[[-79,-179],[-124,-104],[-119,72],[-21,87],[50,-29],[4,-198]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[55,-29],[0,0],[-5,-11],[-20,3],[0,21],[28,61]],"o":[[-55,29],[0,0],[5,11],[20,-3],[0,-21],[-26.285,-57.263]],"v":[[-79,-179],[-124,-104],[-119,72],[-21,87],[50,-29],[4,-198]],"c":true}],"e":[{"i":[[29.478,-54.745],[0,0],[-5,-11],[-20,3],[0,21],[13,66]],"o":[[-7,13],[0,0],[5,11],[20,-3],[0,-21],[-12.177,-61.82]],"v":[[-115,-165],[-124,-104],[-107,16],[-80,39],[-19,5],[-54,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[29.478,-54.745],[0,0],[-5,-11],[-20,3],[0,21],[13,66]],"o":[[-7,13],[0,0],[5,11],[20,-3],[0,-21],[-12.177,-61.82]],"v":[[-115,-165],[-124,-104],[-107,16],[-80,39],[-19,5],[-54,-216]],"c":true}],"e":[{"i":[[29.478,-54.745],[0,0],[-5,-11],[-20,3],[0,21],[13,66]],"o":[[-7,13],[0,0],[5,11],[20,-3],[0,-21],[-12.177,-61.82]],"v":[[-150,-165],[-159,-104],[-142,16],[-115,39],[-54,5],[-77,-199]],"c":true}]},{"t":10}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.993,13.755],[-0.576,6.238],[1.302,0.585],[0,0],[0,0],[0,0],[-2.275,-1.384],[-0.28,-3.435]],"o":[[1.757,-16.495],[0.509,-5.518],[-2.446,-1.099],[0,0],[0,0],[0,0],[1.508,0.917],[1.082,-12.356]],"v":[[-36.507,-32.755],[-33.509,-58.982],[-33.554,-66.651],[-36.609,-64.578],[-39.481,-45.472],[-46.5,1.214],[-41.725,1.384],[-40.332,4.606]],"c":true}],"e":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-44.677,-58.245],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-44.677,-58.245],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}],"e":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[0,0],[-15.518,-7.5],[-1.787,-7.356]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[0,0],[12.065,5.831],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-47.257,-101.593],[-49.484,-64.148],[-53.507,3.5],[-22.232,0.5],[-8.713,17.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[0,0],[-15.518,-7.5],[-1.787,-7.356]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[0,0],[12.065,5.831],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-47.257,-101.593],[-49.484,-64.148],[-53.507,3.5],[-22.232,0.5],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[1.35375,9.22725],[1.2945,5.92749999999999],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-3.1205,-19.9815],[-1.35375,-9.22725],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[12.9565,-90.9865],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[1.35375,9.22725],[1.2945,5.92749999999999],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-3.1205,-19.9815],[-1.35375,-9.22725],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[12.9565,-90.9865],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[1.54124999999999,8.22725],[1.5445,4.67749999999998],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-3.62050000000001,-19.2315],[-1.54125000000001,-8.22725],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[76.519,-124.8615],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[1.54124999999999,8.22725],[1.5445,4.67749999999998],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-3.62050000000001,-19.2315],[-1.54125000000001,-8.22725],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[76.519,-124.8615],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.4935,12.920375],[2.2355,2.65499999999997],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-3.6205,-10.9815],[-4.4935,-12.920375],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[32.28725,-233.940875],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.4935,12.920375],[2.2355,2.65499999999997],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-3.6205,-10.9815],[-4.4935,-12.920375],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[32.28725,-233.940875],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[3.073,9.17012500000001],[0.66749999999999,3.40600000000001],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-1.3705,-6.23150000000001],[-3.07300000000001,-9.17012499999998],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-60.45125,-196.815125],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[3.073,9.17012500000001],[0.66749999999999,3.40600000000001],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-1.3705,-6.23150000000001],[-3.07300000000001,-9.17012499999998],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-60.45125,-196.815125],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.545875,6.84424999999999],[0.27600000000001,3.45950000000002],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.37050000000001,-3.98150000000001],[-0.545875,-6.84424999999999],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-80.744875,-161.3375],[-82.089,-178.355],[-90.963,-174.593],[-80.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"t":11}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.993,13.755],[-0.576,6.238],[1.302,0.585],[0,0],[0,0],[-2.275,-1.384],[-0.28,-3.435]],"o":[[1.757,-16.495],[0.509,-5.518],[-2.446,-1.099],[0,0],[0,0],[1.508,0.917],[1.082,-12.356]],"v":[[-36.507,-32.755],[-33.509,-58.982],[-33.554,-66.651],[-36.609,-64.578],[-46.5,1.214],[-41.725,1.384],[-40.332,4.606]],"c":true}],"e":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}],"e":[{"i":[[0.832,26.037],[0.279,9.355],[-0.34,-0.907],[0,0],[0,0],[-1.764,2.5],[-2,4.644]],"o":[[-0.587,-21.463],[-0.181,-6.06],[-2.641,3.629],[0,0],[0,0],[1.764,-2.5],[3,-26.606]],"v":[[-48.414,-64.537],[-46.516,-92.355],[-47.66,-93.593],[-51.128,-76.843],[-60.507,13.25],[-56.514,6],[-52.5,-2.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0.832,26.037],[0.279,9.355],[-0.34,-0.907],[0,0],[0,0],[-1.764,2.5],[-2,4.644]],"o":[[-0.587,-21.463],[-0.181,-6.06],[-2.641,3.629],[0,0],[0,0],[1.764,-2.5],[3,-26.606]],"v":[[-48.414,-64.537],[-46.516,-92.355],[-47.66,-93.593],[-51.128,-76.843],[-60.507,13.25],[-56.514,6],[-52.5,-2.394]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-80.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"t":11}]},"nm":"B 2"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":6,"op":11,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":20,"ty":4,"nm":"B orange layer 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.993,13.755],[-0.576,6.238],[1.302,0.585],[0,0],[0,0],[0,0],[-2.275,-1.384],[-0.28,-3.435]],"o":[[1.757,-16.495],[0.509,-5.518],[-2.446,-1.099],[0,0],[0,0],[0,0],[1.508,0.917],[1.082,-12.356]],"v":[[-36.507,-32.755],[-33.509,-58.982],[-33.554,-66.651],[-36.609,-64.578],[-39.481,-45.472],[-46.5,1.214],[-41.725,1.384],[-40.332,4.606]],"c":true}],"e":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-44.677,-58.245],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-44.677,-58.245],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}],"e":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[0,0],[-15.518,-7.5],[-1.787,-7.356]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[0,0],[12.065,5.831],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-47.257,-101.593],[-49.484,-64.148],[-53.507,3.5],[-22.232,0.5],[-8.713,17.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[0,0],[-15.518,-7.5],[-1.787,-7.356]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[0,0],[12.065,5.831],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-47.257,-101.593],[-49.484,-64.148],[-53.507,3.5],[-22.232,0.5],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[1.35375,9.22725],[1.2945,5.92749999999999],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-3.1205,-19.9815],[-1.35375,-9.22725],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[12.9565,-90.9865],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[1.35375,9.22725],[1.2945,5.92749999999999],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-3.1205,-19.9815],[-1.35375,-9.22725],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[12.9565,-90.9865],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[1.54124999999999,8.22725],[1.5445,4.67749999999998],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-3.62050000000001,-19.2315],[-1.54125000000001,-8.22725],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[76.519,-124.8615],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[1.54124999999999,8.22725],[1.5445,4.67749999999998],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-3.62050000000001,-19.2315],[-1.54125000000001,-8.22725],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[76.519,-124.8615],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.4935,12.920375],[2.2355,2.65499999999997],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-3.6205,-10.9815],[-4.4935,-12.920375],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[32.28725,-233.940875],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.4935,12.920375],[2.2355,2.65499999999997],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-3.6205,-10.9815],[-4.4935,-12.920375],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[32.28725,-233.940875],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[3.073,9.17012500000001],[0.66749999999999,3.40600000000001],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-1.3705,-6.23150000000001],[-3.07300000000001,-9.17012499999998],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-60.45125,-196.815125],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[3.073,9.17012500000001],[0.66749999999999,3.40600000000001],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-1.3705,-6.23150000000001],[-3.07300000000001,-9.17012499999998],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-60.45125,-196.815125],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.545875,6.84424999999999],[0.27600000000001,3.45950000000002],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.37050000000001,-3.98150000000001],[-0.545875,-6.84424999999999],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-80.744875,-161.3375],[-82.089,-178.355],[-90.963,-174.593],[-80.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"t":11}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.993,13.755],[-0.576,6.238],[1.302,0.585],[0,0],[0,0],[-2.275,-1.384],[-0.28,-3.435]],"o":[[1.757,-16.495],[0.509,-5.518],[-2.446,-1.099],[0,0],[0,0],[1.508,0.917],[1.082,-12.356]],"v":[[-36.507,-32.755],[-33.509,-58.982],[-33.554,-66.651],[-36.609,-64.578],[-46.5,1.214],[-41.725,1.384],[-40.332,4.606]],"c":true}],"e":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}],"e":[{"i":[[0.832,26.037],[0.279,9.355],[-0.34,-0.907],[0,0],[0,0],[-1.764,2.5],[-2,4.644]],"o":[[-0.587,-21.463],[-0.181,-6.06],[-2.641,3.629],[0,0],[0,0],[1.764,-2.5],[3,-26.606]],"v":[[-48.414,-64.537],[-46.516,-92.355],[-47.66,-93.593],[-51.128,-76.843],[-60.507,13.25],[-56.514,6],[-52.5,-2.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0.832,26.037],[0.279,9.355],[-0.34,-0.907],[0,0],[0,0],[-1.764,2.5],[-2,4.644]],"o":[[-0.587,-21.463],[-0.181,-6.06],[-2.641,3.629],[0,0],[0,0],[1.764,-2.5],[3,-26.606]],"v":[[-48.414,-64.537],[-46.516,-92.355],[-47.66,-93.593],[-51.128,-76.843],[-60.507,13.25],[-56.514,6],[-52.5,-2.394]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-80.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"t":11}]},"nm":"B 2"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":4,"op":11,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":21,"ty":4,"nm":"B blue layer 1","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":1,"s":[{"i":[[0,0],[1.135,0.16],[0.519,-0.169],[0.368,-1.304],[0.165,-1.422],[-2.463,0.226],[-0.024,0.731],[0.1,1.443]],"o":[[0,0],[-0.591,-0.084],[-0.572,0.81],[-0.408,1.446],[-0.141,1.212],[2.637,-0.242],[-0.113,-1.414],[-0.065,-0.946]],"v":[[-29.39,-0.524],[-31.301,-0.669],[-32.486,-0.16],[-34.047,2.548],[-34.859,5.55],[-31.571,8.49],[-28.75,5.075],[-29.073,1.857]],"c":true}],"e":[{"i":[[0,0],[4.131,0.584],[1.89,-0.615],[1.34,-4.746],[0.602,-5.175],[-8.964,0.823],[-0.088,2.66],[0.363,5.252]],"o":[[0,0],[-2.152,-0.304],[-2.08,2.95],[-1.486,5.262],[-0.513,4.413],[9.6,-0.881],[-0.41,-5.148],[-0.238,-3.443]],"v":[[-27.079,-7.92],[-34.036,-8.446],[-38.349,-6.594],[-44.031,3.262],[-46.987,14.191],[-35.017,24.893],[-24.75,12.463],[-25.925,0.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":2,"s":[{"i":[[0,0],[4.131,0.584],[1.89,-0.615],[1.34,-4.746],[0.602,-5.175],[-8.964,0.823],[-0.088,2.66],[0.363,5.252]],"o":[[0,0],[-2.152,-0.304],[-2.08,2.95],[-1.486,5.262],[-0.513,4.413],[9.6,-0.881],[-0.41,-5.148],[-0.238,-3.443]],"v":[[-27.079,-7.92],[-34.036,-8.446],[-38.349,-6.594],[-44.031,3.262],[-46.987,14.191],[-35.017,24.893],[-24.75,12.463],[-25.925,0.75]],"c":true}],"e":[{"i":[[0,0],[8.324,1.188],[3.808,-1.25],[2.7,-9.654],[1.213,-10.525],[-18.063,1.674],[-0.178,5.41],[0.731,10.682]],"o":[[0,0],[-4.337,-0.619],[-4.192,6],[-2.994,10.703],[-1.034,8.975],[19.344,-1.793],[-0.826,-10.471],[-0.479,-7.002]],"v":[[-18.099,-21.695],[-32.116,-22.765],[-40.808,-19],[-52.256,1.047],[-58.213,23.275],[-34.094,45.043],[-13.405,19.761],[-15.773,-4.063]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":3,"s":[{"i":[[0,0],[8.324,1.188],[3.808,-1.25],[2.7,-9.654],[1.213,-10.525],[-18.063,1.674],[-0.178,5.41],[0.731,10.682]],"o":[[0,0],[-4.337,-0.619],[-4.192,6],[-2.994,10.703],[-1.034,8.975],[19.344,-1.793],[-0.826,-10.471],[-0.479,-7.002]],"v":[[-18.099,-21.695],[-32.116,-22.765],[-40.808,-19],[-52.256,1.047],[-58.213,23.275],[-34.094,45.043],[-13.405,19.761],[-15.773,-4.063]],"c":true}],"e":[{"i":[[0,0],[12.843,1.833],[4.559,8.938],[3.186,-15.134],[3.035,-13.004],[-27.952,1.396],[-0.275,8.346],[1.128,16.48]],"o":[[0,0],[-6.691,-0.955],[-2.441,12.438],[-4.015,19.071],[-3.168,13.574],[31.05,-1.551],[-1.275,-16.154],[-0.74,-10.803]],"v":[[-2.195,-42.59],[-24.593,-43.083],[-44.559,-47.688],[-56.436,-7.116],[-64.082,27.176],[-28.8,62.301],[4.275,27.154],[0.622,-14.23]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0,0],[12.843,1.833],[4.559,8.938],[3.186,-15.134],[3.035,-13.004],[-27.952,1.396],[-0.275,8.346],[1.128,16.48]],"o":[[0,0],[-6.691,-0.955],[-2.441,12.438],[-4.015,19.071],[-3.168,13.574],[31.05,-1.551],[-1.275,-16.154],[-0.74,-10.803]],"v":[[-2.195,-42.59],[-24.593,-43.083],[-44.559,-47.688],[-56.436,-7.116],[-64.082,27.176],[-28.8,62.301],[4.275,27.154],[0.622,-14.23]],"c":true}],"e":[{"i":[[0,0],[30.844,0.507],[4.059,4.688],[1.936,-11.384],[-2.168,-13.176],[-27.451,0.398],[1.225,11.846],[3.429,20.36]],"o":[[0,0],[-10.157,-0.167],[-1.941,14.188],[-3.267,19.214],[1.6,9.723],[38.05,-0.551],[-1.275,-15.904],[-3.372,-20.02]],"v":[[12.805,-58.84],[-26.843,-38.833],[-49.309,-49.938],[-55.686,-8.616],[-60.582,43.176],[-20.55,70.051],[26.275,28.904],[17.122,-30.23]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[30.844,0.507],[4.059,4.688],[1.936,-11.384],[-2.168,-13.176],[-27.451,0.398],[1.225,11.846],[3.429,20.36]],"o":[[0,0],[-10.157,-0.167],[-1.941,14.188],[-3.267,19.214],[1.6,9.723],[38.05,-0.551],[-1.275,-15.904],[-3.372,-20.02]],"v":[[12.805,-58.84],[-26.843,-38.833],[-49.309,-49.938],[-55.686,-8.616],[-60.582,43.176],[-20.55,70.051],[26.275,28.904],[17.122,-30.23]],"c":true}],"e":[{"i":[[0,0],[-0.089,-0.987],[-0.278,-3.396],[-0.525,-7.148],[-4.945,-5.803],[-9.866,11.148],[0.725,3.596],[6.837,19.482]],"o":[[0,0],[0.121,1.333],[0.323,3.936],[1.428,19.437],[2.832,3.324],[11.55,-13.051],[-1.275,-15.904],[-5.622,-16.02]],"v":[[10.305,-57.09],[10.44,-55.64],[11.04,-48.623],[12.314,-32.116],[21.668,57.426],[44.2,51.551],[54.275,22.904],[39.872,-29.73]],"c":true}]},{"t":6}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":1,"s":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.195,-0.013],[0.819,-14.412]],"v":[[-23.513,-54.481],[-25.144,-53.423],[-32.713,-2.808],[-29.826,7.494],[-26.917,-1.136]],"c":true}],"e":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.195,-0.013],[0.819,-14.412]],"v":[[-31.013,-45.315],[-32.644,-44.256],[-40.213,6.359],[-37.326,16.661],[-34.417,8.03]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":3,"s":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.195,-0.013],[0.819,-14.412]],"v":[[-31.013,-45.315],[-32.644,-44.256],[-40.213,6.359],[-37.326,16.661],[-34.417,8.03]],"c":true}],"e":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.196,-0.013],[0.819,-14.412]],"v":[[-37.096,-52.997],[-38.727,-51.938],[-46.296,-1.323],[-43.159,7.979],[-40.5,0.348]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.196,-0.013],[0.819,-14.412]],"v":[[-37.096,-52.997],[-38.727,-51.938],[-46.296,-1.323],[-43.159,7.979],[-40.5,0.348]],"c":true}],"e":[{"i":[[-0.103,4.085],[4.059,4.688],[1.686,-13.134],[-16.7,0.449],[-0.025,15.596]],"o":[[-5.407,-0.167],[-1.941,14.188],[-2.481,19.331],[7.341,-0.197],[-0.025,-17.404]],"v":[[-31.343,-55.333],[-44.309,-60.438],[-51.186,-11.116],[-42.05,21.551],[-30.225,2.654]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.103,4.085],[4.059,4.688],[1.686,-13.134],[-16.7,0.449],[-0.025,15.596]],"o":[[-5.407,-0.167],[-1.941,14.188],[-2.481,19.331],[7.341,-0.197],[-0.025,-17.404]],"v":[[-31.343,-55.333],[-44.309,-60.438],[-51.186,-11.116],[-42.05,21.551],[-30.225,2.654]],"c":true}],"e":[{"i":[[-0.089,-0.987],[-0.278,-3.396],[-0.525,-7.148],[-9.866,11.148],[0.725,3.596]],"o":[[0.121,1.333],[0.323,3.936],[1.428,19.437],[11.55,-13.051],[-1.275,-15.904]],"v":[[5.773,-76.735],[6.373,-69.719],[7.647,-53.212],[39.533,30.455],[49.608,1.808]],"c":true}]},{"t":6}]},"nm":"B 2"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":1,"op":7,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":22,"ty":4,"nm":"B white layer 2 shadow 2","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-38.124,-198.023],[-153.77,-179.155],[-179.51,0.476],[-152.785,32.892],[-44.446,28.81],[-41.27,-85.157]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-26.124,-205.023],[-141.77,-186.155],[-167.51,-6.524],[-140.785,25.892],[-10.446,30.81],[-18.323,-87.679]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-26.124,-205.023],[-141.77,-186.155],[-167.51,-6.524],[-140.785,25.892],[-10.446,30.81],[-18.323,-87.679]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[-22.446,5.81],[5.009,56.785]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[11.259,-2.914],[-4.977,-56.418]],"v":[[7.876,-190.023],[-107.77,-171.155],[-133.51,8.476],[-106.785,40.892],[16.554,39.31],[20.584,-78.085]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[-22.446,5.81],[5.009,56.785]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[11.259,-2.914],[-4.977,-56.418]],"v":[[7.876,-190.023],[-107.77,-171.155],[-133.51,8.476],[-106.785,40.892],[16.554,39.31],[20.584,-78.085]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,31.5],[9.358,52.957]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-15.801],[-9.297,-52.616]],"v":[[37.5,-220],[-101,-170],[-88,11],[-55,37],[65.5,7],[58.347,-118.825]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,31.5],[9.358,52.957]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-15.801],[-9.297,-52.616]],"v":[[37.5,-220],[-101,-170],[-88,11],[-55,37],[65.5,7],[58.347,-118.825]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,33],[14.123,54.022]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-16.553],[-14.032,-53.673]],"v":[[-38.5,-242],[-236,-164],[-88,11],[-55,36],[8.5,-10],[-8.199,-138.898]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,33],[14.123,54.022]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-16.553],[-14.032,-53.673]],"v":[[-38.5,-242],[-236,-164],[-88,11],[-55,36],[8.5,-10],[-8.199,-138.898]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.976,14.749],[13.055,55.474]],"o":[[0,0],[0,0],[0,0],[50,-11],[8.026,-10.785],[-12.971,-55.116]],"v":[[-61,-230],[-236,-164],[-109,24],[-60,28],[-17,2],[-33.126,-122.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.976,14.749],[13.055,55.474]],"o":[[0,0],[0,0],[0,0],[50,-11],[8.026,-10.785],[-12.971,-55.116]],"v":[[-61,-230],[-236,-164],[-109,24],[-60,28],[-17,2],[-33.126,-122.6]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,14.5],[13.551,58.865]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-7.273],[-13.463,-58.485]],"v":[[-61,-237],[-191,-176],[-109,24],[-76,30],[-11.5,5],[-33.006,-122.007]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,14.5],[13.551,58.865]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-7.273],[-13.463,-58.485]],"v":[[-61,-237],[-191,-176],[-109,24],[-76,30],[-11.5,5],[-33.006,-122.007]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-14,18],[17.568,58.925]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.023,-9.029],[-17.454,-58.545]],"v":[[-56,-244],[-191,-176],[-109,24],[-76,30],[7,0],[-19.42,-129.321]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-14,18],[17.568,58.925]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.023,-9.029],[-17.454,-58.545]],"v":[[-56,-244],[-191,-176],[-109,24],[-76,30],[7,0],[-19.42,-129.321]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-12,13],[17.065,63.067]],"o":[[0,0],[0,0],[0,0],[50,-11],[6.019,-6.521],[-16.954,-62.66]],"v":[[-39,-257],[-191,-176],[-109,24],[-76,30],[23,1],[-3.665,-133.486]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-12,13],[17.065,63.067]],"o":[[0,0],[0,0],[0,0],[50,-11],[6.019,-6.521],[-16.954,-62.66]],"v":[[-39,-257],[-191,-176],[-109,24],[-76,30],[23,1],[-3.665,-133.486]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,17],[17.689,64.569]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-8.528],[-17.575,-64.152]],"v":[[-13,-271],[-191,-176],[-109,24],[-76,30],[53,-5],[23.204,-145]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,17],[17.689,64.569]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-8.528],[-17.575,-64.152]],"v":[[-13,-271],[-191,-176],[-109,24],[-76,30],[53,-5],[23.204,-145]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,20],[23.562,61.869]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.752,-9.689],[-8.438,-57.131]],"v":[[17,-282],[-191,-176],[-109,24],[-76,30],[71,-9],[50.438,-146.869]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,20],[23.562,61.869]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.752,-9.689],[-8.438,-57.131]],"v":[[17,-282],[-191,-176],[-109,24],[-76,30],[71,-9],[50.438,-146.869]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,15],[24.604,34.177]],"o":[[0,0],[0,0],[0,0],[50,-11],[16,-15],[3.604,-39.823]],"v":[[46,-289],[-116,-244],[-109,24],[-51,19],[77,-7],[61.396,-150.177]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,15],[24.604,34.177]],"o":[[0,0],[0,0],[0,0],[50,-11],[16,-15],[3.604,-39.823]],"v":[[46,-289],[-116,-244],[-109,24],[-51,19],[77,-7],[61.396,-150.177]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.999,17.25],[28.431,29.796]],"o":[[0,0],[0,0],[0,0],[50,-11],[10.999,-17.25],[16.431,-29.204]],"v":[[65.252,-286.25],[-116,-244],[-109,24],[-51,19],[88.001,-9.75],[65.569,-132.796]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.999,17.25],[28.431,29.796]],"o":[[0,0],[0,0],[0,0],[50,-11],[10.999,-17.25],[16.431,-29.204]],"v":[[65.252,-286.25],[-116,-244],[-109,24],[-51,19],[88.001,-9.75],[65.569,-132.796]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[50,-11],[0,0],[0,0]],"v":[[92,-282],[-116,-244],[-109,24],[-51,19],[110,22],[100.956,-130.738]],"c":true}]},{"t":19.1474609375}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-1.282,17.269],[-0.661,17.73],[1.838,0.593],[0,0],[0,0],[-1.643,0],[-0.912,-1.481]],"o":[[1.259,-16.963],[0.075,-2.02],[-1.701,-0.549],[0,0],[0,0],[1.257,0],[0.338,-3.231]],"v":[[-41.009,-32.537],[-38.089,-79.48],[-39.588,-83.593],[-42.507,-82.468],[-50.507,4.375],[-47.107,4],[-44.213,5.856]],"c":true}],"e":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}],"e":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}],"e":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}],"e":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}],"e":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}],"e":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}],"e":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}],"e":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}],"e":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}],"e":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}],"e":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}],"e":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}],"e":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}],"e":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}],"e":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}],"e":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}],"e":[{"i":[[23.009,8.287],[0.374,21.444],[37.94,-0.602],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[39.468,0.25],[0.053,-28.967]],"v":[[55.991,-119.287],[79.661,-166.48],[11.162,-226.593],[-79.507,-226.218],[-79.132,-0.25],[22.518,-0.25],[91.162,-62.644]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-276.179,-132.292],[-277.37,-102.994],[-282.552,-101.351],[-288.355,-146.931],[-283.229,-149.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-45.179,-170.292],[-46.37,-140.994],[-51.552,-139.351],[-57.355,-184.931],[-52.229,-187.748]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-45.179,-170.292],[-46.37,-140.994],[-51.552,-139.351],[-57.355,-184.931],[-52.229,-187.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[10.37,-3.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[5.729,-1.752]],"v":[[-29.679,-174.292],[-36.62,-141.244],[-48.302,-138.851],[-53.605,-186.431],[-42.979,-189.748]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-2.196,-15.458],[10.37,-3.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[5.729,-1.752]],"v":[[-29.679,-174.292],[-36.62,-141.244],[-48.302,-138.851],[-53.605,-186.431],[-42.979,-189.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[12.104,-2.127]],"v":[[-14.179,-171.542],[-26.62,-140.744],[-44.802,-137.851],[-48.605,-186.931],[-32.479,-190.998]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.196,-15.458],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[12.104,-2.127]],"v":[[-14.179,-171.542],[-26.62,-140.744],[-44.802,-137.851],[-48.605,-186.931],[-32.479,-190.998]],"c":true}],"e":[{"i":[[-0.946,-15.083],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[0.889,14.172],[0,0],[0,0],[0,0],[11.854,-1.752]],"v":[[-0.554,-168.667],[-16.12,-139.619],[-41.927,-136.351],[-45.105,-186.931],[-21.854,-190.998]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-0.946,-15.083],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[0.889,14.172],[0,0],[0,0],[0,0],[11.854,-1.752]],"v":[[-0.554,-168.667],[-16.12,-139.619],[-41.927,-136.351],[-45.105,-186.931],[-21.854,-190.998]],"c":true}],"e":[{"i":[[0,-14.502],[17.62,-0.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[16.104,-1.752]],"v":[[9.196,-166.167],[-14.62,-138.119],[-39.927,-136.351],[-41.855,-185.931],[-15.354,-189.498]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[0,-14.502],[17.62,-0.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[16.104,-1.752]],"v":[[9.196,-166.167],[-14.62,-138.119],[-39.927,-136.351],[-41.855,-185.931],[-15.354,-189.498]],"c":true}],"e":[{"i":[[0,-14.502],[18.37,-0.631],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[15.303,-0.876]],"v":[[18.196,-164.417],[-8.37,-136.494],[-37.552,-135.101],[-38.855,-185.806],[-8.479,-188.373]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[0,-14.502],[18.37,-0.631],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[15.303,-0.876]],"v":[[18.196,-164.417],[-8.37,-136.494],[-37.552,-135.101],[-38.855,-185.806],[-8.479,-188.373]],"c":true}],"e":[{"i":[[0,-14.502],[19.12,-1.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[24.196,-162.667],[-2.12,-134.869],[-35.177,-133.851],[-35.855,-185.681],[-1.604,-187.248]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[0,-14.502],[19.12,-1.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[24.196,-162.667],[-2.12,-134.869],[-35.177,-133.851],[-35.855,-185.681],[-1.604,-187.248]],"c":true}],"e":[{"i":[[0,-14.502],[18.37,0.935],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[30.446,-160.417],[1.88,-133.369],[-33.177,-133.101],[-33.105,-184.681],[4.646,-184.998]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-287.306,-16.62],[-293.677,-14.62],[-299.802,-64.783],[-294.431,-67.033],[-284.719,-47.051]],"c":true}],"e":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-33.306,-52.62],[-39.677,-50.62],[-45.802,-100.783],[-40.431,-103.033],[-30.719,-83.051]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-33.306,-52.62],[-39.677,-50.62],[-45.802,-100.783],[-40.431,-103.033],[-30.719,-83.051]],"c":true}],"e":[{"i":[[11.556,-3.13],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[8.681,-1.967],[0.969,10.301]],"v":[[-21.806,-51.87],[-37.427,-49.12],[-43.552,-99.783],[-28.431,-103.533],[-13.719,-83.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[11.556,-3.13],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[8.681,-1.967],[0.969,10.301]],"v":[[-21.806,-51.87],[-37.427,-49.12],[-43.552,-99.783],[-28.431,-103.533],[-13.719,-83.551]],"c":true}],"e":[{"i":[[13.181,-3.38],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[14.306,-2.342],[0.969,10.301]],"v":[[-10.556,-49.87],[-36.177,-47.37],[-40.302,-98.783],[-18.181,-102.533],[2.031,-79.801]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.181,-3.38],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[14.306,-2.342],[0.969,10.301]],"v":[[-10.556,-49.87],[-36.177,-47.37],[-40.302,-98.783],[-18.181,-102.533],[2.031,-79.801]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[-5.181,-47.745],[-34.927,-46.745],[-38.427,-97.908],[-7.931,-101.158],[14.156,-75.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[-5.181,-47.745],[-34.927,-46.745],[-38.427,-97.908],[-7.931,-101.158],[14.156,-75.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[2.819,-46.495],[-33.927,-44.495],[-36.427,-96.908],[0.069,-98.908],[23.656,-72.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[2.819,-46.495],[-33.927,-44.495],[-36.427,-96.908],[0.069,-98.908],[23.656,-72.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[16.556,-0.967],[0,14.2]],"v":[[6.819,-45.12],[-33.427,-44.245],[-34.802,-95.783],[5.694,-97.283],[31.781,-71.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[16.556,-0.967],[0,14.2]],"v":[[6.819,-45.12],[-33.427,-44.245],[-34.802,-95.783],[5.694,-97.283],[31.781,-71.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[10.819,-43.745],[-32.927,-43.995],[-33.177,-94.658],[11.319,-95.658],[36.406,-69.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[10.819,-43.745],[-32.927,-43.995],[-33.177,-94.658],[11.319,-95.658],[36.406,-69.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[14.819,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.158],[41.656,-68.176]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":23,"ty":4,"nm":"B white layer 2 shadow","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-38.124,-198.023],[-153.77,-179.155],[-179.51,0.476],[-152.785,32.892],[-44.446,28.81],[-41.27,-85.157]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-26.124,-205.023],[-141.77,-186.155],[-167.51,-6.524],[-140.785,25.892],[-10.446,30.81],[-18.323,-87.679]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-26.124,-205.023],[-141.77,-186.155],[-167.51,-6.524],[-140.785,25.892],[-10.446,30.81],[-18.323,-87.679]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[-22.446,5.81],[5.009,56.785]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[11.259,-2.914],[-4.977,-56.418]],"v":[[7.876,-190.023],[-107.77,-171.155],[-133.51,8.476],[-106.785,40.892],[16.554,39.31],[20.584,-78.085]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[-22.446,5.81],[5.009,56.785]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[11.259,-2.914],[-4.977,-56.418]],"v":[[7.876,-190.023],[-107.77,-171.155],[-133.51,8.476],[-106.785,40.892],[16.554,39.31],[20.584,-78.085]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,31.5],[9.358,52.957]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-15.801],[-9.297,-52.616]],"v":[[37.5,-220],[-101,-170],[-88,11],[-55,37],[65.5,7],[58.347,-118.825]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,31.5],[9.358,52.957]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-15.801],[-9.297,-52.616]],"v":[[37.5,-220],[-101,-170],[-88,11],[-55,37],[65.5,7],[58.347,-118.825]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,33],[14.123,54.022]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-16.553],[-14.032,-53.673]],"v":[[-38.5,-242],[-236,-164],[-88,11],[-55,36],[8.5,-10],[-8.199,-138.898]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,33],[14.123,54.022]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-16.553],[-14.032,-53.673]],"v":[[-38.5,-242],[-236,-164],[-88,11],[-55,36],[8.5,-10],[-8.199,-138.898]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.976,14.749],[13.055,55.474]],"o":[[0,0],[0,0],[0,0],[50,-11],[8.026,-10.785],[-12.971,-55.116]],"v":[[-61,-230],[-236,-164],[-109,24],[-60,28],[-17,2],[-33.126,-122.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.976,14.749],[13.055,55.474]],"o":[[0,0],[0,0],[0,0],[50,-11],[8.026,-10.785],[-12.971,-55.116]],"v":[[-61,-230],[-236,-164],[-109,24],[-60,28],[-17,2],[-33.126,-122.6]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,14.5],[13.551,58.865]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-7.273],[-13.463,-58.485]],"v":[[-61,-237],[-191,-176],[-109,24],[-76,30],[-11.5,5],[-33.006,-122.007]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,14.5],[13.551,58.865]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-7.273],[-13.463,-58.485]],"v":[[-61,-237],[-191,-176],[-109,24],[-76,30],[-11.5,5],[-33.006,-122.007]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-14,18],[17.568,58.925]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.023,-9.029],[-17.454,-58.545]],"v":[[-56,-244],[-191,-176],[-109,24],[-76,30],[7,0],[-19.42,-129.321]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-14,18],[17.568,58.925]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.023,-9.029],[-17.454,-58.545]],"v":[[-56,-244],[-191,-176],[-109,24],[-76,30],[7,0],[-19.42,-129.321]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-12,13],[17.065,63.067]],"o":[[0,0],[0,0],[0,0],[50,-11],[6.019,-6.521],[-16.954,-62.66]],"v":[[-39,-257],[-191,-176],[-109,24],[-76,30],[23,1],[-3.665,-133.486]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-12,13],[17.065,63.067]],"o":[[0,0],[0,0],[0,0],[50,-11],[6.019,-6.521],[-16.954,-62.66]],"v":[[-39,-257],[-191,-176],[-109,24],[-76,30],[23,1],[-3.665,-133.486]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,17],[17.689,64.569]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-8.528],[-17.575,-64.152]],"v":[[-13,-271],[-191,-176],[-109,24],[-76,30],[53,-5],[23.204,-145]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,17],[17.689,64.569]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-8.528],[-17.575,-64.152]],"v":[[-13,-271],[-191,-176],[-109,24],[-76,30],[53,-5],[23.204,-145]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,20],[23.562,61.869]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.752,-9.689],[-8.438,-57.131]],"v":[[17,-282],[-191,-176],[-109,24],[-76,30],[71,-9],[50.438,-146.869]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,20],[23.562,61.869]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.752,-9.689],[-8.438,-57.131]],"v":[[17,-282],[-191,-176],[-109,24],[-76,30],[71,-9],[50.438,-146.869]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,15],[24.604,34.177]],"o":[[0,0],[0,0],[0,0],[50,-11],[16,-15],[3.604,-39.823]],"v":[[46,-289],[-116,-244],[-109,24],[-51,19],[77,-7],[61.396,-150.177]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,15],[24.604,34.177]],"o":[[0,0],[0,0],[0,0],[50,-11],[16,-15],[3.604,-39.823]],"v":[[46,-289],[-116,-244],[-109,24],[-51,19],[77,-7],[61.396,-150.177]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.999,17.25],[28.431,29.796]],"o":[[0,0],[0,0],[0,0],[50,-11],[10.999,-17.25],[16.431,-29.204]],"v":[[65.252,-286.25],[-116,-244],[-109,24],[-51,19],[88.001,-9.75],[65.569,-132.796]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.999,17.25],[28.431,29.796]],"o":[[0,0],[0,0],[0,0],[50,-11],[10.999,-17.25],[16.431,-29.204]],"v":[[65.252,-286.25],[-116,-244],[-109,24],[-51,19],[88.001,-9.75],[65.569,-132.796]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[50,-11],[0,0],[0,0]],"v":[[92,-282],[-116,-244],[-109,24],[-51,19],[110,22],[100.956,-130.738]],"c":true}]},{"t":19.1474609375}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-1.282,17.269],[-0.661,17.73],[1.838,0.593],[0,0],[0,0],[-1.643,0],[-0.912,-1.481]],"o":[[1.259,-16.963],[0.075,-2.02],[-1.701,-0.549],[0,0],[0,0],[1.257,0],[0.338,-3.231]],"v":[[-41.009,-32.537],[-38.089,-79.48],[-39.588,-83.593],[-42.507,-82.468],[-50.507,4.375],[-47.107,4],[-44.213,5.856]],"c":true}],"e":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}],"e":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}],"e":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}],"e":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}],"e":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}],"e":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}],"e":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}],"e":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}],"e":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}],"e":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}],"e":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}],"e":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}],"e":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}],"e":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}],"e":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}],"e":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}],"e":[{"i":[[23.009,8.287],[0.374,21.444],[37.94,-0.602],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[39.468,0.25],[0.053,-28.967]],"v":[[55.991,-119.287],[79.661,-166.48],[11.162,-226.593],[-79.507,-226.218],[-79.132,-0.25],[22.518,-0.25],[91.162,-62.644]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":6,"op":15,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":24,"ty":4,"nm":"B white layer 3","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-1.282,17.269],[-0.661,17.73],[1.838,0.593],[0,0],[0,0],[-1.643,0],[-0.912,-1.481]],"o":[[1.259,-16.963],[0.075,-2.02],[-1.701,-0.549],[0,0],[0,0],[1.257,0],[0.338,-3.231]],"v":[[-41.009,-32.537],[-38.089,-79.48],[-39.588,-83.593],[-42.507,-82.468],[-50.507,4.375],[-47.107,4],[-44.213,5.856]],"c":true}],"e":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}],"e":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}],"e":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}],"e":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}],"e":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}],"e":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}],"e":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}],"e":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}],"e":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}],"e":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}],"e":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}],"e":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}],"e":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}],"e":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}],"e":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}],"e":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}],"e":[{"i":[[23.009,8.287],[0.374,21.444],[37.94,-0.602],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[39.468,0.25],[0.053,-28.967]],"v":[[55.991,-119.287],[79.661,-166.48],[11.162,-226.593],[-79.507,-226.218],[-79.132,-0.25],[22.518,-0.25],[91.162,-62.644]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-276.179,-132.292],[-277.37,-102.994],[-282.552,-101.351],[-288.355,-146.931],[-283.229,-149.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-45.179,-170.292],[-46.37,-140.994],[-51.552,-139.351],[-57.355,-184.931],[-52.229,-187.748]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-45.179,-170.292],[-46.37,-140.994],[-51.552,-139.351],[-57.355,-184.931],[-52.229,-187.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[10.37,-3.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[5.729,-1.752]],"v":[[-29.679,-174.292],[-36.62,-141.244],[-48.302,-138.851],[-53.605,-186.431],[-42.979,-189.748]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-2.196,-15.458],[10.37,-3.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[5.729,-1.752]],"v":[[-29.679,-174.292],[-36.62,-141.244],[-48.302,-138.851],[-53.605,-186.431],[-42.979,-189.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[12.104,-2.127]],"v":[[-14.179,-171.542],[-26.62,-140.744],[-44.802,-137.851],[-48.605,-186.931],[-32.479,-190.998]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.196,-15.458],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[12.104,-2.127]],"v":[[-14.179,-171.542],[-26.62,-140.744],[-44.802,-137.851],[-48.605,-186.931],[-32.479,-190.998]],"c":true}],"e":[{"i":[[-0.946,-15.083],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[0.889,14.172],[0,0],[0,0],[0,0],[11.854,-1.752]],"v":[[-0.554,-168.667],[-16.12,-139.619],[-41.927,-136.351],[-45.105,-186.931],[-21.854,-190.998]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-0.946,-15.083],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[0.889,14.172],[0,0],[0,0],[0,0],[11.854,-1.752]],"v":[[-0.554,-168.667],[-16.12,-139.619],[-41.927,-136.351],[-45.105,-186.931],[-21.854,-190.998]],"c":true}],"e":[{"i":[[0,-14.502],[17.62,-0.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[16.104,-1.752]],"v":[[9.196,-166.167],[-14.62,-138.119],[-39.927,-136.351],[-41.855,-185.931],[-15.354,-189.498]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[0,-14.502],[17.62,-0.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[16.104,-1.752]],"v":[[9.196,-166.167],[-14.62,-138.119],[-39.927,-136.351],[-41.855,-185.931],[-15.354,-189.498]],"c":true}],"e":[{"i":[[0,-14.502],[18.37,-0.631],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[15.303,-0.876]],"v":[[18.196,-164.417],[-8.37,-136.494],[-37.552,-135.101],[-38.855,-185.806],[-8.479,-188.373]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[0,-14.502],[18.37,-0.631],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[15.303,-0.876]],"v":[[18.196,-164.417],[-8.37,-136.494],[-37.552,-135.101],[-38.855,-185.806],[-8.479,-188.373]],"c":true}],"e":[{"i":[[0,-14.502],[19.12,-1.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[24.196,-162.667],[-2.12,-134.869],[-35.177,-133.851],[-35.855,-185.681],[-1.604,-187.248]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[0,-14.502],[19.12,-1.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[24.196,-162.667],[-2.12,-134.869],[-35.177,-133.851],[-35.855,-185.681],[-1.604,-187.248]],"c":true}],"e":[{"i":[[0,-14.502],[18.37,0.935],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[30.446,-160.417],[1.88,-133.369],[-33.177,-133.101],[-33.105,-184.681],[4.646,-184.998]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-287.306,-16.62],[-293.677,-14.62],[-299.802,-64.783],[-294.431,-67.033],[-284.719,-47.051]],"c":true}],"e":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-33.306,-52.62],[-39.677,-50.62],[-45.802,-100.783],[-40.431,-103.033],[-30.719,-83.051]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-33.306,-52.62],[-39.677,-50.62],[-45.802,-100.783],[-40.431,-103.033],[-30.719,-83.051]],"c":true}],"e":[{"i":[[11.556,-3.13],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[8.681,-1.967],[0.969,10.301]],"v":[[-21.806,-51.87],[-37.427,-49.12],[-43.552,-99.783],[-28.431,-103.533],[-13.719,-83.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[11.556,-3.13],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[8.681,-1.967],[0.969,10.301]],"v":[[-21.806,-51.87],[-37.427,-49.12],[-43.552,-99.783],[-28.431,-103.533],[-13.719,-83.551]],"c":true}],"e":[{"i":[[13.181,-3.38],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[14.306,-2.342],[0.969,10.301]],"v":[[-10.556,-49.87],[-36.177,-47.37],[-40.302,-98.783],[-18.181,-102.533],[2.031,-79.801]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.181,-3.38],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[14.306,-2.342],[0.969,10.301]],"v":[[-10.556,-49.87],[-36.177,-47.37],[-40.302,-98.783],[-18.181,-102.533],[2.031,-79.801]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[-5.181,-47.745],[-34.927,-46.745],[-38.427,-97.908],[-7.931,-101.158],[14.156,-75.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[-5.181,-47.745],[-34.927,-46.745],[-38.427,-97.908],[-7.931,-101.158],[14.156,-75.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[2.819,-46.495],[-33.927,-44.495],[-36.427,-96.908],[0.069,-98.908],[23.656,-72.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[2.819,-46.495],[-33.927,-44.495],[-36.427,-96.908],[0.069,-98.908],[23.656,-72.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[16.556,-0.967],[0,14.2]],"v":[[6.819,-45.12],[-33.427,-44.245],[-34.802,-95.783],[5.694,-97.283],[31.781,-71.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[16.556,-0.967],[0,14.2]],"v":[[6.819,-45.12],[-33.427,-44.245],[-34.802,-95.783],[5.694,-97.283],[31.781,-71.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[10.819,-43.745],[-32.927,-43.995],[-33.177,-94.658],[11.319,-95.658],[36.406,-69.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[10.819,-43.745],[-32.927,-43.995],[-33.177,-94.658],[11.319,-95.658],[36.406,-69.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[14.819,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.158],[41.656,-68.176]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":25,"ty":4,"nm":"B white layer 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-1.282,17.269],[-0.661,17.73],[1.838,0.593],[0,0],[0,0],[-1.643,0],[-0.912,-1.481]],"o":[[1.259,-16.963],[0.075,-2.02],[-1.701,-0.549],[0,0],[0,0],[1.257,0],[0.338,-3.231]],"v":[[-41.009,-32.537],[-38.089,-79.48],[-39.588,-83.593],[-42.507,-82.468],[-50.507,4.375],[-47.107,4],[-44.213,5.856]],"c":true}],"e":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}],"e":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}],"e":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}],"e":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}],"e":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}],"e":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}],"e":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}],"e":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}],"e":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}],"e":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}],"e":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}],"e":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}],"e":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}],"e":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}],"e":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}],"e":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}],"e":[{"i":[[23.009,8.287],[0.374,21.444],[37.94,-0.602],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[39.468,0.25],[0.053,-28.967]],"v":[[55.991,-119.287],[79.661,-166.48],[11.162,-226.593],[-79.507,-226.218],[-79.132,-0.25],[22.518,-0.25],[91.162,-62.644]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":5,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":26,"ty":4,"nm":"B light blue layer 3 shadow 2","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[4.596,42.859],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-5.931,-55.302],[0,0]],"v":[[-58.13,-221.16],[-111.991,-226.753],[-103.289,41.823],[-46.069,-81.698],[-54.696,-253.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[9.482,45.79],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-11.278,-54.464],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[-0.569,37.802],[-54.696,-253.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[9.482,45.79],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-11.278,-54.464],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[-0.569,37.802],[-54.696,-253.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[42.431,32.302],[11.804,-249.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[42.431,32.302],[11.804,-249.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[70.931,-10.698],[8.304,-239.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[70.931,-10.698],[8.304,-239.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[59,30],[-33,-263]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[59,30],[-33,-263]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[41,8],[-35,-264]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[41,8],[-35,-264]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[-1,39],[0,0]],"o":[[0,0],[0,0],[3,-1],[1.444,-56.302],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[70,-17],[3,-268]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[-3,1],[-1,39],[0,0]],"o":[[0,0],[0,0],[3,-1],[1.444,-56.302],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[70,-17],[3,-268]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-9],[28,-280]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-9],[28,-280]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-19],[50,-287]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-19],[50,-287]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[116,-7],[70,-285]],"c":true}]},{"t":18}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.201,21.411],[-0.286,15.23],[2.474,0.203],[0,0],[0,0],[-1.893,-0.375],[-0.662,-1.856]],"o":[[0.134,-14.338],[0.036,-1.896],[-1.912,-0.157],[0,0],[0,0],[0.644,0.128],[1.338,-20.856]],"v":[[-46.509,-50.162],[-44.214,-98.23],[-45.963,-101.593],[-49.132,-100.593],[-55.007,4.75],[-50.857,4.25],[-48.588,6.856]],"c":true}],"e":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}],"e":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}],"e":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}],"e":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}],"e":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}],"e":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}],"e":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}],"e":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}],"e":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}],"e":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}],"e":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}],"e":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}],"e":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}],"e":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}],"e":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[32.213,-0.907],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.241,-119.787],[79.411,-168.105],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[90.787,-62.894]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-268.103,-143.239],[-271.189,-115.936],[-276.731,-115.148],[-282.154,-159.988],[-277.112,-161.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-36.103,-162.739],[-39.189,-135.436],[-44.731,-134.648],[-50.154,-179.488],[-45.112,-180.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-36.103,-162.739],[-39.189,-135.436],[-44.731,-134.648],[-50.154,-179.488],[-45.112,-180.776]],"c":true}],"e":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[7.862,-1.724]],"v":[[-22.103,-167.239],[-29.189,-138.186],[-43.481,-135.648],[-49.154,-181.988],[-37.862,-184.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[7.862,-1.724]],"v":[[-22.103,-167.239],[-29.189,-138.186],[-43.481,-135.648],[-49.154,-181.988],[-37.862,-184.776]],"c":true}],"e":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[10.862,0.026]],"v":[[-9.353,-166.739],[-20.189,-138.686],[-42.231,-135.648],[-46.654,-183.988],[-26.862,-187.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[10.862,0.026]],"v":[[-9.353,-166.739],[-20.189,-138.686],[-42.231,-135.648],[-46.654,-183.988],[-26.862,-187.276]],"c":true}],"e":[{"i":[[-1.634,-14.432],[15.643,-0.316],[0,0],[0,0],[0,0]],"o":[[1.499,13.233],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[1.501,-165.483],[-19.143,-137.184],[-39.891,-135.152],[-43.647,-185.494],[-18.285,-187.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-1.634,-14.432],[15.643,-0.316],[0,0],[0,0],[0,0]],"o":[[1.499,13.233],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[1.501,-165.483],[-19.143,-137.184],[-39.891,-135.152],[-43.647,-185.494],[-18.285,-187.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[10.147,-167.739],[-8.939,-136.936],[-38.481,-134.898],[-40.154,-185.488],[-12.862,-186.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[10.147,-167.739],[-8.939,-136.936],[-38.481,-134.898],[-40.154,-185.488],[-12.862,-186.776]],"c":true}],"e":[{"i":[[-1.534,-14.395],[14.273,-2.231],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.778,1.383]],"v":[[17.998,-164.132],[-2.523,-136.269],[-36.047,-134.41],[-37.912,-185.525],[-5.028,-187.133]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[14.273,-2.231],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.778,1.383]],"v":[[17.998,-164.132],[-2.523,-136.269],[-36.047,-134.41],[-37.912,-185.525],[-5.028,-187.133]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[23.139,-163.775],[0.762,-135.102],[-34.862,-134.172],[-35.92,-185.061],[-3.241,-186.241]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[23.139,-163.775],[0.762,-135.102],[-34.862,-134.172],[-35.92,-185.061],[-3.241,-186.241]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[27.029,-160.917],[4.297,-134.435],[-33.677,-133.685],[-33.677,-184.598],[2.797,-185.348]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[27.029,-160.917],[4.297,-134.435],[-33.677,-133.685],[-33.677,-184.598],[2.797,-185.348]],"c":true}],"e":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[30.363,-160.417],[4.963,-133.935],[-32.927,-133.268],[-32.927,-184.014],[3.297,-184.848]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-272.931,-26.995],[-280.427,-25.995],[-286.427,-75.158],[-279.181,-76.658],[-269.094,-56.926]],"c":true}],"e":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-25.931,-49.995],[-33.427,-48.995],[-39.427,-98.158],[-32.181,-99.658],[-22.094,-79.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-25.931,-49.995],[-33.427,-48.995],[-39.427,-98.158],[-32.181,-99.658],[-22.094,-79.926]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[7.681,-0.842],[2.589,13.962]],"v":[[-17.681,-50.245],[-33.677,-48.495],[-39.427,-98.158],[-22.431,-100.908],[-7.094,-82.426]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[7.681,-0.842],[2.589,13.962]],"v":[[-17.681,-50.245],[-33.677,-48.495],[-39.427,-98.158],[-22.431,-100.908],[-7.094,-82.426]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.931,0.158],[2.589,13.962]],"v":[[-9.181,-49.745],[-33.677,-47.745],[-37.927,-97.908],[-12.681,-100.908],[5.906,-78.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.931,0.158],[2.589,13.962]],"v":[[-9.181,-49.745],[-33.677,-47.745],[-37.927,-97.908],[-12.681,-100.908],[5.906,-78.676]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-1.406,-16.074]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[1.237,14.146]],"v":[[-2.681,-47.745],[-34.177,-45.745],[-36.927,-96.908],[-7.181,-99.908],[16.656,-76.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-1.406,-16.074]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[1.237,14.146]],"v":[[-2.681,-47.745],[-34.177,-45.745],[-36.927,-96.908],[-7.181,-99.908],[16.656,-76.926]],"c":true}],"e":[{"i":[[12.181,0.495],[0,0],[0,0],[0,0],[-0.906,-12.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.041,14.162]],"v":[[3.069,-47.245],[-32.927,-45.495],[-35.677,-96.408],[1.819,-98.408],[24.906,-73.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[12.181,0.495],[0,0],[0,0],[0,0],[-0.906,-12.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.041,14.162]],"v":[[3.069,-47.245],[-32.927,-45.495],[-35.677,-96.408],[1.819,-98.408],[24.906,-73.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.264,-12.571]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.261,12.426]],"v":[[8.652,-45.745],[-33.344,-44.412],[-34.844,-95.658],[6.902,-97.325],[31.239,-71.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.264,-12.571]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.261,12.426]],"v":[[8.652,-45.745],[-33.344,-44.412],[-34.844,-95.658],[6.902,-97.325],[31.239,-71.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[10.735,-44.495],[-33.261,-43.579],[-33.761,-94.908],[11.235,-95.742],[35.822,-70.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[10.735,-44.495],[-33.261,-43.579],[-33.761,-94.908],[11.235,-95.742],[35.822,-70.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[12.681,0.408],[0,14.2]],"v":[[14.319,-43.995],[-32.677,-43.245],[-33.177,-93.658],[16.569,-94.658],[39.156,-68.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[12.681,0.408],[0,14.2]],"v":[[14.319,-43.995],[-32.677,-43.245],[-33.177,-93.658],[16.569,-94.658],[39.156,-68.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[14.819,-42.745],[-32.677,-41.995],[-32.677,-93.658],[16.069,-94.158],[41.406,-67.926]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":27,"ty":4,"nm":"B light blue layer 3 shadow","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[4.596,42.859],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-5.931,-55.302],[0,0]],"v":[[-58.13,-221.16],[-111.991,-226.753],[-103.289,41.823],[-46.069,-81.698],[-54.696,-253.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[9.482,45.79],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-11.278,-54.464],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[-0.569,37.802],[-54.696,-253.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[9.482,45.79],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-11.278,-54.464],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[-0.569,37.802],[-54.696,-253.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[42.431,32.302],[11.804,-249.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[42.431,32.302],[11.804,-249.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[70.931,-10.698],[8.304,-239.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[70.931,-10.698],[8.304,-239.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[59,30],[-33,-263]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[59,30],[-33,-263]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[41,8],[-35,-264]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[41,8],[-35,-264]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[-1,39],[0,0]],"o":[[0,0],[0,0],[3,-1],[1.444,-56.302],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[70,-17],[3,-268]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[-3,1],[-1,39],[0,0]],"o":[[0,0],[0,0],[3,-1],[1.444,-56.302],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[70,-17],[3,-268]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-9],[28,-280]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-9],[28,-280]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-19],[50,-287]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-19],[50,-287]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[116,-7],[70,-285]],"c":true}]},{"t":18}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.201,21.411],[-0.286,15.23],[2.474,0.203],[0,0],[0,0],[-1.893,-0.375],[-0.662,-1.856]],"o":[[0.134,-14.338],[0.036,-1.896],[-1.912,-0.157],[0,0],[0,0],[0.644,0.128],[1.338,-20.856]],"v":[[-46.509,-50.162],[-44.214,-98.23],[-45.963,-101.593],[-49.132,-100.593],[-55.007,4.75],[-50.857,4.25],[-48.588,6.856]],"c":true}],"e":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}],"e":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}],"e":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}],"e":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}],"e":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}],"e":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}],"e":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}],"e":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}],"e":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}],"e":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}],"e":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}],"e":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}],"e":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}],"e":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}],"e":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[32.213,-0.907],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.241,-119.787],[79.411,-168.105],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[90.787,-62.894]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":7,"op":15,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":28,"ty":4,"nm":"B light blue layer 4","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.201,21.411],[-0.286,15.23],[2.474,0.203],[0,0],[0,0],[-1.893,-0.375],[-0.662,-1.856]],"o":[[0.134,-14.338],[0.036,-1.896],[-1.912,-0.157],[0,0],[0,0],[0.644,0.128],[1.338,-20.856]],"v":[[-46.509,-50.162],[-44.214,-98.23],[-45.963,-101.593],[-49.132,-100.593],[-55.007,4.75],[-50.857,4.25],[-48.588,6.856]],"c":true}],"e":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}],"e":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}],"e":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}],"e":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}],"e":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}],"e":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}],"e":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}],"e":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}],"e":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}],"e":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}],"e":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}],"e":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}],"e":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}],"e":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}],"e":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[32.213,-0.907],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.241,-119.787],[79.411,-168.105],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[90.787,-62.894]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-268.103,-143.239],[-271.189,-115.936],[-276.731,-115.148],[-282.154,-159.988],[-277.112,-161.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-36.103,-162.739],[-39.189,-135.436],[-44.731,-134.648],[-50.154,-179.488],[-45.112,-180.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-36.103,-162.739],[-39.189,-135.436],[-44.731,-134.648],[-50.154,-179.488],[-45.112,-180.776]],"c":true}],"e":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[7.862,-1.724]],"v":[[-22.103,-167.239],[-29.189,-138.186],[-43.481,-135.648],[-49.154,-181.988],[-37.862,-184.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[7.862,-1.724]],"v":[[-22.103,-167.239],[-29.189,-138.186],[-43.481,-135.648],[-49.154,-181.988],[-37.862,-184.776]],"c":true}],"e":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[10.862,0.026]],"v":[[-9.353,-166.739],[-20.189,-138.686],[-42.231,-135.648],[-46.654,-183.988],[-26.862,-187.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[10.862,0.026]],"v":[[-9.353,-166.739],[-20.189,-138.686],[-42.231,-135.648],[-46.654,-183.988],[-26.862,-187.276]],"c":true}],"e":[{"i":[[-1.634,-14.432],[15.643,-0.316],[0,0],[0,0],[0,0]],"o":[[1.499,13.233],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[1.501,-165.483],[-19.143,-137.184],[-39.891,-135.152],[-43.647,-185.494],[-18.285,-187.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-1.634,-14.432],[15.643,-0.316],[0,0],[0,0],[0,0]],"o":[[1.499,13.233],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[1.501,-165.483],[-19.143,-137.184],[-39.891,-135.152],[-43.647,-185.494],[-18.285,-187.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[10.147,-167.739],[-8.939,-136.936],[-38.481,-134.898],[-40.154,-185.488],[-12.862,-186.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[10.147,-167.739],[-8.939,-136.936],[-38.481,-134.898],[-40.154,-185.488],[-12.862,-186.776]],"c":true}],"e":[{"i":[[-1.534,-14.395],[14.273,-2.231],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.778,1.383]],"v":[[17.998,-164.132],[-2.523,-136.269],[-36.047,-134.41],[-37.912,-185.525],[-5.028,-187.133]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[14.273,-2.231],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.778,1.383]],"v":[[17.998,-164.132],[-2.523,-136.269],[-36.047,-134.41],[-37.912,-185.525],[-5.028,-187.133]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[23.139,-163.775],[0.762,-135.102],[-34.862,-134.172],[-35.92,-185.061],[-3.241,-186.241]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[23.139,-163.775],[0.762,-135.102],[-34.862,-134.172],[-35.92,-185.061],[-3.241,-186.241]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[27.029,-160.917],[4.297,-134.435],[-33.677,-133.685],[-33.677,-184.598],[2.797,-185.348]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[27.029,-160.917],[4.297,-134.435],[-33.677,-133.685],[-33.677,-184.598],[2.797,-185.348]],"c":true}],"e":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[30.363,-160.417],[4.963,-133.935],[-32.927,-133.268],[-32.927,-184.014],[3.297,-184.848]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-272.931,-26.995],[-280.427,-25.995],[-286.427,-75.158],[-279.181,-76.658],[-269.094,-56.926]],"c":true}],"e":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-25.931,-49.995],[-33.427,-48.995],[-39.427,-98.158],[-32.181,-99.658],[-22.094,-79.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-25.931,-49.995],[-33.427,-48.995],[-39.427,-98.158],[-32.181,-99.658],[-22.094,-79.926]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[7.681,-0.842],[2.589,13.962]],"v":[[-17.681,-50.245],[-33.677,-48.495],[-39.427,-98.158],[-22.431,-100.908],[-7.094,-82.426]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[7.681,-0.842],[2.589,13.962]],"v":[[-17.681,-50.245],[-33.677,-48.495],[-39.427,-98.158],[-22.431,-100.908],[-7.094,-82.426]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.931,0.158],[2.589,13.962]],"v":[[-9.181,-49.745],[-33.677,-47.745],[-37.927,-97.908],[-12.681,-100.908],[5.906,-78.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.931,0.158],[2.589,13.962]],"v":[[-9.181,-49.745],[-33.677,-47.745],[-37.927,-97.908],[-12.681,-100.908],[5.906,-78.676]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-1.406,-16.074]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[1.237,14.146]],"v":[[-2.681,-47.745],[-34.177,-45.745],[-36.927,-96.908],[-7.181,-99.908],[16.656,-76.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-1.406,-16.074]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[1.237,14.146]],"v":[[-2.681,-47.745],[-34.177,-45.745],[-36.927,-96.908],[-7.181,-99.908],[16.656,-76.926]],"c":true}],"e":[{"i":[[12.181,0.495],[0,0],[0,0],[0,0],[-0.906,-12.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.041,14.162]],"v":[[3.069,-47.245],[-32.927,-45.495],[-35.677,-96.408],[1.819,-98.408],[24.906,-73.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[12.181,0.495],[0,0],[0,0],[0,0],[-0.906,-12.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.041,14.162]],"v":[[3.069,-47.245],[-32.927,-45.495],[-35.677,-96.408],[1.819,-98.408],[24.906,-73.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.264,-12.571]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.261,12.426]],"v":[[8.652,-45.745],[-33.344,-44.412],[-34.844,-95.658],[6.902,-97.325],[31.239,-71.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.264,-12.571]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.261,12.426]],"v":[[8.652,-45.745],[-33.344,-44.412],[-34.844,-95.658],[6.902,-97.325],[31.239,-71.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[10.735,-44.495],[-33.261,-43.579],[-33.761,-94.908],[11.235,-95.742],[35.822,-70.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[10.735,-44.495],[-33.261,-43.579],[-33.761,-94.908],[11.235,-95.742],[35.822,-70.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[12.681,0.408],[0,14.2]],"v":[[14.319,-43.995],[-32.677,-43.245],[-33.177,-93.658],[16.569,-94.658],[39.156,-68.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[12.681,0.408],[0,14.2]],"v":[[14.319,-43.995],[-32.677,-43.245],[-33.177,-93.658],[16.569,-94.658],[39.156,-68.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[14.819,-42.745],[-32.677,-41.995],[-32.677,-93.658],[16.069,-94.158],[41.406,-67.926]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":29,"ty":4,"nm":"B light blue layer 3","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.201,21.411],[-0.286,15.23],[2.474,0.203],[0,0],[0,0],[-1.893,-0.375],[-0.662,-1.856]],"o":[[0.134,-14.338],[0.036,-1.896],[-1.912,-0.157],[0,0],[0,0],[0.644,0.128],[1.338,-20.856]],"v":[[-46.509,-50.162],[-44.214,-98.23],[-45.963,-101.593],[-49.132,-100.593],[-55.007,4.75],[-50.857,4.25],[-48.588,6.856]],"c":true}],"e":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}],"e":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}],"e":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}],"e":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}],"e":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}],"e":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}],"e":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}],"e":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}],"e":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}],"e":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}],"e":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}],"e":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}],"e":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}],"e":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}],"e":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[32.213,-0.907],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.241,-119.787],[79.411,-168.105],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[90.787,-62.894]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":6,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":30,"ty":4,"nm":"B light blue layer 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-0.899,27.404],[-1.161,21.73],[-2.043,1.082],[0,0],[0,0],[1.78,-1.142],[1.963,-3.606]],"o":[[0.634,-19.338],[0.161,-3.017],[1.713,-0.907],[0,0],[0,0],[-2.143,1.375],[-0.037,-20.106]],"v":[[-64.884,-51.412],[-61.589,-110.48],[-56.963,-116.843],[-53.507,-117.468],[-55.257,2.75],[-61.857,5.625],[-66.463,11.356]],"c":true}},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":7,"op":8,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":31,"ty":4,"nm":"B light blue layer 1","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[2.067,0.035],[0.272,0.321],[0.13,-0.779],[-0.356,-1.134],[-1.495,0.021],[0.012,0.775],[0.067,1.41]],"o":[[0,0],[-0.681,-0.011],[-0.197,0.927],[-0.219,1.314],[0.201,0.642],[2.094,-0.03],[0.082,-1.953],[-0.078,-1.64]],"v":[[-48.938,-1.125],[-52.016,0.387],[-54.014,-0.086],[-54.792,2.812],[-54.769,6.713],[-51.876,8.407],[-48.457,5.952],[-48.648,1.19]],"c":true}],"e":[{"i":[[0,0],[8.009,0.121],[1.054,1.117],[0.503,-2.712],[-1.38,-3.952],[-5.796,0.074],[0.046,2.698],[0.26,4.913]],"o":[[0,0],[-2.637,-0.04],[-0.765,3.23],[-0.848,4.577],[0.781,2.235],[8.117,-0.104],[0.318,-6.802],[-0.303,-5.714]],"v":[[-41.806,-11.476],[-53.736,-6.21],[-62.84,-11.105],[-65.858,1.238],[-65.495,16.577],[-54.51,22.479],[-39.943,14.677],[-40.685,-3.661]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[8.009,0.121],[1.054,1.117],[0.503,-2.712],[-1.38,-3.952],[-5.796,0.074],[0.046,2.698],[0.26,4.913]],"o":[[0,0],[-2.637,-0.04],[-0.765,3.23],[-0.848,4.577],[0.781,2.235],[8.117,-0.104],[0.318,-6.802],[-0.303,-5.714]],"v":[[-41.806,-11.476],[-53.736,-6.21],[-62.84,-11.105],[-65.858,1.238],[-65.495,16.577],[-54.51,22.479],[-39.943,14.677],[-40.685,-3.661]],"c":true}],"e":[{"i":[[0,0],[18.114,0.262],[4.357,-2.3],[0.602,-17.382],[-1.273,-6.802],[-19.282,0.006],[0.47,7.998],[1.175,10.637]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-0.349,10.097],[0.939,5.019],[22.347,-0.007],[-0.749,-8.21],[-1.405,-12.724]],"v":[[-32.13,-94.796],[-52.413,-95.468],[-69.857,-95.45],[-70.102,-37.118],[-69.977,24.12],[-51.218,42.744],[-15.72,20.252],[-22.595,-20.776]],"c":true}]},{"t":8}]},"nm":"B"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":6,"op":9,"st":2,"bm":0,"sr":1},{"ddd":0,"ind":32,"ty":4,"nm":"B white layer 1","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[2.067,0.035],[0.272,0.321],[0.13,-0.779],[-0.356,-1.134],[-1.495,0.021],[0.012,0.775],[0.067,1.41]],"o":[[0,0],[-0.681,-0.011],[-0.197,0.927],[-0.219,1.314],[0.201,0.642],[2.094,-0.03],[0.082,-1.953],[-0.078,-1.64]],"v":[[-45.188,-1.125],[-48.266,0.387],[-50.264,-0.086],[-51.042,2.812],[-51.019,6.713],[-48.126,8.407],[-44.707,5.952],[-44.898,1.19]],"c":true}],"e":[{"i":[[0,0],[7.348,0.121],[0.967,1.117],[0.461,-2.712],[-1.266,-3.952],[-5.317,0.074],[0.042,2.698],[0.239,4.913]],"o":[[0,0],[-2.42,-0.04],[-0.702,3.23],[-0.778,4.577],[0.716,2.235],[7.447,-0.104],[0.292,-6.802],[-0.278,-5.714]],"v":[[-36.501,-11.351],[-47.446,-6.085],[-55.798,-10.98],[-58.567,1.363],[-58.234,15.952],[-47.697,21.854],[-34.792,13.302],[-35.472,-3.536]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[7.348,0.121],[0.967,1.117],[0.461,-2.712],[-1.266,-3.952],[-5.317,0.074],[0.042,2.698],[0.239,4.913]],"o":[[0,0],[-2.42,-0.04],[-0.702,3.23],[-0.778,4.577],[0.716,2.235],[7.447,-0.104],[0.292,-6.802],[-0.278,-5.714]],"v":[[-36.501,-11.351],[-47.446,-6.085],[-55.798,-10.98],[-58.567,1.363],[-58.234,15.952],[-47.697,21.854],[-34.792,13.302],[-35.472,-3.536]],"c":true}],"e":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[1.102,-14.882],[-1.273,-6.802],[-19.282,0.006],[0.47,7.998],[1.175,10.637]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-0.746,10.075],[0.939,5.019],[22.347,-0.007],[-0.749,-8.211],[-1.405,-12.724]],"v":[[-20.38,-97.546],[-49.163,-91.968],[-61.857,-100.7],[-65.602,-41.118],[-67.977,23.12],[-40.968,39.244],[-11.22,17.752],[-14.595,-21.526]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[1.102,-14.882],[-1.273,-6.802],[-19.282,0.006],[0.47,7.998],[1.175,10.637]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-0.746,10.075],[0.939,5.019],[22.347,-0.007],[-0.749,-8.211],[-1.405,-12.724]],"v":[[-20.38,-97.546],[-49.163,-91.968],[-61.857,-100.7],[-65.602,-41.118],[-67.977,23.12],[-40.968,39.244],[-11.22,17.752],[-14.595,-21.526]],"c":true}],"e":[{"i":[[0,0],[5.836,-0.538],[0.9,1.062],[-1.035,-10.477],[-0.481,-2.985],[-4.731,0.661],[-0.012,3.839],[1.64,5.168]],"o":[[0,0],[-2.242,0.207],[0.323,6.451],[0.436,4.412],[0.355,2.203],[8.337,-1.165],[-0.012,-6.693],[-1.375,-4.332]],"v":[[33.321,-6.126],[25.664,-9.212],[19,-11.513],[22.285,15.477],[25.087,31.97],[31.697,39.589],[41.03,25.38],[38.496,8.259]],"c":true}]},{"t":8}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.007,0.279],[0.272,0.321],[0.079,-0.813],[-1.102,-0.004],[0.001,1.067]],"o":[[-0.362,-0.011],[-0.13,0.97],[-0.13,1.326],[0.541,0.002],[-0.002,-1.19]],"v":[[-254.943,4.83],[-255.945,4.464],[-256.48,7.854],[-255.801,10.105],[-255.008,8.796]],"c":true}],"e":[{"i":[[-0.025,0.973],[0.967,1.117],[0.283,-2.831],[-3.919,-0.012],[0.005,3.715]],"o":[[-1.288,-0.04],[-0.462,3.38],[-0.461,4.62],[1.925,0.006],[-0.006,-4.146]],"v":[[-49.268,-10.266],[-52.833,-11.541],[-54.733,0.268],[-52.319,8.11],[-49.502,3.548]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.025,0.973],[0.967,1.117],[0.283,-2.831],[-3.919,-0.012],[0.005,3.715]],"o":[[-1.288,-0.04],[-0.462,3.38],[-0.461,4.62],[1.925,0.006],[-0.006,-4.146]],"v":[[-49.268,-10.266],[-52.833,-11.541],[-54.733,0.268],[-52.319,8.11],[-49.502,3.548]],"c":true}],"e":[{"i":[[-0.103,2.475],[4.052,2.841],[0.919,-10.247],[-10.422,0.015],[0.022,12.118]],"o":[[-5.362,-2.495],[-1.938,8.597],[-0.804,8.962],[8.067,-0.012],[-0.019,-10.546]],"v":[[-44.638,-94.255],[-60.829,-101],[-66.196,3.288],[-56.078,21.235],[-40.272,8.382]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[-0.103,2.475],[4.052,2.841],[0.919,-10.247],[-10.422,0.015],[0.022,12.118]],"o":[[-5.362,-2.495],[-1.938,8.597],[-0.804,8.962],[8.067,-0.012],[-0.019,-10.546]],"v":[[-44.638,-94.255],[-60.829,-101],[-66.196,3.288],[-56.078,21.235],[-40.272,8.382]],"c":true}],"e":[{"i":[[-0.061,2.109],[3.595,-2.75],[0.696,-6.135],[-9.66,-0.026],[0.013,8.051]],"o":[[-3.175,-0.086],[-1.14,7.324],[-1.137,10.012],[4.745,0.013],[-0.015,-8.985]],"v":[[-56.056,-36.486],[-75.595,-26.5],[-76.296,12.591],[-66.594,33.585],[-52.9,17.2]],"c":true}]},{"t":8}]},"nm":"B 2"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":5,"op":9,"st":1,"bm":0,"sr":1},{"ddd":0,"ind":33,"ty":4,"nm":"B orange layer 1","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0,0],[2.067,0.035],[0.272,0.321],[0.13,-0.779],[-0.356,-1.134],[-1.495,0.021],[0.012,0.775],[0.067,1.41]],"o":[[0,0],[-0.681,-0.011],[-0.197,0.927],[-0.219,1.314],[0.201,0.642],[2.094,-0.03],[0.082,-1.953],[-0.078,-1.64]],"v":[[-40.938,-1],[-44.016,0.512],[-46.014,0.039],[-46.792,2.937],[-46.769,6.838],[-43.876,9.032],[-40.457,6.077],[-40.648,1.315]],"c":true}],"e":[{"i":[[0,0],[7.348,0.121],[0.967,1.117],[0.461,-2.712],[-1.266,-3.952],[-5.317,0.074],[0.042,2.698],[0.239,4.913]],"o":[[0,0],[-2.42,-0.04],[-0.702,3.23],[-0.778,4.577],[0.716,2.235],[7.447,-0.104],[0.292,-6.802],[-0.278,-5.714]],"v":[[-32.501,-11.351],[-43.446,-6.085],[-50.548,-7.73],[-53.317,2.363],[-53.734,15.952],[-42.697,22.604],[-30.292,13.552],[-31.472,-3.286]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[7.348,0.121],[0.967,1.117],[0.461,-2.712],[-1.266,-3.952],[-5.317,0.074],[0.042,2.698],[0.239,4.913]],"o":[[0,0],[-2.42,-0.04],[-0.702,3.23],[-0.778,4.577],[0.716,2.235],[7.447,-0.104],[0.292,-6.802],[-0.278,-5.714]],"v":[[-32.501,-11.351],[-43.446,-6.085],[-50.548,-7.73],[-53.317,2.363],[-53.734,15.952],[-42.697,22.604],[-30.292,13.552],[-31.472,-3.286]],"c":true}],"e":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[1.602,-8.382],[-1.273,-6.802],[-16.121,0.205],[0.47,7.998],[2.014,10.511]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-1.896,9.923],[0.939,5.019],[22.345,-0.285],[-0.749,-8.211],[-1.98,-10.335]],"v":[[-16.38,-29.046],[-39.663,-18.718],[-54.607,-25.2],[-57.602,-5.368],[-59.727,23.12],[-35.218,37.244],[-9.72,15.252],[-13.845,-14.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[1.602,-8.382],[-1.273,-6.802],[-16.121,0.205],[0.47,7.998],[2.014,10.511]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-1.896,9.923],[0.939,5.019],[22.345,-0.285],[-0.749,-8.211],[-1.98,-10.335]],"v":[[-16.38,-29.046],[-39.663,-18.718],[-54.607,-25.2],[-57.602,-5.368],[-59.727,23.12],[-35.218,37.244],[-9.72,15.252],[-13.845,-14.276]],"c":true}],"e":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[0.352,-20.882],[-1.273,-6.802],[-12.532,1.506],[-0.03,8.748],[4.345,11.776]],"o":[[0,0],[-5.965,-0.086],[0.857,14.7],[-0.17,10.101],[0.939,5.019],[22.085,-2.655],[-0.03,-15.252],[-3.642,-9.873]],"v":[[7.12,-52.546],[-13.163,-60.718],[-24.857,-45.45],[-24.102,2.382],[-21.977,37.12],[-4.468,50.494],[29.53,19.252],[22.155,-15.776]],"c":true}]},{"t":7}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.007,0.279],[0.272,0.321],[0.079,-0.813],[-1.102,-0.004],[0.001,1.067]],"o":[[-0.362,-0.011],[-0.13,0.97],[-0.13,1.326],[0.541,0.002],[-0.002,-1.19]],"v":[[-254.943,4.83],[-255.945,4.464],[-256.48,7.854],[-255.801,10.105],[-255.008,8.796]],"c":true}],"e":[{"i":[[-0.025,0.973],[0.967,1.117],[0.283,-2.831],[-3.919,-0.012],[0.005,3.715]],"o":[[-1.288,-0.04],[-0.462,3.38],[-0.461,4.62],[1.925,0.006],[-0.006,-4.146]],"v":[[-44.518,-9.766],[-48.083,-11.041],[-49.983,0.768],[-47.319,8.11],[-44.752,2.798]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.025,0.973],[0.967,1.117],[0.283,-2.831],[-3.919,-0.012],[0.005,3.715]],"o":[[-1.288,-0.04],[-0.462,3.38],[-0.461,4.62],[1.925,0.006],[-0.006,-4.146]],"v":[[-44.518,-9.766],[-48.083,-11.041],[-49.983,0.768],[-47.319,8.11],[-44.752,2.798]],"c":true}],"e":[{"i":[[-0.103,2.475],[4.052,2.841],[1.184,-7.201],[-11.422,1.515],[0.022,9.45]],"o":[[-5.398,-0.101],[-1.938,8.597],[-1.932,11.751],[7.997,-1.061],[-0.025,-10.546]],"v":[[-35.638,-26.505],[-50.579,-29.75],[-56.696,0.288],[-45.828,20.985],[-35.272,6.382]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.103,2.475],[4.052,2.841],[1.184,-7.201],[-11.422,1.515],[0.022,9.45]],"o":[[-5.398,-0.101],[-1.938,8.597],[-1.932,11.751],[7.997,-1.061],[-0.025,-10.546]],"v":[[-35.638,-26.505],[-50.579,-29.75],[-56.696,0.288],[-45.828,20.985],[-35.272,6.382]],"c":true}],"e":[{"i":[[-0.061,2.109],[3.595,-2.75],[0.696,-6.135],[-9.66,-0.026],[0.013,8.051]],"o":[[-3.175,-0.086],[-1.14,7.324],[-1.137,10.012],[4.745,0.013],[-0.015,-8.985]],"v":[[-15.306,-36.486],[-34.095,-25],[-34.796,14.091],[-25.094,35.085],[-12.4,18.95]],"c":true}]},{"t":7}]},"nm":"B 2"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":4,"op":8,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":34,"ty":1,"nm":"ResizerTemp","parent":35,"ks":{"o":{"k":0},"r":{"k":0},"p":{"k":[74,102,0]},"a":{"k":[250,300,0]},"s":{"k":[30,30,100]}},"ao":0,"sw":500,"sh":600,"sc":"#ffffff","ip":0,"op":37,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":35,"ty":1,"nm":"White Solid 8","ks":{"o":{"k":0},"r":{"k":0},"p":{"k":[40,50,0]},"a":{"k":[70,100,0]},"s":{"k":[57.143,50,100]}},"ao":0,"sw":140,"sh":200,"sc":"#ffffff","ip":0,"op":37,"st":0,"bm":0,"sr":1}],"v":"4.4.26","ddd":0,"ip":0,"op":37,"fr":25,"w":80,"h":100} diff --git a/sdk/python/examples/controls/lottie/example_1/main.py b/sdk/python/examples/controls/lottie/example_1/main.py new file mode 100644 index 0000000000..cba7564e9b --- /dev/null +++ b/sdk/python/examples/controls/lottie/example_1/main.py @@ -0,0 +1,33 @@ +import flet as ft +import flet_lottie as ftl + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ftl.Lottie( + src="https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json", + reverse=False, + animate=True, + error_content=ft.Placeholder(ft.Text("Error loading Lottie")), + on_error=lambda e: print(f"Error loading Lottie: {e.data}"), + ), + ftl.Lottie( + src="sample.json", + reverse=False, + animate=True, + enable_merge_paths=True, + enable_layers_opacity=True, + error_content=ft.Placeholder(ft.Text("Error loading Lottie")), + on_error=lambda e: print(f"Error loading Lottie: {e.data}"), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/lottie/example_1/pyproject.toml b/sdk/python/examples/controls/lottie/example_1/pyproject.toml new file mode 100644 index 0000000000..670db24128 --- /dev/null +++ b/sdk/python/examples/controls/lottie/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "lottie-example-1" +version = "1.0.0" +description = "Plays Lottie animations from a remote URL and local JSON file with error fallback content." +requires-python = ">=3.10" +keywords = ["lottie", "animation", "json", "remote", "assets"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-lottie"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Lottie"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "Column", "Lottie", "Placeholder", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["remote lottie animation", "local lottie asset", "error callback and fallback content"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/listtile.md b/sdk/python/packages/flet/docs/controls/listtile.md index 0edd2263f3..c0b1619a60 100644 --- a/sdk/python/packages/flet/docs/controls/listtile.md +++ b/sdk/python/packages/flet/docs/controls/listtile.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/list_tile/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/listview.md b/sdk/python/packages/flet/docs/controls/listview.md index 4a7146e4e9..18c63e5b40 100644 --- a/sdk/python/packages/flet/docs/controls/listview.md +++ b/sdk/python/packages/flet/docs/controls/listview.md @@ -14,7 +14,7 @@ example_images: ../test-images/examples/core/golden/macos/list_view ### Auto-scrolling and dynamical items addition ```python ---8<-- "{{ examples }}/autoscroll_and_dynamic_items.py" +--8<-- "{{ examples }}/autoscroll_and_dynamic_items/main.py" ``` {{ image(example_media + "/autoscroll_and_dynamic_items.gif", alt="autoscroll-and-dynamic-items", width="80%") }} diff --git a/sdk/python/packages/flet/docs/lottie/index.md b/sdk/python/packages/flet/docs/lottie/index.md index d7a4b70fd5..6d696a86a5 100644 --- a/sdk/python/packages/flet/docs/lottie/index.md +++ b/sdk/python/packages/flet/docs/lottie/index.md @@ -36,7 +36,7 @@ pip install flet-lottie # (1)! ## Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Description From 6022bbbb3adecc83ed19c3c5d4670501e489861f Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 17:36:40 -0700 Subject: [PATCH 55/96] Reorganize examples to package layout Move example scripts into example-specific directories with main.py, add pyproject.toml metadata for each example, and remove legacy top-level example modules. Wrap UIs with SafeArea and add if __name__ == "__main__": ft.run(main) guards where applicable. Update docs to reference the new example paths and adjust a few example UI/layout tweaks (e.g. MenuBar, SafeArea usage). This consolidates examples into a consistent package layout and adds per-example metadata for the gallery/tooling. --- .../controls/map/{basic.py => basic/main.py} | 3 +- .../controls/map/basic/pyproject.toml | 26 +++ .../examples/controls/map/camera_controls.py | 106 ------------ .../controls/map/camera_controls/main.py | 112 +++++++++++++ .../map/camera_controls/pyproject.toml | 26 +++ .../examples/controls/map/idle_camera.py | 76 --------- .../examples/controls/map/idle_camera/main.py | 83 ++++++++++ .../controls/map/idle_camera/pyproject.toml | 26 +++ .../main.py} | 43 ++--- .../map/interaction_flags/pyproject.toml | 26 +++ .../examples/controls/map/multi_layers.py | 132 --------------- .../controls/map/multi_layers/main.py | 153 ++++++++++++++++++ .../controls/map/multi_layers/pyproject.toml | 26 +++ .../markdown/{basic.py => basic/main.py} | 15 +- .../controls/markdown/basic/pyproject.toml | 26 +++ .../main.py} | 21 +-- .../code_syntax_highlight/pyproject.toml | 26 +++ .../controls/markdown/custom_text_theme.py | 44 ----- .../markdown/custom_text_theme/main.py | 47 ++++++ .../markdown/custom_text_theme/pyproject.toml | 26 +++ .../{listviews.py => listviews/main.py} | 49 +++--- .../markdown/listviews/pyproject.toml | 26 +++ .../examples/controls/menu_bar/__init__.py | 0 .../controls/menu_bar/nested_submenus.py | 123 -------------- .../controls/menu_bar/nested_submenus/main.py | 135 ++++++++++++++++ .../menu_bar/nested_submenus/pyproject.toml | 26 +++ .../packages/flet/docs/controls/markdown.md | 6 +- .../packages/flet/docs/controls/menubar.md | 2 +- sdk/python/packages/flet/docs/map/index.md | 10 +- .../examples/material/test_menu_bar.py | 3 +- 30 files changed, 877 insertions(+), 546 deletions(-) rename sdk/python/examples/controls/map/{basic.py => basic/main.py} (91%) create mode 100644 sdk/python/examples/controls/map/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/map/camera_controls.py create mode 100644 sdk/python/examples/controls/map/camera_controls/main.py create mode 100644 sdk/python/examples/controls/map/camera_controls/pyproject.toml delete mode 100644 sdk/python/examples/controls/map/idle_camera.py create mode 100644 sdk/python/examples/controls/map/idle_camera/main.py create mode 100644 sdk/python/examples/controls/map/idle_camera/pyproject.toml rename sdk/python/examples/controls/map/{interaction_flags.py => interaction_flags/main.py} (74%) create mode 100644 sdk/python/examples/controls/map/interaction_flags/pyproject.toml delete mode 100644 sdk/python/examples/controls/map/multi_layers.py create mode 100644 sdk/python/examples/controls/map/multi_layers/main.py create mode 100644 sdk/python/examples/controls/map/multi_layers/pyproject.toml rename sdk/python/examples/controls/markdown/{basic.py => basic/main.py} (87%) create mode 100644 sdk/python/examples/controls/markdown/basic/pyproject.toml rename sdk/python/examples/controls/markdown/{code_syntax_highlight.py => code_syntax_highlight/main.py} (91%) create mode 100644 sdk/python/examples/controls/markdown/code_syntax_highlight/pyproject.toml delete mode 100644 sdk/python/examples/controls/markdown/custom_text_theme.py create mode 100644 sdk/python/examples/controls/markdown/custom_text_theme/main.py create mode 100644 sdk/python/examples/controls/markdown/custom_text_theme/pyproject.toml rename sdk/python/examples/controls/markdown/{listviews.py => listviews/main.py} (70%) create mode 100644 sdk/python/examples/controls/markdown/listviews/pyproject.toml delete mode 100644 sdk/python/examples/controls/menu_bar/__init__.py delete mode 100644 sdk/python/examples/controls/menu_bar/nested_submenus.py create mode 100644 sdk/python/examples/controls/menu_bar/nested_submenus/main.py create mode 100644 sdk/python/examples/controls/menu_bar/nested_submenus/pyproject.toml diff --git a/sdk/python/examples/controls/map/basic.py b/sdk/python/examples/controls/map/basic/main.py similarity index 91% rename from sdk/python/examples/controls/map/basic.py rename to sdk/python/examples/controls/map/basic/main.py index aa6fe30537..c2b29c858c 100644 --- a/sdk/python/examples/controls/map/basic.py +++ b/sdk/python/examples/controls/map/basic/main.py @@ -18,4 +18,5 @@ def main(page: ft.Page): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/map/basic/pyproject.toml b/sdk/python/examples/controls/map/basic/pyproject.toml new file mode 100644 index 0000000000..9192cfc420 --- /dev/null +++ b/sdk/python/examples/controls/map/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-basic" +version = "1.0.0" +description = "Shows a basic flet-map tile layer with error callback handling." +requires-python = ">=3.10" +keywords = ["map", "tile layer", "flet-map", "geospatial"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/Map"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Map", "TileLayer"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["map tile rendering", "tile load error callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/map/camera_controls.py b/sdk/python/examples/controls/map/camera_controls.py deleted file mode 100644 index a475ecf237..0000000000 --- a/sdk/python/examples/controls/map/camera_controls.py +++ /dev/null @@ -1,106 +0,0 @@ -import flet as ft -import flet_map as ftm - - -def main(page: ft.Page): - page.padding = 16 - - async def update_camera_status(trigger: str): - camera = await my_map.get_camera() - camera_status.value = ( - f"Camera [{trigger}]: " - f"center=({camera.center.latitude:.5f}, {camera.center.longitude:.5f}), " - f"zoom={camera.zoom:.2f}, rotation={camera.rotation:.1f}" - ) - page.update() - - async def zoom_in(e: ft.Event[ft.Button]): - await my_map.zoom_in() - await update_camera_status("zoom_in") - - async def zoom_out(e: ft.Event[ft.Button]): - await my_map.zoom_out() - await update_camera_status("zoom_out") - - async def rotate_plus_15(e: ft.Event[ft.Button]): - await my_map.rotate_from(15) - await update_camera_status("rotate_from(+15)") - - async def reset_rotation(e: ft.Event[ft.Button]): - await my_map.reset_rotation() - await update_camera_status("reset_rotation") - - async def center_berlin(e: ft.Event[ft.Button]): - await my_map.center_on(point=ftm.MapLatitudeLongitude(52.52, 13.405), zoom=12) - await update_camera_status("center_on(berlin)") - - async def move_tokyo(e: ft.Event[ft.Button]): - await my_map.move_to( - destination=ftm.MapLatitudeLongitude(35.6762, 139.6503), zoom=11 - ) - await update_camera_status("move_to(tokyo)") - - async def set_world_zoom(e: ft.Event[ft.Button]): - await my_map.zoom_to(3) - await update_camera_status("zoom_to(3)") - - page.appbar = ft.AppBar(title="Camera controls") - page.add( - ft.Column( - expand=True, - controls=[ - ft.Text( - "Use buttons to control map camera programmatically.", - size=12, - ), - ft.Row( - wrap=True, - spacing=8, - run_spacing=8, - controls=[ - ft.Button("Zoom in", on_click=zoom_in), - ft.Button("Zoom out", on_click=zoom_out), - ft.Button("Rotate +15°", on_click=rotate_plus_15), - ft.Button("Reset rotation", on_click=reset_rotation), - ft.Button("Center Berlin", on_click=center_berlin), - ft.Button("Move to Tokyo", on_click=move_tokyo), - ft.Button("World zoom (3)", on_click=set_world_zoom), - ], - ), - camera_status := ft.Text(selectable=True, font_family="monospace"), - my_map := ftm.Map( - expand=True, - initial_center=ftm.MapLatitudeLongitude(52.52, 13.405), - initial_zoom=5, - layers=[ - ftm.TileLayer( - url_template="https://tile.memomaps.de/tilegen/{z}/{x}/{y}.png" - ), - ftm.SimpleAttribution( - text="OpenStreetMap contributors", - on_click=lambda e: e.page.launch_url( - "https://www.openstreetmap.org/copyright" - ), - ), - ftm.MarkerLayer( - markers=[ - ftm.Marker( - coordinates=ftm.MapLatitudeLongitude(52.52, 13.405), - content=ft.Icon(ft.Icons.LOCATION_ON), - ), - ftm.Marker( - coordinates=ftm.MapLatitudeLongitude( - 35.6762, 139.6503 - ), - content=ft.Icon(ft.Icons.LOCATION_ON), - ), - ] - ), - ], - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/map/camera_controls/main.py b/sdk/python/examples/controls/map/camera_controls/main.py new file mode 100644 index 0000000000..f3f74e9d37 --- /dev/null +++ b/sdk/python/examples/controls/map/camera_controls/main.py @@ -0,0 +1,112 @@ +import flet as ft +import flet_map as ftm + + +def main(page: ft.Page): + page.padding = 16 + + async def update_camera_status(trigger: str): + camera = await my_map.get_camera() + camera_status.value = ( + f"Camera [{trigger}]: " + f"center=({camera.center.latitude:.5f}, {camera.center.longitude:.5f}), " + f"zoom={camera.zoom:.2f}, rotation={camera.rotation:.1f}" + ) + page.update() + + async def zoom_in(e: ft.Event[ft.Button]): + await my_map.zoom_in() + await update_camera_status("zoom_in") + + async def zoom_out(e: ft.Event[ft.Button]): + await my_map.zoom_out() + await update_camera_status("zoom_out") + + async def rotate_plus_15(e: ft.Event[ft.Button]): + await my_map.rotate_from(15) + await update_camera_status("rotate_from(+15)") + + async def reset_rotation(e: ft.Event[ft.Button]): + await my_map.reset_rotation() + await update_camera_status("reset_rotation") + + async def center_berlin(e: ft.Event[ft.Button]): + await my_map.center_on(point=ftm.MapLatitudeLongitude(52.52, 13.405), zoom=12) + await update_camera_status("center_on(berlin)") + + async def move_tokyo(e: ft.Event[ft.Button]): + await my_map.move_to( + destination=ftm.MapLatitudeLongitude(35.6762, 139.6503), zoom=11 + ) + await update_camera_status("move_to(tokyo)") + + async def set_world_zoom(e: ft.Event[ft.Button]): + await my_map.zoom_to(3) + await update_camera_status("zoom_to(3)") + + page.appbar = ft.AppBar(title="Camera controls") + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Text( + "Use buttons to control map camera programmatically.", + size=12, + ), + ft.Row( + wrap=True, + spacing=8, + run_spacing=8, + controls=[ + ft.Button("Zoom in", on_click=zoom_in), + ft.Button("Zoom out", on_click=zoom_out), + ft.Button("Rotate +15°", on_click=rotate_plus_15), + ft.Button("Reset rotation", on_click=reset_rotation), + ft.Button("Center Berlin", on_click=center_berlin), + ft.Button("Move to Tokyo", on_click=move_tokyo), + ft.Button("World zoom (3)", on_click=set_world_zoom), + ], + ), + camera_status := ft.Text(selectable=True, font_family="monospace"), + my_map := ftm.Map( + expand=True, + initial_center=ftm.MapLatitudeLongitude(52.52, 13.405), + initial_zoom=5, + layers=[ + ftm.TileLayer( + url_template="https://tile.memomaps.de/tilegen/{z}/{x}/{y}.png" + ), + ftm.SimpleAttribution( + text="OpenStreetMap contributors", + on_click=lambda e: e.page.launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + ftm.MarkerLayer( + markers=[ + ftm.Marker( + coordinates=ftm.MapLatitudeLongitude( + 52.52, 13.405 + ), + content=ft.Icon(ft.Icons.LOCATION_ON), + ), + ftm.Marker( + coordinates=ftm.MapLatitudeLongitude( + 35.6762, 139.6503 + ), + content=ft.Icon(ft.Icons.LOCATION_ON), + ), + ] + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/map/camera_controls/pyproject.toml b/sdk/python/examples/controls/map/camera_controls/pyproject.toml new file mode 100644 index 0000000000..4469103649 --- /dev/null +++ b/sdk/python/examples/controls/map/camera_controls/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-camera-controls" +version = "1.0.0" +description = "Controls map camera programmatically with zoom, rotate, center, move, and state text updates." +requires-python = ">=3.10" +keywords = ["map", "camera controls", "zoom", "rotate", "markers"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/Map"] + +[tool.flet.metadata] +title = "Camera Controls" +controls = ["SafeArea", "Column", "Row", "Map", "TileLayer", "SimpleAttribution", "MarkerLayer", "Marker", "Button", "Text", "Icon", "AppBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["programmatic camera actions", "camera state display", "predefined map centers"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/map/idle_camera.py b/sdk/python/examples/controls/map/idle_camera.py deleted file mode 100644 index 9630e0140c..0000000000 --- a/sdk/python/examples/controls/map/idle_camera.py +++ /dev/null @@ -1,76 +0,0 @@ -import flet as ft -import flet_map as ftm - -IDLE_EVENT_TYPES = { - ftm.MapEventType.MOVE_END, - ftm.MapEventType.FLING_ANIMATION_END, - ftm.MapEventType.FLING_ANIMATION_NOT_STARTED, - ftm.MapEventType.DOUBLE_TAP_ZOOM_END, - ftm.MapEventType.ROTATE_END, -} - - -def main(page: ft.Page): - page.padding = 16 - - async def handle_map_event(e: ftm.MapEvent): - last_event.value = ( - "Last event: " - f"type={e.event_type}, source={e.source.value}, zoom={e.camera.zoom:.2f}" - ) - - if e.event_type in IDLE_EVENT_TYPES: # here the camera is settled/idle - camera = await e.control.get_camera() - settled_camera.value = ( - "Settled camera: " - f"center=({camera.center.latitude:.3f}, " - f"{camera.center.longitude:.3f}), " - f"zoom={camera.zoom:.2f}, rotation={camera.rotation:.1f}, " - f"trigger={e.event_type}" - ) - - page.update() - - page.add( - ft.Column( - expand=True, - controls=[ - ft.Text("Camera idle pattern", size=20, weight=ft.FontWeight.BOLD), - ft.Text( - "Drag, fling, rotate, zoom and watch when the camera is settled.", - size=12, - ), - last_event := ft.Text( - "Last event: -", selectable=True, font_family="monospace" - ), - settled_camera := ft.Text( - "Settled camera: -", selectable=True, font_family="monospace" - ), - ftm.Map( - expand=True, - initial_center=ftm.MapLatitudeLongitude( - latitude=52.52, longitude=13.405 - ), - initial_zoom=11, - on_event=handle_map_event, - interaction_configuration=ftm.InteractionConfiguration( - flags=ftm.InteractionFlag.ALL - ), - layers=[ - ftm.TileLayer( - url_template="https://tile.memomaps.de/tilegen/{z}/{x}/{y}.png" - ), - ftm.SimpleAttribution( - text="OpenStreetMap contributors", - on_click=lambda e: e.page.launch_url( - "https://www.openstreetmap.org/copyright" - ), - ), - ], - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/map/idle_camera/main.py b/sdk/python/examples/controls/map/idle_camera/main.py new file mode 100644 index 0000000000..7a14addd86 --- /dev/null +++ b/sdk/python/examples/controls/map/idle_camera/main.py @@ -0,0 +1,83 @@ +import flet as ft +import flet_map as ftm + +IDLE_EVENT_TYPES = { + ftm.MapEventType.MOVE_END, + ftm.MapEventType.FLING_ANIMATION_END, + ftm.MapEventType.FLING_ANIMATION_NOT_STARTED, + ftm.MapEventType.DOUBLE_TAP_ZOOM_END, + ftm.MapEventType.ROTATE_END, +} + + +def main(page: ft.Page): + page.padding = 16 + + async def handle_map_event(e: ftm.MapEvent): + last_event.value = ( + "Last event: " + f"type={e.event_type}, source={e.source.value}, zoom={e.camera.zoom:.2f}" + ) + + if e.event_type in IDLE_EVENT_TYPES: # here the camera is settled/idle + camera = await e.control.get_camera() + settled_camera.value = ( + "Settled camera: " + f"center=({camera.center.latitude:.3f}, " + f"{camera.center.longitude:.3f}), " + f"zoom={camera.zoom:.2f}, rotation={camera.rotation:.1f}, " + f"trigger={e.event_type}" + ) + + page.update() + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Text("Camera idle pattern", size=20, weight=ft.FontWeight.BOLD), + ft.Text( + ( + "Drag, fling, rotate, zoom and watch " + "when the camera is settled." + ), + size=12, + ), + last_event := ft.Text( + "Last event: -", selectable=True, font_family="monospace" + ), + settled_camera := ft.Text( + "Settled camera: -", selectable=True, font_family="monospace" + ), + ftm.Map( + expand=True, + initial_center=ftm.MapLatitudeLongitude( + latitude=52.52, longitude=13.405 + ), + initial_zoom=11, + on_event=handle_map_event, + interaction_configuration=ftm.InteractionConfiguration( + flags=ftm.InteractionFlag.ALL + ), + layers=[ + ftm.TileLayer( + url_template="https://tile.memomaps.de/tilegen/{z}/{x}/{y}.png" + ), + ftm.SimpleAttribution( + text="OpenStreetMap contributors", + on_click=lambda e: e.page.launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/map/idle_camera/pyproject.toml b/sdk/python/examples/controls/map/idle_camera/pyproject.toml new file mode 100644 index 0000000000..9d3721d8ba --- /dev/null +++ b/sdk/python/examples/controls/map/idle_camera/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-idle-camera" +version = "1.0.0" +description = "Tracks map events and reports settled camera state when idle-related events occur." +requires-python = ">=3.10" +keywords = ["map", "camera idle", "events", "interaction flags"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/Map"] + +[tool.flet.metadata] +title = "Idle Camera" +controls = ["SafeArea", "Column", "Map", "TileLayer", "SimpleAttribution", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["map event handling", "idle camera detection", "camera status output"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/map/interaction_flags.py b/sdk/python/examples/controls/map/interaction_flags/main.py similarity index 74% rename from sdk/python/examples/controls/map/interaction_flags.py rename to sdk/python/examples/controls/map/interaction_flags/main.py index 5a9cf7cc49..77a2b07dd5 100644 --- a/sdk/python/examples/controls/map/interaction_flags.py +++ b/sdk/python/examples/controls/map/interaction_flags/main.py @@ -74,28 +74,35 @@ def handle_map_event(e: ftm.MapEvent): page.appbar = ft.AppBar(title="Interaction flags") page.add( - ft.Column( + ft.SafeArea( expand=True, - controls=[ - ft.Text( - "Toggle flags and try dragging, zooming, rotating, and scrolling.", - size=12, - ), - ft.ResponsiveRow( - controls=[ - ft.Container(col={"sm": 6, "md": 4}, content=c) - for c in checkboxes - ] - ), - last_event := ft.Text( - "Last event: -", selectable=True, font_family="monospace" - ), - ft.Container(expand=True, content=my_map), - ], + content=ft.Column( + expand=True, + controls=[ + ft.Text( + ( + "Toggle flags and try dragging, zooming, rotating, " + "and scrolling." + ), + size=12, + ), + ft.ResponsiveRow( + controls=[ + ft.Container(col={"sm": 6, "md": 4}, content=c) + for c in checkboxes + ] + ), + last_event := ft.Text( + "Last event: -", selectable=True, font_family="monospace" + ), + ft.Container(expand=True, content=my_map), + ], + ), ) ) update_interaction_flags() -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/map/interaction_flags/pyproject.toml b/sdk/python/examples/controls/map/interaction_flags/pyproject.toml new file mode 100644 index 0000000000..da37819e2c --- /dev/null +++ b/sdk/python/examples/controls/map/interaction_flags/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-interaction-flags" +version = "1.0.0" +description = "Toggles map interaction flags with checkboxes and displays live map event details." +requires-python = ">=3.10" +keywords = ["map", "interaction flags", "checkbox", "events", "attribution"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/Map"] + +[tool.flet.metadata] +title = "Interaction Flags" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "Checkbox", "Map", "TileLayer", "RichAttribution", "TextSourceAttribution", "Text", "AppBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["runtime interaction toggles", "map event logging", "custom attributions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/map/multi_layers.py b/sdk/python/examples/controls/map/multi_layers.py deleted file mode 100644 index f1ba4e6016..0000000000 --- a/sdk/python/examples/controls/map/multi_layers.py +++ /dev/null @@ -1,132 +0,0 @@ -import random - -import flet as ft -import flet_map as ftm - - -def main(page: ft.Page): - def handle_tap(e: ftm.MapTapEvent): - if e.name == "tap": - marker_layer.markers.append( - ftm.Marker( - content=ft.Icon( - ft.Icons.LOCATION_ON, color=ft.CupertinoColors.DESTRUCTIVE_RED - ), - coordinates=e.coordinates, - ) - ) - elif e.name == "secondary_tap": - circle_layer.circles.append( - ftm.CircleMarker( - radius=random.randint(5, 10), - coordinates=e.coordinates, - color=ft.Colors.random(), - border_color=ft.Colors.random(), - border_stroke_width=4, - ) - ) - page.update() - - page.appbar = ft.AppBar(title="Multiple Layers") - page.add( - ft.Text("Click anywhere to add a Marker, right-click to add a CircleMarker."), - ftm.Map( - expand=True, - initial_center=ftm.MapLatitudeLongitude(15, 10), - initial_zoom=4.2, - interaction_configuration=ftm.InteractionConfiguration( - flags=ftm.InteractionFlag.ALL - ), - on_tap=handle_tap, - on_secondary_tap=handle_tap, - on_event=print, - layers=[ - ftm.TileLayer( - url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", - on_image_error=lambda e: print("TileLayer Error"), - ), - ftm.RichAttribution( - attributions=[ - ftm.TextSourceAttribution( - text="OpenStreetMap Contributors", - on_click=lambda e: e.page.launch_url( - "https://www.openstreetmap.org/copyright" - ), - ), - ftm.TextSourceAttribution( - text="Flet", - on_click=lambda e: e.page.launch_url("https://flet.dev"), - ), - ] - ), - ftm.SimpleAttribution( - text="Flet", - alignment=ft.Alignment.TOP_RIGHT, - on_click=lambda e: print("Clicked SimpleAttribution"), - ), - marker_layer := ftm.MarkerLayer( - markers=[ - ftm.Marker( - content=ft.Icon(ft.Icons.LOCATION_ON), - coordinates=ftm.MapLatitudeLongitude(30, 15), - ), - ftm.Marker( - content=ft.Icon(ft.Icons.LOCATION_ON), - coordinates=ftm.MapLatitudeLongitude(10, 10), - ), - ftm.Marker( - content=ft.Icon(ft.Icons.LOCATION_ON), - coordinates=ftm.MapLatitudeLongitude(25, 45), - ), - ], - ), - circle_layer := ftm.CircleLayer( - circles=[ - ftm.CircleMarker( - radius=10, - coordinates=ftm.MapLatitudeLongitude(16, 24), - color=ft.Colors.RED, - border_color=ft.Colors.BLUE, - border_stroke_width=4, - ), - ], - ), - ftm.PolygonLayer( - polygons=[ - ftm.PolygonMarker( - label="Popular Touristic Area", - label_text_style=ft.TextStyle( - color=ft.Colors.BLACK, - size=15, - weight=ft.FontWeight.BOLD, - ), - color=ft.Colors.with_opacity(0.3, ft.Colors.BLUE), - coordinates=[ - ftm.MapLatitudeLongitude(10, 10), - ftm.MapLatitudeLongitude(30, 15), - ftm.MapLatitudeLongitude(25, 45), - ], - ), - ], - ), - ftm.PolylineLayer( - polylines=[ - ftm.PolylineMarker( - border_stroke_width=3, - border_color=ft.Colors.RED, - gradient_colors=[ft.Colors.BLACK, ft.Colors.BLACK], - color=ft.Colors.with_opacity(0.6, ft.Colors.GREEN), - coordinates=[ - ftm.MapLatitudeLongitude(10, 10), - ftm.MapLatitudeLongitude(30, 15), - ftm.MapLatitudeLongitude(25, 45), - ], - ), - ], - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/map/multi_layers/main.py b/sdk/python/examples/controls/map/multi_layers/main.py new file mode 100644 index 0000000000..e057bfffe0 --- /dev/null +++ b/sdk/python/examples/controls/map/multi_layers/main.py @@ -0,0 +1,153 @@ +import random + +import flet as ft +import flet_map as ftm + + +def main(page: ft.Page): + def handle_tap(e: ftm.MapTapEvent): + if e.name == "tap": + marker_layer.markers.append( + ftm.Marker( + content=ft.Icon( + ft.Icons.LOCATION_ON, color=ft.CupertinoColors.DESTRUCTIVE_RED + ), + coordinates=e.coordinates, + ) + ) + elif e.name == "secondary_tap": + circle_layer.circles.append( + ftm.CircleMarker( + radius=random.randint(5, 10), + coordinates=e.coordinates, + color=ft.Colors.random(), + border_color=ft.Colors.random(), + border_stroke_width=4, + ) + ) + page.update() + + page.appbar = ft.AppBar(title="Multiple Layers") + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Text( + "Click anywhere to add a Marker, right-click to add a " + "CircleMarker." + ), + ftm.Map( + expand=True, + initial_center=ftm.MapLatitudeLongitude(15, 10), + initial_zoom=4.2, + interaction_configuration=ftm.InteractionConfiguration( + flags=ftm.InteractionFlag.ALL + ), + on_tap=handle_tap, + on_secondary_tap=handle_tap, + on_event=print, + layers=[ + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + on_image_error=lambda e: print("TileLayer Error"), + ), + ftm.RichAttribution( + attributions=[ + ftm.TextSourceAttribution( + text="OpenStreetMap Contributors", + on_click=lambda e: e.page.launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + ftm.TextSourceAttribution( + text="Flet", + on_click=lambda e: e.page.launch_url( + "https://flet.dev" + ), + ), + ] + ), + ftm.SimpleAttribution( + text="Flet", + alignment=ft.Alignment.TOP_RIGHT, + on_click=lambda e: print("Clicked SimpleAttribution"), + ), + marker_layer := ftm.MarkerLayer( + markers=[ + ftm.Marker( + content=ft.Icon(ft.Icons.LOCATION_ON), + coordinates=ftm.MapLatitudeLongitude(30, 15), + ), + ftm.Marker( + content=ft.Icon(ft.Icons.LOCATION_ON), + coordinates=ftm.MapLatitudeLongitude(10, 10), + ), + ftm.Marker( + content=ft.Icon(ft.Icons.LOCATION_ON), + coordinates=ftm.MapLatitudeLongitude(25, 45), + ), + ], + ), + circle_layer := ftm.CircleLayer( + circles=[ + ftm.CircleMarker( + radius=10, + coordinates=ftm.MapLatitudeLongitude(16, 24), + color=ft.Colors.RED, + border_color=ft.Colors.BLUE, + border_stroke_width=4, + ), + ], + ), + ftm.PolygonLayer( + polygons=[ + ftm.PolygonMarker( + label="Popular Touristic Area", + label_text_style=ft.TextStyle( + color=ft.Colors.BLACK, + size=15, + weight=ft.FontWeight.BOLD, + ), + color=ft.Colors.with_opacity( + 0.3, ft.Colors.BLUE + ), + coordinates=[ + ftm.MapLatitudeLongitude(10, 10), + ftm.MapLatitudeLongitude(30, 15), + ftm.MapLatitudeLongitude(25, 45), + ], + ), + ], + ), + ftm.PolylineLayer( + polylines=[ + ftm.PolylineMarker( + border_stroke_width=3, + border_color=ft.Colors.RED, + gradient_colors=[ + ft.Colors.BLACK, + ft.Colors.BLACK, + ], + color=ft.Colors.with_opacity( + 0.6, ft.Colors.GREEN + ), + coordinates=[ + ftm.MapLatitudeLongitude(10, 10), + ftm.MapLatitudeLongitude(30, 15), + ftm.MapLatitudeLongitude(25, 45), + ], + ), + ], + ), + ], + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/map/multi_layers/pyproject.toml b/sdk/python/examples/controls/map/multi_layers/pyproject.toml new file mode 100644 index 0000000000..64ec87c460 --- /dev/null +++ b/sdk/python/examples/controls/map/multi_layers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-multi-layers" +version = "1.0.0" +description = "Combines tile, marker, circle, polygon, and polyline layers with tap-to-add overlays." +requires-python = ">=3.10" +keywords = ["map", "layers", "markers", "polygons", "polylines"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/Map"] + +[tool.flet.metadata] +title = "Multiple Layers" +controls = ["SafeArea", "Column", "Text", "Map", "TileLayer", "RichAttribution", "SimpleAttribution", "TextSourceAttribution", "MarkerLayer", "Marker", "CircleLayer", "CircleMarker", "PolygonLayer", "PolygonMarker", "PolylineLayer", "PolylineMarker", "Icon", "AppBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["multi-layer map composition", "tap and secondary-tap overlay creation", "interactive attributions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/markdown/basic.py b/sdk/python/examples/controls/markdown/basic/main.py similarity index 87% rename from sdk/python/examples/controls/markdown/basic.py rename to sdk/python/examples/controls/markdown/basic/main.py index 7788678401..075fc15c35 100644 --- a/sdk/python/examples/controls/markdown/basic.py +++ b/sdk/python/examples/controls/markdown/basic/main.py @@ -83,13 +83,16 @@ async def handle_link_tap(e: ft.Event[ft.Markdown]): await page.launch_url(e.data) page.add( - ft.Markdown( - value=sample, - selectable=True, - extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, - on_tap_link=handle_link_tap, + ft.SafeArea( + content=ft.Markdown( + value=sample, + selectable=True, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + on_tap_link=handle_link_tap, + ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/markdown/basic/pyproject.toml b/sdk/python/examples/controls/markdown/basic/pyproject.toml new file mode 100644 index 0000000000..784c5c4417 --- /dev/null +++ b/sdk/python/examples/controls/markdown/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "markdown-basic" +version = "1.0.0" +description = "Renders a long Markdown document with links, images, tables, and code blocks." +requires-python = ">=3.10" +keywords = ["markdown", "rich text", "links", "tables", "code blocks"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Markdown"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Markdown"] +layout_pattern = "article" +complexity = "basic" +features = ["github markdown rendering", "link tap callback", "scrollable markdown"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/markdown/code_syntax_highlight.py b/sdk/python/examples/controls/markdown/code_syntax_highlight/main.py similarity index 91% rename from sdk/python/examples/controls/markdown/code_syntax_highlight.py rename to sdk/python/examples/controls/markdown/code_syntax_highlight/main.py index 72838ac1d3..fd116fb1d4 100644 --- a/sdk/python/examples/controls/markdown/code_syntax_highlight.py +++ b/sdk/python/examples/controls/markdown/code_syntax_highlight/main.py @@ -162,17 +162,20 @@ async def navigate_md_link(e: ft.Event[ft.Markdown]): await page.launch_url(e.data) page.add( - ft.Markdown( - value=sample, - selectable=True, - extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, - code_theme=ft.MarkdownCodeTheme.ATOM_ONE_DARK, - code_style_sheet=ft.MarkdownStyleSheet( - code_text_style=ft.TextStyle(font_family="Roboto Mono") + ft.SafeArea( + content=ft.Markdown( + value=sample, + selectable=True, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + code_theme=ft.MarkdownCodeTheme.ATOM_ONE_DARK, + code_style_sheet=ft.MarkdownStyleSheet( + code_text_style=ft.TextStyle(font_family="Roboto Mono") + ), + on_tap_link=navigate_md_link, ), - on_tap_link=navigate_md_link, ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/markdown/code_syntax_highlight/pyproject.toml b/sdk/python/examples/controls/markdown/code_syntax_highlight/pyproject.toml new file mode 100644 index 0000000000..8acfd0fa29 --- /dev/null +++ b/sdk/python/examples/controls/markdown/code_syntax_highlight/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "markdown-code-syntax-highlight" +version = "1.0.0" +description = "Displays Markdown with syntax-highlighted code blocks and custom monospace font style." +requires-python = ">=3.10" +keywords = ["markdown", "syntax highlight", "code theme", "fonts"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Markdown"] + +[tool.flet.metadata] +title = "Code syntax highlight" +controls = ["SafeArea", "Markdown", "MarkdownStyleSheet", "TextStyle"] +layout_pattern = "article" +complexity = "basic" +features = ["code syntax highlighting", "custom code font", "link tap callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/markdown/custom_text_theme.py b/sdk/python/examples/controls/markdown/custom_text_theme.py deleted file mode 100644 index 51749a9e31..0000000000 --- a/sdk/python/examples/controls/markdown/custom_text_theme.py +++ /dev/null @@ -1,44 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.DARK - - def change_theme_mode(e: ft.Event[ft.Switch]): - if page.theme_mode == ft.ThemeMode.DARK: - page.theme_mode = ft.ThemeMode.LIGHT - switch.thumb_icon = ft.Icons.LIGHT_MODE - else: - switch.thumb_icon = ft.Icons.DARK_MODE - page.theme_mode = ft.ThemeMode.DARK - page.update() - - switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=change_theme_mode) - - page.add( - ft.Row( - alignment=ft.MainAxisAlignment.SPACE_BETWEEN, - controls=[ - ft.Container( - content=ft.Markdown("I can read this!"), - bgcolor="#550000", - padding=20, - theme=ft.Theme( - text_theme=ft.TextTheme( - body_medium=ft.TextStyle(color=ft.Colors.WHITE), - body_large=ft.TextStyle(color=ft.Colors.WHITE), - body_small=ft.TextStyle(color=ft.Colors.WHITE), - ) - ), - ), - ft.Container( - content=switch, - padding=ft.Padding.only(bottom=50), - alignment=ft.Alignment.TOP_RIGHT, - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/markdown/custom_text_theme/main.py b/sdk/python/examples/controls/markdown/custom_text_theme/main.py new file mode 100644 index 0000000000..132a52d039 --- /dev/null +++ b/sdk/python/examples/controls/markdown/custom_text_theme/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.DARK + + def change_theme_mode(e: ft.Event[ft.Switch]): + if page.theme_mode == ft.ThemeMode.DARK: + page.theme_mode = ft.ThemeMode.LIGHT + switch.thumb_icon = ft.Icons.LIGHT_MODE + else: + switch.thumb_icon = ft.Icons.DARK_MODE + page.theme_mode = ft.ThemeMode.DARK + page.update() + + switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=change_theme_mode) + + page.add( + ft.SafeArea( + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Container( + bgcolor="#550000", + padding=20, + theme=ft.Theme( + text_theme=ft.TextTheme( + body_medium=ft.TextStyle(color=ft.Colors.WHITE), + body_large=ft.TextStyle(color=ft.Colors.WHITE), + body_small=ft.TextStyle(color=ft.Colors.WHITE), + ) + ), + content=ft.Markdown("I can read this!"), + ), + ft.Container( + padding=ft.Padding.only(bottom=50), + alignment=ft.Alignment.TOP_RIGHT, + content=switch, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/markdown/custom_text_theme/pyproject.toml b/sdk/python/examples/controls/markdown/custom_text_theme/pyproject.toml new file mode 100644 index 0000000000..ed894ad15e --- /dev/null +++ b/sdk/python/examples/controls/markdown/custom_text_theme/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "markdown-custom-text-theme" +version = "1.0.0" +description = "Applies a custom text theme to Markdown and toggles light/dark theme mode." +requires-python = ">=3.10" +keywords = ["markdown", "theme", "text theme", "dark mode", "switch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Markdown"] + +[tool.flet.metadata] +title = "Custom text theme" +controls = ["SafeArea", "Row", "Container", "Markdown", "Switch", "Theme", "TextTheme"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom markdown text colors", "theme mode toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/markdown/listviews.py b/sdk/python/examples/controls/markdown/listviews/main.py similarity index 70% rename from sdk/python/examples/controls/markdown/listviews.py rename to sdk/python/examples/controls/markdown/listviews/main.py index 9faf353dd6..119a5905b4 100644 --- a/sdk/python/examples/controls/markdown/listviews.py +++ b/sdk/python/examples/controls/markdown/listviews/main.py @@ -124,28 +124,37 @@ async def navigate_md_link(e: ft.Event[ft.Markdown]): await page.launch_url(e.data) page.add( - ft.ListView( + ft.SafeArea( expand=True, - controls=[ - ft.Markdown( - value=sample, - on_tap_link=navigate_md_link, - ) - ], - ), - ft.Divider(), - ft.ListView( - expand=True, - controls=[ - ft.Markdown( - value=sample, - selectable=True, - extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, - on_tap_link=navigate_md_link, - ) - ], + content=ft.Column( + expand=True, + controls=[ + ft.ListView( + expand=True, + controls=[ + ft.Markdown( + value=sample, + on_tap_link=navigate_md_link, + ) + ], + ), + ft.Divider(), + ft.ListView( + expand=True, + controls=[ + ft.Markdown( + value=sample, + selectable=True, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + on_tap_link=navigate_md_link, + ) + ], + ), + ], + ), ), ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/markdown/listviews/pyproject.toml b/sdk/python/examples/controls/markdown/listviews/pyproject.toml new file mode 100644 index 0000000000..3425a3daa6 --- /dev/null +++ b/sdk/python/examples/controls/markdown/listviews/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "markdown-listviews" +version = "1.0.0" +description = "Compares Markdown rendering in two ListViews, including selectable GitHub-style mode." +requires-python = ">=3.10" +keywords = ["markdown", "listview", "selectable", "comparison"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Markdown"] + +[tool.flet.metadata] +title = "ListViews" +controls = ["SafeArea", "Column", "ListView", "Divider", "Markdown"] +layout_pattern = "comparison" +complexity = "basic" +features = ["dual markdown views", "selectable markdown", "github extension set"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/menu_bar/__init__.py b/sdk/python/examples/controls/menu_bar/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/menu_bar/nested_submenus.py b/sdk/python/examples/controls/menu_bar/nested_submenus.py deleted file mode 100644 index c52c0ebc1b..0000000000 --- a/sdk/python/examples/controls/menu_bar/nested_submenus.py +++ /dev/null @@ -1,123 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - appbar_text_ref = ft.Ref[ft.Text]() - - def handle_menu_item_click(e: ft.Event[ft.MenuItemButton]): - text = e.control.content.value - page.show_dialog(ft.SnackBar(ft.Text(f"{text} was clicked!"))) - appbar_text_ref.current.value = text - page.update() - - def handle_submenu_open(e: ft.Event[ft.SubmenuButton]): - print(f"{e.control.content.value}.on_open") - - def handle_submenu_close(e: ft.Event[ft.SubmenuButton]): - print(f"{e.control.content.value}.on_close") - - def handle_submenu_hover(e: ft.Event[ft.SubmenuButton]): - print(f"{e.control.content.value}.on_hover") - - page.appbar = ft.AppBar( - title=ft.Text("Menus", ref=appbar_text_ref), - center_title=True, - bgcolor=ft.Colors.BLUE, - ) - - page.add( - ft.Row( - controls=[ - ft.MenuBar( - expand=True, - style=ft.MenuStyle( - alignment=ft.Alignment.TOP_LEFT, - bgcolor=ft.Colors.RED_300, - mouse_cursor={ - ft.ControlState.HOVERED: ft.MouseCursor.WAIT, - ft.ControlState.DEFAULT: ft.MouseCursor.ZOOM_OUT, - }, - ), - controls=[ - ft.SubmenuButton( - content=ft.Text("File"), - on_open=handle_submenu_open, - on_close=handle_submenu_close, - on_hover=handle_submenu_hover, - controls=[ - ft.MenuItemButton( - content=ft.Text("About"), - leading=ft.Icon(ft.Icons.INFO), - on_click=handle_menu_item_click, - style=ft.ButtonStyle( - bgcolor={ - ft.ControlState.HOVERED: ft.Colors.GREEN_100 - } - ), - ), - ft.MenuItemButton( - content=ft.Text("Save"), - leading=ft.Icon(ft.Icons.SAVE), - on_click=handle_menu_item_click, - style=ft.ButtonStyle( - bgcolor={ - ft.ControlState.HOVERED: ft.Colors.GREEN_100 - } - ), - ), - ft.MenuItemButton( - content=ft.Text("Quit"), - leading=ft.Icon(ft.Icons.CLOSE), - on_click=handle_menu_item_click, - style=ft.ButtonStyle( - bgcolor={ - ft.ControlState.HOVERED: ft.Colors.GREEN_100 - } - ), - ), - ], - ), - ft.SubmenuButton( - content=ft.Text("View"), - on_open=handle_submenu_open, - on_close=handle_submenu_close, - on_hover=handle_submenu_hover, - controls=[ - ft.SubmenuButton( - content=ft.Text("Zoom"), - controls=[ - ft.MenuItemButton( - content=ft.Text("Magnify"), - leading=ft.Icon(ft.Icons.ZOOM_IN), - close_on_click=False, - on_click=handle_menu_item_click, - style=ft.ButtonStyle( - bgcolor={ - ft.ControlState.HOVERED: ft.Colors.PURPLE_200 - } - ), - ), - ft.MenuItemButton( - content=ft.Text("Minify"), - leading=ft.Icon(ft.Icons.ZOOM_OUT), - close_on_click=False, - on_click=handle_menu_item_click, - style=ft.ButtonStyle( - bgcolor={ - ft.ControlState.HOVERED: ft.Colors.PURPLE_200 - } - ), - ), - ], - ) - ], - ), - ], - ) - ] - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/menu_bar/nested_submenus/main.py b/sdk/python/examples/controls/menu_bar/nested_submenus/main.py new file mode 100644 index 0000000000..fcdc64ff0f --- /dev/null +++ b/sdk/python/examples/controls/menu_bar/nested_submenus/main.py @@ -0,0 +1,135 @@ +import flet as ft + + +def main(page: ft.Page): + appbar_text_ref = ft.Ref[ft.Text]() + + def handle_menu_item_click(e: ft.Event[ft.MenuItemButton]): + text = e.control.content.value + page.show_dialog(ft.SnackBar(ft.Text(f"{text} was clicked!"))) + appbar_text_ref.current.value = text + appbar_text_ref.current.update() + + def handle_submenu_open(e: ft.Event[ft.SubmenuButton]): + print(f"{e.control.content.value}.on_open") + + def handle_submenu_close(e: ft.Event[ft.SubmenuButton]): + print(f"{e.control.content.value}.on_close") + + def handle_submenu_hover(e: ft.Event[ft.SubmenuButton]): + print(f"{e.control.content.value}.on_hover") + + page.appbar = ft.AppBar( + title=ft.Text("Menus", ref=appbar_text_ref), + center_title=True, + bgcolor=ft.Colors.BLUE, + ) + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.MenuBar( + expand=True, + style=ft.MenuStyle( + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.RED_300, + mouse_cursor={ + ft.ControlState.HOVERED: ft.MouseCursor.WAIT, + ft.ControlState.DEFAULT: ft.MouseCursor.ZOOM_OUT, + }, + ), + controls=[ + ft.SubmenuButton( + content=ft.Text("File"), + on_open=handle_submenu_open, + on_close=handle_submenu_close, + on_hover=handle_submenu_hover, + controls=[ + ft.MenuItemButton( + content=ft.Text("About"), + leading=ft.Icon(ft.Icons.INFO), + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.GREEN_100 + ) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Save"), + leading=ft.Icon(ft.Icons.SAVE), + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.GREEN_100 + ) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Quit"), + leading=ft.Icon(ft.Icons.CLOSE), + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.GREEN_100 + ) + } + ), + ), + ], + ), + ft.SubmenuButton( + content=ft.Text("View"), + on_open=handle_submenu_open, + on_close=handle_submenu_close, + on_hover=handle_submenu_hover, + controls=[ + ft.SubmenuButton( + content=ft.Text("Zoom"), + controls=[ + ft.MenuItemButton( + content=ft.Text("Magnify"), + leading=ft.Icon(ft.Icons.ZOOM_IN), + close_on_click=False, + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.PURPLE_200 + ) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Minify"), + leading=ft.Icon(ft.Icons.ZOOM_OUT), + close_on_click=False, + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.PURPLE_200 + ) + } + ), + ), + ], + ) + ], + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/menu_bar/nested_submenus/pyproject.toml b/sdk/python/examples/controls/menu_bar/nested_submenus/pyproject.toml new file mode 100644 index 0000000000..36115e22b6 --- /dev/null +++ b/sdk/python/examples/controls/menu_bar/nested_submenus/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "menu-bar-nested-submenus" +version = "1.0.0" +description = "Builds a MenuBar with nested submenus, hover callbacks, and click feedback." +requires-python = ">=3.10" +keywords = ["menu bar", "submenu", "nested menu", "events", "navigation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/MenuBar"] + +[tool.flet.metadata] +title = "MenuBar with nested submenus" +controls = ["SafeArea", "Row", "MenuBar", "SubmenuButton", "MenuItemButton", "AppBar", "SnackBar", "Text", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["nested submenus", "menu open and close callbacks", "menu item click feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/markdown.md b/sdk/python/packages/flet/docs/controls/markdown.md index 0b335d5bcd..566e286841 100644 --- a/sdk/python/packages/flet/docs/controls/markdown.md +++ b/sdk/python/packages/flet/docs/controls/markdown.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/markdown/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/markdown/media ### Code syntax highlight ```python ---8<-- "{{ examples }}/code_syntax_highlight.py" +--8<-- "{{ examples }}/code_syntax_highlight/main.py" ``` {{ image(example_media + "/code_syntax_highlight.png", alt="code-syntax-highlight", width="80%") }} @@ -32,7 +32,7 @@ example_media: ../examples/controls/markdown/media ### Custom text theme ```python ---8<-- "{{ examples }}/custom_text_theme.py" +--8<-- "{{ examples }}/custom_text_theme/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/menubar.md b/sdk/python/packages/flet/docs/controls/menubar.md index 6349b91155..915b80c71c 100644 --- a/sdk/python/packages/flet/docs/controls/menubar.md +++ b/sdk/python/packages/flet/docs/controls/menubar.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/menu_bar ### `MenuBar` with Nested Submenus ```python ---8<-- "{{ examples }}/nested_submenus.py" +--8<-- "{{ examples }}/nested_submenus/main.py" ``` {{ image(example_images + "/nested_submenus.gif", width="80%") }} diff --git a/sdk/python/packages/flet/docs/map/index.md b/sdk/python/packages/flet/docs/map/index.md index 399122754d..09ee58456e 100644 --- a/sdk/python/packages/flet/docs/map/index.md +++ b/sdk/python/packages/flet/docs/map/index.md @@ -43,31 +43,31 @@ More details [here](tilelayer.md). ### Basic ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` ### Camera Controls ```python ---8<-- "{{ examples }}/camera_controls.py" +--8<-- "{{ examples }}/camera_controls/main.py" ``` ### Idle Camera ```python ---8<-- "{{ examples }}/idle_camera.py" +--8<-- "{{ examples }}/idle_camera/main.py" ``` ### Interaction Flags ```python ---8<-- "{{ examples }}/interaction_flags.py" +--8<-- "{{ examples }}/interaction_flags/main.py" ``` ### Multiple Layers ```python ---8<-- "{{ examples }}/multi_layers.py" +--8<-- "{{ examples }}/multi_layers/main.py" ``` ## Reference diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_menu_bar.py b/sdk/python/packages/flet/integration_tests/examples/material/test_menu_bar.py index 3e8478097b..1435f4fd96 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_menu_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_menu_bar.py @@ -2,8 +2,7 @@ import flet as ft import flet.testing as ftt - -from examples.controls.menu_bar import nested_submenus +from examples.controls.menu_bar.nested_submenus import main as nested_submenus @pytest.mark.asyncio(loop_scope="function") From 7f9f5f10f376feaabbea13b48171cc3c3dd09351 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sat, 14 Mar 2026 18:31:18 -0700 Subject: [PATCH 56/96] Enable SafeArea expansion Add expand=True to ft.SafeArea so the nested Map can fill the available space. The Map already had expand=True; this change ensures the SafeArea no longer constrains the map's layout. --- sdk/python/examples/controls/map/basic/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/python/examples/controls/map/basic/main.py b/sdk/python/examples/controls/map/basic/main.py index c2b29c858c..45a4d8870c 100644 --- a/sdk/python/examples/controls/map/basic/main.py +++ b/sdk/python/examples/controls/map/basic/main.py @@ -5,6 +5,7 @@ def main(page: ft.Page): page.add( ft.SafeArea( + expand=True, content=ftm.Map( expand=True, layers=[ From e92c6d60d6c30e86078c530512cf076cb8a5fa9b Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 15 Mar 2026 09:04:16 -0700 Subject: [PATCH 57/96] Restructure MenuItemButton example Move and reorganize the MenuItemButton example into a subpackage (basic/main.py) and remove the old package __init__.py. Add a pyproject.toml for the example with gallery/metadata and dependencies. Update the example code to wrap UI in a SafeArea > Column (remove an explicit page.update call) and adjust layout (Row + Container nesting and avoid_intrusions settings). Update docs to point to the new example path and fix the integration test import to reference examples.controls.menu_item_button.basic.main. --- .../controls/menu_item_button/__init__.py | 0 .../{basic.py => basic/main.py} | 30 +++++++++++++------ .../menu_item_button/basic/pyproject.toml | 26 ++++++++++++++++ .../flet/docs/controls/menuitembutton.md | 2 +- .../material/test_menu_item_button.py | 3 +- 5 files changed, 49 insertions(+), 12 deletions(-) delete mode 100644 sdk/python/examples/controls/menu_item_button/__init__.py rename sdk/python/examples/controls/menu_item_button/{basic.py => basic/main.py} (71%) create mode 100644 sdk/python/examples/controls/menu_item_button/basic/pyproject.toml diff --git a/sdk/python/examples/controls/menu_item_button/__init__.py b/sdk/python/examples/controls/menu_item_button/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/menu_item_button/basic.py b/sdk/python/examples/controls/menu_item_button/basic/main.py similarity index 71% rename from sdk/python/examples/controls/menu_item_button/basic.py rename to sdk/python/examples/controls/menu_item_button/basic/main.py index 4b15491094..97bf6dc256 100644 --- a/sdk/python/examples/controls/menu_item_button/basic.py +++ b/sdk/python/examples/controls/menu_item_button/basic/main.py @@ -10,7 +10,6 @@ def handle_color_click(e: ft.Event[ft.MenuItemButton]): color = e.control.content.value background_container.content.value = f"{color} background color" background_container.bgcolor = color.lower() - page.update() def handle_on_hover(e: ft.Event[ft.MenuItemButton]): print(e) @@ -54,16 +53,29 @@ def handle_on_hover(e: ft.Event[ft.MenuItemButton]): ) page.add( - ft.Row(controls=[menubar]), - background_container := ft.Container( + ft.SafeArea( expand=True, - bgcolor=ft.Colors.WHITE, - alignment=ft.Alignment.CENTER, - content=ft.Text( - value="Choose a bgcolor from the menu", - style=ft.TextStyle(weight=ft.FontWeight.W_500), + avoid_intrusions_left=False, + avoid_intrusions_top=False, + avoid_intrusions_right=False, + avoid_intrusions_bottom=False, + content=ft.Column( + expand=True, + spacing=0, + controls=[ + ft.Row(controls=[menubar]), + background_container := ft.Container( + expand=True, + bgcolor=ft.Colors.WHITE, + alignment=ft.Alignment.CENTER, + content=ft.Text( + value="Choose a bgcolor from the menu", + style=ft.TextStyle(weight=ft.FontWeight.W_500), + ), + ), + ], ), - ), + ) ) diff --git a/sdk/python/examples/controls/menu_item_button/basic/pyproject.toml b/sdk/python/examples/controls/menu_item_button/basic/pyproject.toml new file mode 100644 index 0000000000..b747c3d414 --- /dev/null +++ b/sdk/python/examples/controls/menu_item_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "menu-item-button-basic" +version = "1.0.0" +description = "Uses MenuItemButton items to change page background color from a submenu with hover styling." +requires-python = ">=3.10" +keywords = ["menu item button", "submenu", "hover style", "events", "background color"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/MenuItemButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Row", "MenuBar", "SubmenuButton", "MenuItemButton", "Container", "Text", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["submenu item click handling", "menu item hover styling", "dynamic background color updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/menuitembutton.md b/sdk/python/packages/flet/docs/controls/menuitembutton.md index 02d8e61783..a035f76216 100644 --- a/sdk/python/packages/flet/docs/controls/menuitembutton.md +++ b/sdk/python/packages/flet/docs/controls/menuitembutton.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/menu_item_button ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_menu_item_button.py b/sdk/python/packages/flet/integration_tests/examples/material/test_menu_item_button.py index 3dd5a18140..c3cf8cd0c2 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_menu_item_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_menu_item_button.py @@ -2,8 +2,7 @@ import flet as ft import flet.testing as ftt - -from examples.controls.menu_item_button import basic +from examples.controls.menu_item_button.basic import main as basic @pytest.mark.asyncio(loop_scope="function") From c9d47eb87f056b5278215aebdf062de3e8865bc5 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 15 Mar 2026 09:36:51 -0700 Subject: [PATCH 58/96] Refactor navigation_bar example and add metadata Move navigation_bar example into a submodule (basic/main.py), delete the package __init__.py, and wrap the example body in a SafeArea. Add a pyproject.toml to provide example metadata and packaging info for the basic navigation bar sample. Update the integration test import and parameter to use the renamed main entry (from examples.controls.navigation_bar.basic.main import main as basic) and pass the function itself to the test harness. --- .../controls/navigation_bar/__init__.py | 0 .../{basic.py => basic/main.py} | 6 ++++- .../navigation_bar/basic/pyproject.toml | 26 +++++++++++++++++++ .../examples/material/test_navigation_bar.py | 5 ++-- 4 files changed, 33 insertions(+), 4 deletions(-) delete mode 100644 sdk/python/examples/controls/navigation_bar/__init__.py rename sdk/python/examples/controls/navigation_bar/{basic.py => basic/main.py} (86%) create mode 100644 sdk/python/examples/controls/navigation_bar/basic/pyproject.toml diff --git a/sdk/python/examples/controls/navigation_bar/__init__.py b/sdk/python/examples/controls/navigation_bar/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/navigation_bar/basic.py b/sdk/python/examples/controls/navigation_bar/basic/main.py similarity index 86% rename from sdk/python/examples/controls/navigation_bar/basic.py rename to sdk/python/examples/controls/navigation_bar/basic/main.py index 2e0b3c844e..b10a48b2df 100644 --- a/sdk/python/examples/controls/navigation_bar/basic.py +++ b/sdk/python/examples/controls/navigation_bar/basic/main.py @@ -16,7 +16,11 @@ def main(page: ft.Page): ] ) - page.add(ft.Text("Body!")) + page.add( + ft.SafeArea( + content=ft.Text("Body!"), + ) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/navigation_bar/basic/pyproject.toml b/sdk/python/examples/controls/navigation_bar/basic/pyproject.toml new file mode 100644 index 0000000000..4457421a1c --- /dev/null +++ b/sdk/python/examples/controls/navigation_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-bar-basic" +version = "1.0.0" +description = "Demonstrates a Material NavigationBar with three destination tabs." +requires-python = ">=3.10" +keywords = ["navigation bar", "bottom navigation", "destinations", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationBar"] + +[tool.flet.metadata] +title = "Basic" +controls = ["NavigationBar", "NavigationBarDestination", "SafeArea", "Text"] +layout_pattern = "tabbed-navigation" +complexity = "basic" +features = ["bottom navigation", "destination tabs"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_bar.py b/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_bar.py index bc8f5bf84e..941244a2dc 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_bar.py @@ -2,8 +2,7 @@ import flet as ft import flet.testing as ftt - -from examples.controls.navigation_bar import basic +from examples.controls.navigation_bar.basic.main import main as basic @pytest.mark.asyncio(loop_scope="function") @@ -33,7 +32,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": basic.main}], + [{"flet_app_main": basic}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") From a886324b5488061fd08df2eccd011d3126d25ea9 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 15 Mar 2026 10:05:19 -0700 Subject: [PATCH 59/96] Restructure navigation drawer examples Rename position_start.py and position_end.py into their own main.py modules, remove the now-empty package __init__.py, and wrap example Buttons with SafeArea. Add pyproject.toml metadata for both example packages. Update docs to reference the new example paths (including navigationbar and navigationdrawer docs) and adjust integration tests to import and use the relocated main functions. --- .../controls/navigation_drawer/__init__.py | 0 .../{position_end.py => position_end/main.py} | 9 ++++--- .../position_end/pyproject.toml | 26 +++++++++++++++++++ .../main.py} | 9 ++++--- .../position_start/pyproject.toml | 26 +++++++++++++++++++ .../flet/docs/controls/navigationbar/index.md | 2 +- .../docs/controls/navigationdrawer/index.md | 4 +-- .../material/test_navigation_drawer.py | 10 ++++--- 8 files changed, 73 insertions(+), 13 deletions(-) delete mode 100644 sdk/python/examples/controls/navigation_drawer/__init__.py rename sdk/python/examples/controls/navigation_drawer/{position_end.py => position_end/main.py} (85%) create mode 100644 sdk/python/examples/controls/navigation_drawer/position_end/pyproject.toml rename sdk/python/examples/controls/navigation_drawer/{position_start.py => position_start/main.py} (89%) create mode 100644 sdk/python/examples/controls/navigation_drawer/position_start/pyproject.toml diff --git a/sdk/python/examples/controls/navigation_drawer/__init__.py b/sdk/python/examples/controls/navigation_drawer/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/navigation_drawer/position_end.py b/sdk/python/examples/controls/navigation_drawer/position_end/main.py similarity index 85% rename from sdk/python/examples/controls/navigation_drawer/position_end.py rename to sdk/python/examples/controls/navigation_drawer/position_end/main.py index 85800af7f3..7201b80ab1 100644 --- a/sdk/python/examples/controls/navigation_drawer/position_end.py +++ b/sdk/python/examples/controls/navigation_drawer/position_end/main.py @@ -26,10 +26,13 @@ async def handle_change(e: ft.Event[ft.NavigationDrawer]): ), ], ) + page.add( - ft.Button( - content="Show end drawer", - on_click=handle_show_drawer, + ft.SafeArea( + content=ft.Button( + content="Show end drawer", + on_click=handle_show_drawer, + ) ) ) diff --git a/sdk/python/examples/controls/navigation_drawer/position_end/pyproject.toml b/sdk/python/examples/controls/navigation_drawer/position_end/pyproject.toml new file mode 100644 index 0000000000..79827c831f --- /dev/null +++ b/sdk/python/examples/controls/navigation_drawer/position_end/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-drawer-position-end" +version = "1.0.0" +description = "Demonstrates an end-position NavigationDrawer with destination selection handling." +requires-python = ">=3.10" +keywords = ["navigation drawer", "drawer", "navigation", "end position"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationDrawer"] + +[tool.flet.metadata] +title = "End Position" +controls = ["NavigationDrawer", "NavigationDrawerDestination", "Button", "SafeArea", "Page"] +layout_pattern = "drawer-navigation" +complexity = "basic" +features = ["end drawer", "destination callbacks", "open/close actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/navigation_drawer/position_start.py b/sdk/python/examples/controls/navigation_drawer/position_start/main.py similarity index 89% rename from sdk/python/examples/controls/navigation_drawer/position_start.py rename to sdk/python/examples/controls/navigation_drawer/position_start/main.py index 4002748777..438b560964 100644 --- a/sdk/python/examples/controls/navigation_drawer/position_start.py +++ b/sdk/python/examples/controls/navigation_drawer/position_start/main.py @@ -35,10 +35,13 @@ async def handle_change(e: ft.Event[ft.NavigationDrawer]): ), ], ) + page.add( - ft.Button( - content="Show drawer", - on_click=handle_show_drawer, + ft.SafeArea( + content=ft.Button( + content="Show drawer", + on_click=handle_show_drawer, + ) ) ) diff --git a/sdk/python/examples/controls/navigation_drawer/position_start/pyproject.toml b/sdk/python/examples/controls/navigation_drawer/position_start/pyproject.toml new file mode 100644 index 0000000000..b240c696aa --- /dev/null +++ b/sdk/python/examples/controls/navigation_drawer/position_start/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-drawer-position-start" +version = "1.0.0" +description = "Demonstrates a start-position NavigationDrawer with labeled destinations and callbacks." +requires-python = ">=3.10" +keywords = ["navigation drawer", "drawer", "navigation", "start position"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationDrawer"] + +[tool.flet.metadata] +title = "Start Position" +controls = ["NavigationDrawer", "NavigationDrawerDestination", "Button", "SafeArea", "Container", "Divider", "Page"] +layout_pattern = "drawer-navigation" +complexity = "basic" +features = ["start drawer", "navigation destinations", "selection and dismiss callbacks"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/navigationbar/index.md b/sdk/python/packages/flet/docs/controls/navigationbar/index.md index e1ee7317a4..38acbc7def 100644 --- a/sdk/python/packages/flet/docs/controls/navigationbar/index.md +++ b/sdk/python/packages/flet/docs/controls/navigationbar/index.md @@ -15,7 +15,7 @@ example_images: ../../test-images/examples/material/golden/macos/navigation_bar ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/navigationdrawer/index.md b/sdk/python/packages/flet/docs/controls/navigationdrawer/index.md index db2ce17308..2c890ccf5a 100644 --- a/sdk/python/packages/flet/docs/controls/navigationdrawer/index.md +++ b/sdk/python/packages/flet/docs/controls/navigationdrawer/index.md @@ -15,7 +15,7 @@ example_images: ../../test-images/examples/material/golden/macos/navigation_draw ### Start-aligned drawer ```python ---8<-- "{{ examples }}/position_start.py" +--8<-- "{{ examples }}/position_start/main.py" ``` {{ image(example_images + "/position_start.gif", alt="position-start", width="80%") }} @@ -24,7 +24,7 @@ example_images: ../../test-images/examples/material/golden/macos/navigation_draw ### End-aligned drawer ```python ---8<-- "{{ examples }}/position_end.py" +--8<-- "{{ examples }}/position_end/main.py" ``` {{ image(example_images + "/position_end.gif", alt="position-end", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_drawer.py b/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_drawer.py index 16b37422f5..3a53e85cc7 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_drawer.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_drawer.py @@ -2,8 +2,10 @@ import flet as ft import flet.testing as ftt - -from examples.controls.navigation_drawer import position_end, position_start +from examples.controls.navigation_drawer.position_end.main import main as position_end +from examples.controls.navigation_drawer.position_start.main import ( + main as position_start, +) @pytest.mark.asyncio(loop_scope="function") @@ -39,7 +41,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": position_end.main}], + [{"flet_app_main": position_end}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") @@ -87,7 +89,7 @@ async def test_position_end(flet_app_function: ftt.FletTestApp): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": position_start.main}], + [{"flet_app_main": position_start}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") From 871adc7ca120f1fc4d822c95047ffb7b5e1ca3d4 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 15 Mar 2026 10:16:52 -0700 Subject: [PATCH 60/96] Reorganize NavigationRail example and update refs Move the NavigationRail example into a subdirectory (basic/main.py), remove the old __init__.py, and add a pyproject.toml for the example. Wrap the example's Row in a SafeArea (using content property) to improve layout. Update docs include path to point to basic/main.py and adjust the integration test import/parameterization to import the example main function. Also add the "async" keyword to two NavigationDrawer example pyproject metadata. --- .../position_end/pyproject.toml | 2 +- .../position_start/pyproject.toml | 2 +- .../controls/navigation_rail/__init__.py | 0 .../{basic.py => basic/main.py} | 23 +++++++++------- .../navigation_rail/basic/pyproject.toml | 26 +++++++++++++++++++ .../docs/controls/navigationrail/index.md | 2 +- .../examples/material/test_navigation_rail.py | 5 ++-- 7 files changed, 44 insertions(+), 16 deletions(-) delete mode 100644 sdk/python/examples/controls/navigation_rail/__init__.py rename sdk/python/examples/controls/navigation_rail/{basic.py => basic/main.py} (73%) create mode 100644 sdk/python/examples/controls/navigation_rail/basic/pyproject.toml diff --git a/sdk/python/examples/controls/navigation_drawer/position_end/pyproject.toml b/sdk/python/examples/controls/navigation_drawer/position_end/pyproject.toml index 79827c831f..f649167a6b 100644 --- a/sdk/python/examples/controls/navigation_drawer/position_end/pyproject.toml +++ b/sdk/python/examples/controls/navigation_drawer/position_end/pyproject.toml @@ -3,7 +3,7 @@ name = "navigation-drawer-position-end" version = "1.0.0" description = "Demonstrates an end-position NavigationDrawer with destination selection handling." requires-python = ">=3.10" -keywords = ["navigation drawer", "drawer", "navigation", "end position"] +keywords = ["navigation drawer", "drawer", "navigation", "end position", "async"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] dependencies = ["flet"] diff --git a/sdk/python/examples/controls/navigation_drawer/position_start/pyproject.toml b/sdk/python/examples/controls/navigation_drawer/position_start/pyproject.toml index b240c696aa..de3b5e011f 100644 --- a/sdk/python/examples/controls/navigation_drawer/position_start/pyproject.toml +++ b/sdk/python/examples/controls/navigation_drawer/position_start/pyproject.toml @@ -3,7 +3,7 @@ name = "navigation-drawer-position-start" version = "1.0.0" description = "Demonstrates a start-position NavigationDrawer with labeled destinations and callbacks." requires-python = ">=3.10" -keywords = ["navigation drawer", "drawer", "navigation", "start position"] +keywords = ["navigation drawer", "drawer", "navigation", "start position", "async"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] dependencies = ["flet"] diff --git a/sdk/python/examples/controls/navigation_rail/__init__.py b/sdk/python/examples/controls/navigation_rail/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/navigation_rail/basic.py b/sdk/python/examples/controls/navigation_rail/basic/main.py similarity index 73% rename from sdk/python/examples/controls/navigation_rail/basic.py rename to sdk/python/examples/controls/navigation_rail/basic/main.py index d43fee2ac8..1637fcb988 100644 --- a/sdk/python/examples/controls/navigation_rail/basic.py +++ b/sdk/python/examples/controls/navigation_rail/basic/main.py @@ -34,17 +34,20 @@ def main(page: ft.Page): ) page.add( - ft.Row( + ft.SafeArea( expand=True, - controls=[ - ft.SelectionArea(content=rail), - ft.VerticalDivider(width=1), - ft.Column( - alignment=ft.MainAxisAlignment.START, - expand=True, - controls=[ft.Text("Body!")], - ), - ], + content=ft.Row( + expand=True, + controls=[ + ft.SelectionArea(content=rail), + ft.VerticalDivider(width=1), + ft.Column( + alignment=ft.MainAxisAlignment.START, + expand=True, + controls=[ft.Text("Body!")], + ), + ], + ), ) ) diff --git a/sdk/python/examples/controls/navigation_rail/basic/pyproject.toml b/sdk/python/examples/controls/navigation_rail/basic/pyproject.toml new file mode 100644 index 0000000000..9187d09833 --- /dev/null +++ b/sdk/python/examples/controls/navigation_rail/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-rail-basic" +version = "1.0.0" +description = "Demonstrates a Material NavigationRail with three destinations and custom leading FAB." +requires-python = ">=3.10" +keywords = ["navigation rail", "material", "navigation", "rail", "destinations"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationRail"] + +[tool.flet.metadata] +title = "Basic" +controls = ["NavigationRail", "NavigationRailDestination", "SafeArea", "FloatingActionButton", "SelectionArea", "Page", "VerticalDivider", "Column", "Row", "Text"] +layout_pattern = "side-navigation" +complexity = "basic" +features = ["navigation rail", "destination selection", "leading action button"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/navigationrail/index.md b/sdk/python/packages/flet/docs/controls/navigationrail/index.md index 5b4a8859db..092854fe13 100644 --- a/sdk/python/packages/flet/docs/controls/navigationrail/index.md +++ b/sdk/python/packages/flet/docs/controls/navigationrail/index.md @@ -15,7 +15,7 @@ example_images: ../../test-images/examples/material/golden/macos/navigation_rail ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_rail.py b/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_rail.py index 4c7c7933e1..5cc871fb4a 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_rail.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_navigation_rail.py @@ -2,8 +2,7 @@ import flet as ft import flet.testing as ftt - -from examples.controls.navigation_rail import basic +from examples.controls.navigation_rail.basic.main import main as basic @pytest.mark.asyncio(loop_scope="function") @@ -35,7 +34,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": basic.main}], + [{"flet_app_main": basic}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") From f20f0f73cfc66685f5a3ac4b98b7d1e04eefeaf9 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 15 Mar 2026 15:34:38 -0700 Subject: [PATCH 61/96] Refactor OutlinedButton examples into projects Convert OutlinedButton examples into standalone example projects: remove legacy top-level example scripts and add per-example folders with main.py and pyproject.toml for basic, custom_content, icons, and handling_clicks. Wrap example app content in ft.SafeArea(ft.Column(...)) to ensure correct mobile rendering and follow the examples migration guidance (SKILL.md updated). Update docs to reference the new example paths and adjust integration tests to import the new main functions; also update golden images/gif for the handling_clicks example. --- .../create-flet-example-projects/SKILL.md | 1 + .../controls/outlined_button/__init__.py | 0 .../controls/outlined_button/basic.py | 14 ------ .../controls/outlined_button/basic/main.py | 20 ++++++++ .../outlined_button/basic/pyproject.toml | 26 +++++++++++ .../outlined_button/custom_content.py | 37 --------------- .../outlined_button/custom_content/main.py | 43 ++++++++++++++++++ .../custom_content/pyproject.toml | 26 +++++++++++ .../main.py} | 12 +++-- .../handling_clicks/pyproject.toml | 26 +++++++++++ .../controls/outlined_button/icons.py | 18 -------- .../controls/outlined_button/icons/main.py | 26 +++++++++++ .../outlined_button/icons/pyproject.toml | 26 +++++++++++ .../flet/docs/controls/outlinedbutton.md | 8 ++-- .../macos/outlined_button/handling_clicks.gif | Bin 17506 -> 17496 bytes .../outlined_button/handling_clicks1.png | Bin 17020 -> 17018 bytes .../outlined_button/handling_clicks2.png | Bin 16732 -> 16729 bytes .../outlined_button/handling_clicks3.png | Bin 17072 -> 17069 bytes .../examples/material/test_outlined_button.py | 18 ++++---- 19 files changed, 214 insertions(+), 87 deletions(-) delete mode 100644 sdk/python/examples/controls/outlined_button/__init__.py delete mode 100644 sdk/python/examples/controls/outlined_button/basic.py create mode 100644 sdk/python/examples/controls/outlined_button/basic/main.py create mode 100644 sdk/python/examples/controls/outlined_button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/outlined_button/custom_content.py create mode 100644 sdk/python/examples/controls/outlined_button/custom_content/main.py create mode 100644 sdk/python/examples/controls/outlined_button/custom_content/pyproject.toml rename sdk/python/examples/controls/outlined_button/{handling_clicks.py => handling_clicks/main.py} (67%) create mode 100644 sdk/python/examples/controls/outlined_button/handling_clicks/pyproject.toml delete mode 100644 sdk/python/examples/controls/outlined_button/icons.py create mode 100644 sdk/python/examples/controls/outlined_button/icons/main.py create mode 100644 sdk/python/examples/controls/outlined_button/icons/pyproject.toml diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 798edb5e25..66c2836db1 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -71,6 +71,7 @@ Ensure each runnable example is a standalone project containing: - Apply this `page.update()` rule to all examples in the touched folder (new, migrated, and already converted). - Wrap app content in `ft.SafeArea` so example renders correctly on mobile. - Add `expand=True` to `ft.SafeArea` only when needed for correct layout/sizing (for example to avoid Infinity/NaN sizing issues), and avoid adding it when not necessary. +- When converting legacy `page.add(a, b, ...)` style examples, wrap the controls in `ft.Column(controls=[...])` inside `ft.SafeArea(content=...)` rather than `ft.Row`, unless the original code explicitly used a row layout. - Apply this to all examples in the touched folder (new, migrated, and already converted), not only files changed by moves. - During validation, confirm every `/main.py` in scope includes a top-level `ft.SafeArea` around rendered content. diff --git a/sdk/python/examples/controls/outlined_button/__init__.py b/sdk/python/examples/controls/outlined_button/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/outlined_button/basic.py b/sdk/python/examples/controls/outlined_button/basic.py deleted file mode 100644 index 2f9e2dcfd8..0000000000 --- a/sdk/python/examples/controls/outlined_button/basic.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "OutlinedButton Example" - - page.add( - ft.OutlinedButton(content="Outlined button"), - ft.OutlinedButton(content="Disabled button", disabled=True), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/outlined_button/basic/main.py b/sdk/python/examples/controls/outlined_button/basic/main.py new file mode 100644 index 0000000000..796f7e046d --- /dev/null +++ b/sdk/python/examples/controls/outlined_button/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "OutlinedButton Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton(content="Outlined button"), + ft.OutlinedButton(content="Disabled button", disabled=True), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/outlined_button/basic/pyproject.toml b/sdk/python/examples/controls/outlined_button/basic/pyproject.toml new file mode 100644 index 0000000000..5a0c1b037e --- /dev/null +++ b/sdk/python/examples/controls/outlined_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "outlined-button-basic" +version = "1.0.0" +description = "Shows enabled and disabled OutlinedButton variants." +requires-python = ">=3.10" +keywords = ["outlined button", "button", "material", "disabled states"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/OutlinedButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "OutlinedButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["enabled and disabled states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/outlined_button/custom_content.py b/sdk/python/examples/controls/outlined_button/custom_content.py deleted file mode 100644 index b56740234d..0000000000 --- a/sdk/python/examples/controls/outlined_button/custom_content.py +++ /dev/null @@ -1,37 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "OutlinedButton Example" - page.theme_mode = ft.ThemeMode.LIGHT - - page.add( - ft.OutlinedButton( - width=150, - content=ft.Row( - alignment=ft.MainAxisAlignment.SPACE_AROUND, - controls=[ - ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), - ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), - ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), - ], - ), - ), - ft.OutlinedButton( - content=ft.Container( - padding=ft.Padding.all(10), - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - spacing=5, - controls=[ - ft.Text(value="Compound button", size=20), - ft.Text(value="This is secondary text"), - ], - ), - ), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/outlined_button/custom_content/main.py b/sdk/python/examples/controls/outlined_button/custom_content/main.py new file mode 100644 index 0000000000..9894601896 --- /dev/null +++ b/sdk/python/examples/controls/outlined_button/custom_content/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "OutlinedButton Example" + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton( + width=150, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), + ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), + ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), + ], + ), + ), + ft.OutlinedButton( + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + spacing=5, + controls=[ + ft.Text(value="Compound button", size=20), + ft.Text(value="This is secondary text"), + ], + ), + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/outlined_button/custom_content/pyproject.toml b/sdk/python/examples/controls/outlined_button/custom_content/pyproject.toml new file mode 100644 index 0000000000..a85e0741a0 --- /dev/null +++ b/sdk/python/examples/controls/outlined_button/custom_content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "outlined-button-custom-content" +version = "1.0.0" +description = "Demonstrates OutlinedButtons with custom content and icon/text composition." +requires-python = ">=3.10" +keywords = ["outlined button", "custom content", "compound button", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/OutlinedButton"] + +[tool.flet.metadata] +title = "Custom content" +controls = ["SafeArea", "OutlinedButton", "Row", "Column", "Icon", "Container", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom button content", "compound layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/outlined_button/handling_clicks.py b/sdk/python/examples/controls/outlined_button/handling_clicks/main.py similarity index 67% rename from sdk/python/examples/controls/outlined_button/handling_clicks.py rename to sdk/python/examples/controls/outlined_button/handling_clicks/main.py index dab5b33bf3..8cb6d21646 100644 --- a/sdk/python/examples/controls/outlined_button/handling_clicks.py +++ b/sdk/python/examples/controls/outlined_button/handling_clicks/main.py @@ -18,11 +18,13 @@ def handle_button_click(e: ft.Event[ft.OutlinedButton]): message = ft.Text() page.add( - ft.Column( - controls=[button, message], - alignment=ft.MainAxisAlignment.CENTER, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - expand=True, + ft.SafeArea( + content=ft.Column( + controls=[button, message], + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + expand=True, + ) ) ) diff --git a/sdk/python/examples/controls/outlined_button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/outlined_button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..db34e2728d --- /dev/null +++ b/sdk/python/examples/controls/outlined_button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "outlined-button-handling-clicks" +version = "1.0.0" +description = "Demonstrates OutlinedButton click handling with a live counter." +requires-python = ">=3.10" +keywords = ["outlined button", "events", "on_click", "counter", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/OutlinedButton"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "OutlinedButton", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["click event handling", "dynamic label updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/outlined_button/icons.py b/sdk/python/examples/controls/outlined_button/icons.py deleted file mode 100644 index 9f1d045ce7..0000000000 --- a/sdk/python/examples/controls/outlined_button/icons.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "OutlinedButton Example" - - page.add( - ft.OutlinedButton(content="Button with icon", icon=ft.Icons.CHAIR_OUTLINED), - ft.OutlinedButton( - content="Button with colorful icon", - icon=ft.Icons.PARK_ROUNDED, - icon_color=ft.Colors.GREEN_400, - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/outlined_button/icons/main.py b/sdk/python/examples/controls/outlined_button/icons/main.py new file mode 100644 index 0000000000..733c763310 --- /dev/null +++ b/sdk/python/examples/controls/outlined_button/icons/main.py @@ -0,0 +1,26 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "OutlinedButton Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton( + content="Button with icon", icon=ft.Icons.CHAIR_OUTLINED + ), + ft.OutlinedButton( + content="Button with colorful icon", + icon=ft.Icons.PARK_ROUNDED, + icon_color=ft.Colors.GREEN_400, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/outlined_button/icons/pyproject.toml b/sdk/python/examples/controls/outlined_button/icons/pyproject.toml new file mode 100644 index 0000000000..bc759a083d --- /dev/null +++ b/sdk/python/examples/controls/outlined_button/icons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "outlined-button-icons" +version = "1.0.0" +description = "Shows OutlinedButtons with icon and color variations." +requires-python = ">=3.10" +keywords = ["outlined button", "icon button", "material icons", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/OutlinedButton"] + +[tool.flet.metadata] +title = "Icons" +controls = ["SafeArea", "OutlinedButton", "Icon"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["icon support"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/outlinedbutton.md b/sdk/python/packages/flet/docs/controls/outlinedbutton.md index e8b2e2004b..0b09bc2207 100644 --- a/sdk/python/packages/flet/docs/controls/outlinedbutton.md +++ b/sdk/python/packages/flet/docs/controls/outlinedbutton.md @@ -14,7 +14,7 @@ example_images: ../test-images/examples/material/golden/macos/outlined_button ### Basic example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} @@ -23,7 +23,7 @@ example_images: ../test-images/examples/material/golden/macos/outlined_button ### Handling clicks ```python ---8<-- "{{ examples }}/handling_clicks.py" +--8<-- "{{ examples }}/handling_clicks/main.py" ``` {{ image(example_images + "/handling_clicks.gif", alt="handling-clicks", width="80%") }} @@ -32,7 +32,7 @@ example_images: ../test-images/examples/material/golden/macos/outlined_button ### Icons ```python ---8<-- "{{ examples }}/icons.py" +--8<-- "{{ examples }}/icons/main.py" ``` {{ image(example_images + "/icons.png", alt="icons", width="80%") }} @@ -41,7 +41,7 @@ example_images: ../test-images/examples/material/golden/macos/outlined_button ### Custom content ```python ---8<-- "{{ examples }}/custom_content.py" +--8<-- "{{ examples }}/custom_content/main.py" ``` {{ image(example_images + "/custom_content.png", alt="custom-content", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/outlined_button/handling_clicks.gif b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/outlined_button/handling_clicks.gif index 36127a5cd6df18acf0a117bccf5f18a09673a1f8..1a8794494abfdbd23ec04622b2be39906b72cc26 100644 GIT binary patch delta 6778 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 KV_B>H#UHj$$wgjBT6$b_1s64D%%4n?Ju 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 K++8x=Mg1STKZYRy diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/outlined_button/handling_clicks1.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/outlined_button/handling_clicks1.png index cc8dece8c7a239d66b093323810d46c43afd58d6..2a155397147f8d681e1138bf7d14e97046f47e4f 100644 GIT binary patch delta 8258 zcmZ{JWn2|sxb+|)4blz5K|v5ux;vEaMnIZFN!MZEPa`4Xk&>3~?hX~CyF=*|={Vf+ zeec&hALqCC%Sz4m!Y!kD9!{NKkB;q_# zIh82Zk1gJ$t}qdrs;YOdM!vuBd>0v6NKtou98^(3B;s`(64BC9^j=m6b|zr{3>U;B zruJo^MJBd2G*nize2D z+|Qp!zgGr;I6}hh$sde?2Z*tOg$1lhc^2jzqntz-3o}>}hg1FMrRZRJqb9d!Cl~h%GP$3bn ztP%`tM0$vu(5m|A$VdPX%(ZkqIkjhbvV;y`c$|FGhADI|FAqb{93T9R#&L3sxxd^( z#E!&GG=sswxdG|3kFU|EgJmQBjHJ{6L0N~vRQzrj&pA0&b?KOy9f0Z@_sXMAw8fY> zGytDb1Ow6Sm)2|`XQV<=S?|0M$Dv<=24paZ<93M)$%IBm79Sq{Vs+iW!~vuXjx=JZ z1STitnMsma%$?>>uyULiLy<`GeASFluY>t%Phv1Ka{Hz0&WW|-LKPnHXq=ZSHiB61KRp>E{bnGkX8us2y;& zi|E%kXl477KG;?7-sN+Vh_CIknCIo^TU;z7q_0g<9e6k)L#UV20<)+nEfyhzfag1C*dE%RW3TXH zRD48k2)aTno#sLWj5&vOu`r5M0d+r#C^1o#d0UnWM(e* z93CE~60mv!V6RBad6wy+Peb7PFt`DsrDwwhg8K030qH|ZTU!>^g4Nrw_xW6e;=vA_ z5Y+MBZ92{scC{nA9rj+x$;tT@C5^1r5?JBZQB*R+Msgb)F%A$QVsv1krJhh$PVTF| zc|*CY^D>?N&Q4_WyNSuZY*v*r%+mKsTg}+j~|or*{m`0PWz{aOBi2mtvbiL(CBaHXZo2OOkYQl^bKfz$9r#XZ-J(a zcktZd=}TFdvU?&DjAux1t)v=xjv~j5W(GR9@cNm0J9J~u>)Zz4?F(t1=e`|SmHL@E zt3Fv>{481t_*CXRH9Jm164iJkcrMl(&~_>uxJDsyYcC08IlbRBxaf*;ILd95!?Cu1 z26T>h({0*#HXC40$u2c}bwMB}rgz6{^7XZQ>*BJ@JVpxU=slQ@-L?ay3e-?_RW~Ak zeuTp=_g3t37kv0!q6y0uN2_8*`_B&W@$ep&hyT7luwr@+NcGlT(qM&?H$ORxs*s|vZ!iQ*V zK#?FZHWnlh@!Afe6?9qO9I`vb-xQYi%+-6K=jb>`f(cOu-15Rx#xRWg$M2tXEVi4g zvsYB1W^p~=xMO9sMfZ%JsYg|lkuG1oZbZ%97K~*h)0Ulb*R_uiFZ@IIL_d#ga{G!u zn6C?p)rB$fo#NV+)eL2R<66IvO#p(*+cPfh&OvR@H)^V>8~lP53mx{lZ@9HvlPgC=IH^#U2Gb&xZIlQe?GKB}cOQwMv08w-bRRb|J@ zooIp1^vjlfE?jYGxqA$yW_=2=R%5@YHh3cS*dXIQBCv4UDLUt^Npw?$*?9)B$gM(O z!K$<~S}K3lOU>6s&2$G&FLLyI><8*WXUC}0*6P7n)klwaZ}zO03g7ZrYPU-0Nb)<) zlMSVR`S1+M{NxGw;UPhbLLAM*G09*pEp0S_fnoiepva|^#xO@;3SR5s-djsFjniP( z?n#6m!k((2tgQQL_@{J{5+-jH2Im+0Q!kazKk%4_IB%xxCT2;7==Xz8)P{BpL0`7= zN!BOwsUbG@^#D+iUtd}05K5QwK={h->nr!VdQ~NV!2NG^ej>%NDuDo{jm;KJ!Z12! zKOi|Rt*ft#@SxSi++|{Rb?<||2HWj?U5#_7jq1R_r*zhDXQDqo{J>k=*^SgYRD&LS zTA8G)=w=f)O8LES>`j55jG<99ctb7RefGILPUMD7gN%t+@!=;BO;mJ#XQ`t_n>0J> znK%bgbPma@LB@!a`O@Cn=RiN#_=-2F_rQx&zn#PkWW=S_Gah%V$_D2c(Cf{xtGC1T zEBe3uE3Clkx*ZlrtcG>opKH72H`)zHw#>pXT0>tqKKR=ZieW;#gSD^T3qSV*$jB(r zk;{08i^!7w<7B+h4fv0C){MQoW&qJ==(SSo+E7-0Y z?sLwcW8-Dit)}#z*D-oqU`;;L$+0Upo`j%70I{*kM-BCix}VV8XQ8KdwX%SBy!_g+t4+hqzKCjPoHq&YhR?H#d(zEywoEI z(tSI)NfEga7M-_1g$5c)ViXUI?&Uo@kY>2HcnXyi=)gxWN1QBgt}^ z62z`3%55WP2jRHT@5Ej(u;(Y97Be@EZHafO&j3e7>BG!8^jn1ymBTmN5$S6}Zsm^U zPb_mEyDX~qEp8Zx?!lK+9!kbas6Bb2RJu$ZCmFw!i3sSAH2+CMiW`;jwb|-GI{T*k zzaMvNdmAx*@N+o-6XhaqoSgZ`e%zy_rPXFO zLv)}goPghb_yMwac13H1YbUVy?33bG=sLPBI2bF+7V}BV zfyW#bfJ^y&RHHvN|Gc-ZLuJlU{@b-^N$@P3!}AKYGICSpb!1p5cbJs~(>5QQS%B_; z%Eanmyrw)VUq(-9tsJ;P{=oZlEhri~GudBE-2R47lfxuiYrE8*bPd`SpN+w?hg;Xt z?P=kd_cu`S2^%#K;T9)<+&sTi`Knj^T2IvdEY5W<*H^ptq8wY8o&313-|`{YLk`?} z9h==Y^4?~T{2IPfX}w!=PItuwUfUb`_+Ht3)$t>Yud#_60%DKYa^|1<5$L@MlmI%H z+oNV%%Dq4Gx>q_bF|GM^NHO~GdB3<$-gVg8iNQ>~NxCcMtO!F3D!B1dP;RIuis6#T z0D@4#634DyQZmtG{%U5V_35BscKoQ^_IT;~Q4Sk>m*~nt_Yzr=tFfS&dZ>p3fxPBR zRFj|L+5q_ie6ug9;e@4OaXpYDv;4`>@< zc%Sy8z;blIZZhCYTlt+lgD(tC{o>%c2{)(in$kXE&Ck1|_>3SR&&tZ`l5ou0J!Tm$7ZzhnG1VolBQlS_IPAUw2?+%FYbXnv7VE7wr--HZfYIR z^`?cg%3ya1M+1CGAghJD`MS2V>?=N9hpY0X^zj}F`?AhW-cE`({cbWer;zF>phcO( zpm?OfB;~<3?nM%rA9Eo5&#ddQ*-!eF0^A$UF5?wF3~$;J1%tb3om#gUr{bDvY+ZgF z18T!7gRg(Ch36N{UsW;&w0&RLn=52`@Np?xA-F!QU$_`?NO}~ft&q0 zQL2K1`Yi*i7*}5_7qIMNqT&YTdhGbgRlK)@T;_q1tYNWCZ=DY)x2ysHjv{Uhbb;o%i@85{0BS&JZ4ew-Jv6A$-IflIndt zccscU)52Fr=V-e(D!H7_&dYq9=B0e>PwlU70%C>*QYkuwWVZ1BrdZ4mK6zrR(`MM+ zwM^4alfAvUq_b9SGo%wwNUr^#9IMW)6JN)%tY||~%~j_znDJ7sBtAxtxvK{DUtN7u zQu#vY<%=@$)ZDa+g5}iENvtNLVBfB5hw!gfyICk?4h1iwG*yynclddf-KO}oUmy3o*7FK7U2|&QTOVb{07L(ff zwQnBb47O)%Z|)UMnU%3K{2n+yip5yFzE8XR^r(E&s7cgf?Gvi|OqN)%Hgy>5q7YjJ zB7Ir4c9Xq7sliXP$|CegxBk4Z>bAb0KJ>A7bV=vo`obdx{}5i4kKoo<{7FY&?3tDq z)->&Fki{kw$e-#!%QJX#^!4M%x7w6p8IR)iaY3GhV~z&mzzu=$^Zg+2Oh&x}BOLAT z!-?>_kB5xgxeez-#R-^x-p(PMirm1%)SbyM^arPLU#e@I@fH1Pvuz&hKb`q&*8`1! zP3oAoq(4`2^<@&#oV7Wh$d>v0qi>t#vcZe8UVm?{%6Zdz4_d3Yhv|EzTtY~zgymC$ zFMIWhhxR7Q(w7e&%=?*NP`b;BasgIbly>Rr=*>5~;+d(lMi##m?|rvXp9Zu7Pzz=< znc`4EULFoTvzzF4ZS>O--cao z=N!IG?(dBGMagmfnDA&y6W&3|KMZa`a_4&zrF5pAv)cFX?C{NKRi4G9ihsM`5uEhi zOECOPfbf1PK|I;hoK#|Qb3=pVe|_4MCr>JC9S!(J!gVsRl=HNhc#XqvsOM%$162*Q zw!Sx|{S%Ed`2>6x_9gjl-}EibPE!%4)hD?40!~+c)XstM>0SjF+Xb+A`*4P2?_3^0 zij+o}ao(IQb7b+)`?ugQ9hyv<{$#sHmQ!~(*Hxr7&EZc~8W<$Q&&G%sLQD>3W~QnR zuch@eLhFz>xtNM)>^KgnvZb+l3g`eSdnOE+kGDwb@4Pc?!j$R!_$o-#BE8aPMiK~` zNLmjKLMEhF=>A=50Mp{91NjQ{=McNaqhxj}HgRhxx$xx)FM)XVi`ZQ@u4g4hb(KD1 z?Ma0w(zdqVf#Omy#sqa)@2<>3A|yJWT~fhHF+vx-rFc$uxZrydy=>NYrn*6FqNaK_ zGM9TK;hTVB_d@ja_l;^=V&Bv){Lmmnt_CX9A9F}Rw8sLHU?Y0U`4ENo$`o%Qh_!4Hi=Bz3tJ%_j2W!UIT6e*PpRlq*goI>mx{1?hFiBngwB7h zo8C-^C4Y4zUvrCSsh8D`-7(T(pJemV4_xA(n!c&Z)&f}#jm1;Y5_dDU`3=s!yuJ?( z%D#ESl?w9t^5}6gQj8Pt5q%*oUx`$gR!4uoN<%|-U-|4&@ATL4)F}IL6Cv8|=f=K` zO{%||)9psPyXm0UkSc8TJ>JPeI}m@ul?((8gM#@R_cFm*a+%d{5O+o_qODY?sJ>i{AxXBSYPF{ zBlo%d@sH9BLut%Vm5+)cP&Uln&9!|+%H)XB@G!fPt)~fg6})pT?zA!ZQ<9c}(iSgE zX$@tV(dgs|tK(~0TdSWu+TZUL=Z?aMFe@w~@>uu@CQ)_uXinH6OK5!V0G?Pu$qdgJ z3{=k_z1}GP%+7zCJg?Cd&ct+vCPJNj%OlbBmIljKQ8aOK6ywGp4{Zxoxp8 zm^IzMPK2f57{OmWL`GD8Gu%k+hp_)p5&pSNz?%C56+b;PDWW-znO`WS_Ux6 zXCI}vc`5ES*C=S~Y}gcu`aK1oKhtDh_d83Kj0tNT;5l`KyG&38mYIa@wWxz;af1%TvFcZlb7ptN24x> zN~f6(TJTQ=PtRWUIJal`7+QkG{~1T^7}TBh!jkke2NE$di%#41IJh*|wNyyB`dDx# z=ymevI(C2O8I&Oi2oAHn9dL&dDhnzW1%#S;Uver7wKwCm3g~XtbPfziB~S zMNUF()1kBVo%P2=Pur!yMKW@Zs(Tf(&kiaA(MpJLsO755r-o$C7f_Fp^Q@W*X&YAl zv)kkb{c18#C}b#FV0vEFCp_FO9=nLDj|?G5uyQ06J3b!mkeT!Li3DmROKW!xub z3W>q()w^TK2s{e`nOoft9pLxKuZx= zN5FX7sBVy^nYg)GgIg z|7=lggvMFLn-MNZWwF?hn8dc-kGh7PNYJ!%nugweX{L)PpeR#Nzt^LhY9aNrQ<2v2 z6}SR*!HnK=ZT+#~3F^PB=j0Ak{pWlC(f%pw{++adY7a%X%^98OAcs!A?AK}s8-Ea| z<>LDK*BZr{e`_k4C4_-;~GsY&B&+ zWVB^>QDKa^v?_WbdOz+NQ3-W67~YOyp*mpEi-q?2*+5e{(eq>pw8&_6;!XVp$WV+! z(Z;qf&1Xx!`RXpA%0On2_e>S?6;L;~FK%srJk0L5nX8Bx8y=KDO$c)tqWbTWtmp;t zUMn|BO3IkXLk;0v>Pl zTS{H|2iz`5GC@CX@k{C|)E<>FDnl}B>dit8d+}ex360;se?Qh{m;cot+ce5MMLh8mDWe3Ef)ksW#&D#b@##korMATh8nMbYoz@ z?%I22NS+$a;E~A-K_=x#c2L#89%6&so(Hwg%1VR(+Q{0c5}#hN`1tof3bn&{bSA+8 zQmawZMcRh%N;EX^`3vpno|5Te_-`bQ11)9GvqLVw!`iev5=eFFx(_m z>>V^F;bM91(T|twhch#kNe-Q46S(@2)U4c%{lQYfxQkgKm(M;dUK02$eeDO_@n_43C*0|+Y8)dj9B;iGF1ZN6|#=RXGxhY%4EhAmU zg?T}&6_oF|9W}hWE=3$Vk)ns?vK;=c^X(c&D^F48*qwnW`Gw9p!$c8U%wk^&{_098Wx;O`|D@V$bp&2vhE>+sm zydNb1q3y$1kkJQXU6P=d_Q%_3vANm zaA_10g^9z^p?GVwOC1~p}WhMqM z4NwrqiGl6)gwk?yRyx10sy%hkTXfq-7!#CbQo5~_~jNelJRKkNSLr{c?!1Xhm| zI-p4McJ$jLVq)>=m>7IIiEGOLjfbYcsa)XhL)x~pi z!*Xv6YwVH!7@mqpqt%*WX$`0-@aE!ZW-2=h%KW^4+3Waf8!0Bv>*70P67!VXF+% z`D_n~iTO1^M#*5yZ|VTh?HBR3w=x@=kkDy`h6fPRiNt`zUoZg-Pomz!1em$~TqVWC z6Xu*|WO{lC0*i3f#seQPzZ_+PK5b#Lk9qv^@50VyNmQDHeb%(HWI7W>I#+pFK2$_r61eLEinO-}Ot%OJhif1v>f2*hZE zI+c;He_FF0G?xepU%P%x6eN7|AOaqZ{$Ny(r9$)f7uBYWeO2K{Tsb+c@TI5f7whAs z!QhjuDHvO1hgxK0hDK7kiL}*kOcs`>4}dSJ{5@b+F#2eodr;AP1uLC4TmvBM{|u`Q zOXTHFskDo9B4b-(x3{TG-bc$wOQS)?-!em+tbexpk%l&9LZQ;GX{VMp83i-Xi5S7C^;%v{u3X0azyASWxhfn0 delta 8231 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

Vn&S zOxo6-I~?=5RU7lG^KU^h+D4w^ZAM`TAiq}fQPU>1WIv~BWG5-iQhfd{Ymrj*{-<#M zAw5JvP*xrt?eelR)?Y6%5za2f3aNlReffi&Y8MBG-ZS@}e0>{I2B^U+l;7M30QZ2W zijVb$onGqL_HIj)K)^Lzv41b_ZW|gSzdqEok>%myYAGL(B?KC-mN)EPScn}g zz{Z|kxfUAEy1emFh8odM%AFa(>DQ@f&R9h_%*LCV)J@1Z*~n3rM@Z;t!nlo)m{71u z1xH)aDEL(a{y6v|=$pgK%$ghwzckrO9JhsBZSfxiCg~ zaKf{~78bL6ySjdb6h@IkT3K%KQ&%#A)Yvc@WMr>2ny^dO%l(1e5QOYFA2gYOiMv## zQAB>!6Rixy)|<&1ExMxOVwf8*Ew;p>v`+yBgAqf9j|#L=Y3XU$sLbGKdnTuLF#%s; zNAx2*c@St>U=@lQV`LWLB8o znsRY*Y3YLf_~%gtjXiB~b#rSU!KmN>9y>GPwc=M%+Oy{yUpKKgj~)d3+3W39Z>a7 z?Oh8$2D9A&Y7+c_soE5_D9G}g=v%dWJ>7s0400BU<=SNUWEzgc{gO3IuH_+{s;s=c zt+G3Au*7Vto*x%-)d={_n%+A~dEfv~dBcK1MR-BR)Y7*~2ej;FDnLuC$&XU{+Wr-XbcyuMcH9CkH#pS#!OcwP%6k7T zK9HYp{~O$;*#6mx2TWd^XF#T1<^HiKYA7NikLCY4x<_!!d~~#UIAo~G^C#ggJuXzy zrU20tFquq#v$~+JE>cxh^;?j0fDC(#N0_0u0_fe1?#lC_DT4#@kOv4w+neRh=hSzT z0043yAuCu8@^s1#qas!x<-{rD!g;^H&CcQCQ+)Z?+Z3|;*68WmwhRpocb(So$;ruU z>%}oC7&I`56rVHrvLx| diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/outlined_button/handling_clicks2.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/outlined_button/handling_clicks2.png index c52021676a900477ade9239ff4d0400eb5a05962..9c87225b9f8961f9937b87ee142336cc49593e24 100644 GIT binary patch literal 16729 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 literal 16732 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 diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/outlined_button/handling_clicks3.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/outlined_button/handling_clicks3.png index 5585d2a34d53948b657f5e615fecc0db626b9205..b4777602a5462be8084a5404c2fa70fd8c8e9f44 100644 GIT binary patch delta 8402 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 Date: Sun, 15 Mar 2026 16:19:12 -0700 Subject: [PATCH 62/96] Restructure page examples and add pyproject files Move several page examples into per-example directories (rename *.py to */main.py), wrap UI content in SafeArea/Column, and replace direct ft.run calls with guarded if __name__ == "__main__": ft.run(...) entrypoints. Add pyproject.toml metadata for each example (app_exit_confirm_dialog, device_locale, device_orientation, keyboard_events, semantics_debugger, set_platform, splash_test, window_hidden_on_start, window_resize) to register them in the Flet gallery. Update documentation references to point to the new example paths. --- .../main.py} | 15 ++++++- .../app_exit_confirm_dialog/pyproject.toml | 27 ++++++++++++ .../main.py} | 20 ++++++--- .../page/device_locale/pyproject.toml | 26 ++++++++++++ .../main.py} | 42 +++++++++++-------- .../page/device_orientation/pyproject.toml | 26 ++++++++++++ .../main.py} | 36 +++++++++------- .../page/keyboard_events/pyproject.toml | 26 ++++++++++++ .../main.py} | 23 ++++++---- .../page/semantics_debugger/pyproject.toml | 26 ++++++++++++ .../{set_platform.py => set_platform/main.py} | 15 +++++-- .../controls/page/set_platform/pyproject.toml | 26 ++++++++++++ .../{splash_test.py => splash_test/main.py} | 17 ++++++-- .../controls/page/splash_test/pyproject.toml | 26 ++++++++++++ .../main.py} | 13 +++++- .../window_hidden_on_start/pyproject.toml | 27 ++++++++++++ .../main.py} | 13 +++++- .../page/window_resize/pyproject.toml | 27 ++++++++++++ .../flet/docs/cookbook/accessibility.md | 2 +- .../flet/docs/cookbook/keyboard-shortcuts.md | 2 +- 20 files changed, 374 insertions(+), 61 deletions(-) rename sdk/python/examples/controls/page/{app_exit_confirm_dialog.py => app_exit_confirm_dialog/main.py} (73%) create mode 100644 sdk/python/examples/controls/page/app_exit_confirm_dialog/pyproject.toml rename sdk/python/examples/controls/page/{device_locale.py => device_locale/main.py} (54%) create mode 100644 sdk/python/examples/controls/page/device_locale/pyproject.toml rename sdk/python/examples/controls/page/{device_orientation.py => device_orientation/main.py} (52%) create mode 100644 sdk/python/examples/controls/page/device_orientation/pyproject.toml rename sdk/python/examples/controls/page/{keyboard_events.py => keyboard_events/main.py} (50%) create mode 100644 sdk/python/examples/controls/page/keyboard_events/pyproject.toml rename sdk/python/examples/controls/page/{semantics_debugger.py => semantics_debugger/main.py} (52%) create mode 100644 sdk/python/examples/controls/page/semantics_debugger/pyproject.toml rename sdk/python/examples/controls/page/{set_platform.py => set_platform/main.py} (54%) create mode 100644 sdk/python/examples/controls/page/set_platform/pyproject.toml rename sdk/python/examples/controls/page/{splash_test.py => splash_test/main.py} (67%) create mode 100644 sdk/python/examples/controls/page/splash_test/pyproject.toml rename sdk/python/examples/controls/page/{window_hidden_on_start.py => window_hidden_on_start/main.py} (69%) create mode 100644 sdk/python/examples/controls/page/window_hidden_on_start/pyproject.toml rename sdk/python/examples/controls/page/{window_resize.py => window_resize/main.py} (55%) create mode 100644 sdk/python/examples/controls/page/window_resize/pyproject.toml diff --git a/sdk/python/examples/controls/page/app_exit_confirm_dialog.py b/sdk/python/examples/controls/page/app_exit_confirm_dialog/main.py similarity index 73% rename from sdk/python/examples/controls/page/app_exit_confirm_dialog.py rename to sdk/python/examples/controls/page/app_exit_confirm_dialog/main.py index 7511ba0095..8e26e87e58 100644 --- a/sdk/python/examples/controls/page/app_exit_confirm_dialog.py +++ b/sdk/python/examples/controls/page/app_exit_confirm_dialog/main.py @@ -28,7 +28,18 @@ def handle_no_click(e: ft.Event[ft.OutlinedButton]): actions_alignment=ft.MainAxisAlignment.END, ) - page.add(ft.Text('Try exiting this app by clicking window\'s "Close" button!')) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + 'Try exiting this app by clicking window\'s "Close" button!' + ) + ] + ) + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page/app_exit_confirm_dialog/pyproject.toml b/sdk/python/examples/controls/page/app_exit_confirm_dialog/pyproject.toml new file mode 100644 index 0000000000..ac7c8d0668 --- /dev/null +++ b/sdk/python/examples/controls/page/app_exit_confirm_dialog/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "page-app-exit-confirm-dialog" +version = "1.0.0" +description = "Demonstrates handling window close events with a custom confirm dialog." +requires-python = ">=3.10" +keywords = ["page", "window", "close", "confirm dialog", "window event", "desktop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "App exit confirm dialog" +controls = ["SafeArea", "Text", "AlertDialog", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["window close interception", "confirm dialog"] + +[tool.flet] +platforms = ["macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page/device_locale.py b/sdk/python/examples/controls/page/device_locale/main.py similarity index 54% rename from sdk/python/examples/controls/page/device_locale.py rename to sdk/python/examples/controls/page/device_locale/main.py index e240c53f18..28888ec8cf 100644 --- a/sdk/python/examples/controls/page/device_locale.py +++ b/sdk/python/examples/controls/page/device_locale/main.py @@ -15,12 +15,20 @@ def handle_locale_change(e: ft.LocaleChangeEvent): initial_locales = (await page.get_device_info()).locales page.add( - ft.Text(f"Initial locales: {format_locales(initial_locales)}"), - ft.Text( - "Change your system or browser language to trigger on_locale_change.", - color=ft.Colors.BLUE, - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text(f"Initial locales: {format_locales(initial_locales)}"), + ft.Text( + "Change your system or browser language to trigger " + "on_locale_change.", + color=ft.Colors.BLUE, + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page/device_locale/pyproject.toml b/sdk/python/examples/controls/page/device_locale/pyproject.toml new file mode 100644 index 0000000000..7789fa6f35 --- /dev/null +++ b/sdk/python/examples/controls/page/device_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-device-locale" +version = "1.0.0" +description = "Demonstrates locale-change handling and initial locale reporting in a Page." +requires-python = ">=3.10" +keywords = ["page", "locale", "locales", "on_locale_change", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Device locale" +controls = ["SafeArea", "Column", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["locale change handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page/device_orientation.py b/sdk/python/examples/controls/page/device_orientation/main.py similarity index 52% rename from sdk/python/examples/controls/page/device_orientation.py rename to sdk/python/examples/controls/page/device_orientation/main.py index 639e530f1b..a9e781fb71 100644 --- a/sdk/python/examples/controls/page/device_orientation.py +++ b/sdk/python/examples/controls/page/device_orientation/main.py @@ -37,23 +37,31 @@ async def on_checkbox_change(e: ft.Event[ft.Checkbox]) -> None: } page.add( - ft.Text( - spans=[ - # shown only on mobile platforms - ft.TextSpan( - "Select the orientations that should remain enabled for the app. " - "If no orientation is selected, the system defaults will be used.", - visible=page.platform.is_mobile(), - ), - # shown only on non-mobile platforms - ft.TextSpan( - "Please open this example on a mobile device instead.", - visible=not page.platform.is_mobile(), - style=ft.TextStyle(weight=ft.FontWeight.BOLD), - ), - ], - ), - ft.Column(controls=list(checkboxes.values())), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + spans=[ + # shown only on mobile platforms + ft.TextSpan( + "Select the orientations that should remain enabled " + "for the app. " + "If no orientation is selected, " + "the system defaults will be used.", + visible=page.platform.is_mobile(), + ), + # shown only on non-mobile platforms + ft.TextSpan( + "Please open this example on a mobile device instead.", + visible=not page.platform.is_mobile(), + style=ft.TextStyle(weight=ft.FontWeight.BOLD), + ), + ], + ), + ft.Column(controls=list(checkboxes.values())), + ] + ) + ) ) diff --git a/sdk/python/examples/controls/page/device_orientation/pyproject.toml b/sdk/python/examples/controls/page/device_orientation/pyproject.toml new file mode 100644 index 0000000000..69ba50e83b --- /dev/null +++ b/sdk/python/examples/controls/page/device_orientation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-device-orientation" +version = "1.0.0" +description = "Shows how to handle device orientation and lock allowed orientations at runtime." +requires-python = ">=3.10" +keywords = ["page", "orientation", "media", "checkbox", "mobile"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Device orientation" +controls = ["SafeArea", "AppBar", "Text", "Column", "Checkbox", "Page"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["media change handling", "orientation locking"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page/keyboard_events.py b/sdk/python/examples/controls/page/keyboard_events/main.py similarity index 50% rename from sdk/python/examples/controls/page/keyboard_events.py rename to sdk/python/examples/controls/page/keyboard_events/main.py index 91b931ad39..f1a745ef6f 100644 --- a/sdk/python/examples/controls/page/keyboard_events.py +++ b/sdk/python/examples/controls/page/keyboard_events/main.py @@ -29,20 +29,28 @@ def on_keyboard(e: ft.KeyboardEvent): page.on_keyboard_event = on_keyboard page.add( - ft.Text( - "Press any key with a combination of CTRL, ALT, SHIFT and META keys..." - ), - ft.Row( - controls=[ - key := ButtonControl(""), - shift := ButtonControl("Shift"), - ctrl := ButtonControl("Control"), - alt := ButtonControl("Alt"), - meta := ButtonControl("Meta"), - ], - alignment=ft.MainAxisAlignment.CENTER, - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Press any key with a combination of CTRL, ALT, SHIFT " + "and META keys..." + ), + ft.Row( + controls=[ + key := ButtonControl(""), + shift := ButtonControl("Shift"), + ctrl := ButtonControl("Control"), + alt := ButtonControl("Alt"), + meta := ButtonControl("Meta"), + ], + alignment=ft.MainAxisAlignment.CENTER, + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page/keyboard_events/pyproject.toml b/sdk/python/examples/controls/page/keyboard_events/pyproject.toml new file mode 100644 index 0000000000..45ef142d2e --- /dev/null +++ b/sdk/python/examples/controls/page/keyboard_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-keyboard-events" +version = "1.0.0" +description = "Demonstrates live updates from page keyboard events and modifier keys." +requires-python = ">=3.10" +keywords = ["page", "keyboard", "keyboard event", "shortcut", "modifier keys"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Keyboard events" +controls = ["SafeArea", "Column", "Row", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["keyboard input handling", "modifier keys display"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page/semantics_debugger.py b/sdk/python/examples/controls/page/semantics_debugger/main.py similarity index 52% rename from sdk/python/examples/controls/page/semantics_debugger.py rename to sdk/python/examples/controls/page/semantics_debugger/main.py index 91b8b8d07b..58abf08baf 100644 --- a/sdk/python/examples/controls/page/semantics_debugger.py +++ b/sdk/python/examples/controls/page/semantics_debugger/main.py @@ -17,14 +17,21 @@ def button_click(e: ft.Event[ft.Button]): page.update() page.add( - counter := ft.Text("0", size=40), - ft.Text("Press Shift+S to toggle semantics debugger"), - ft.Button( - content="Increment number", - icon=ft.Icons.ADD, - on_click=button_click, - ), + ft.SafeArea( + content=ft.Column( + controls=[ + counter := ft.Text("0", size=40), + ft.Text("Press Shift+S to toggle semantics debugger"), + ft.Button( + content="Increment number", + icon=ft.Icons.ADD, + on_click=button_click, + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page/semantics_debugger/pyproject.toml b/sdk/python/examples/controls/page/semantics_debugger/pyproject.toml new file mode 100644 index 0000000000..bf5916d300 --- /dev/null +++ b/sdk/python/examples/controls/page/semantics_debugger/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-semantics-debugger" +version = "1.0.0" +description = "Demonstrates toggling the semantics debugger using a keyboard shortcut." +requires-python = ">=3.10" +keywords = ["page", "semantics", "accessibility", "keyboard shortcut", "debugger"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Semantics debugger" +controls = ["SafeArea", "Column", "Text", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["semantics debugger toggle", "keyboard interaction"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page/set_platform.py b/sdk/python/examples/controls/page/set_platform/main.py similarity index 54% rename from sdk/python/examples/controls/page/set_platform.py rename to sdk/python/examples/controls/page/set_platform/main.py index 076ab89fff..9cea0a76d3 100644 --- a/sdk/python/examples/controls/page/set_platform.py +++ b/sdk/python/examples/controls/page/set_platform/main.py @@ -13,12 +13,19 @@ def set_ios(e: ft.Event[ft.Button]): print("New platform:", page.platform) page.add( - ft.Switch(label="Switch A", adaptive=True), - ft.Button("Set Android", on_click=set_android), - ft.Button("Set iOS", on_click=set_ios), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Switch(label="Switch A", adaptive=True), + ft.Button("Set Android", on_click=set_android), + ft.Button("Set iOS", on_click=set_ios), + ] + ) + ) ) print("Default platform:", page.platform) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page/set_platform/pyproject.toml b/sdk/python/examples/controls/page/set_platform/pyproject.toml new file mode 100644 index 0000000000..15b5f71989 --- /dev/null +++ b/sdk/python/examples/controls/page/set_platform/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-set-platform" +version = "1.0.0" +description = "Demonstrates switching page platform at runtime between iOS and Android." +requires-python = ">=3.10" +keywords = ["page", "platform", "ios", "android", "switch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Set platform" +controls = ["SafeArea", "Column", "Switch", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["runtime platform switching", "page platform update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page/splash_test.py b/sdk/python/examples/controls/page/splash_test/main.py similarity index 67% rename from sdk/python/examples/controls/page/splash_test.py rename to sdk/python/examples/controls/page/splash_test/main.py index 7f09dbc93c..d00d4bac14 100644 --- a/sdk/python/examples/controls/page/splash_test.py +++ b/sdk/python/examples/controls/page/splash_test/main.py @@ -17,7 +17,16 @@ async def handle_button_click(e: ft.Event[ft.Button]): page.update() btn = ft.Button("Do some lengthy task!", on_click=handle_button_click) - page.add(btn) - - -ft.run(main) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + btn, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page/splash_test/pyproject.toml b/sdk/python/examples/controls/page/splash_test/pyproject.toml new file mode 100644 index 0000000000..7be0cee220 --- /dev/null +++ b/sdk/python/examples/controls/page/splash_test/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-splash-test" +version = "1.0.0" +description = "Shows overlay progress-bar feedback while an async task runs." +requires-python = ">=3.10" +keywords = ["page", "overlay", "async", "progress", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Splash test" +controls = ["SafeArea", "Column", "Button", "ProgressBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["async task execution", "page overlay usage"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page/window_hidden_on_start.py b/sdk/python/examples/controls/page/window_hidden_on_start/main.py similarity index 69% rename from sdk/python/examples/controls/page/window_hidden_on_start.py rename to sdk/python/examples/controls/page/window_hidden_on_start/main.py index 1750371282..c4a0c98dff 100644 --- a/sdk/python/examples/controls/page/window_hidden_on_start.py +++ b/sdk/python/examples/controls/page/window_hidden_on_start/main.py @@ -11,7 +11,15 @@ async def main(page: ft.Page): print("Window is hidden on start. Will show after 3 seconds...") - page.add(ft.Text("Hello!")) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Hello!"), + ] + ) + ) + ) # some configuration that we want to do before showing the window page.window.width = 300 @@ -27,4 +35,5 @@ async def main(page: ft.Page): page.update() -ft.run(main, view=ft.AppView.FLET_APP_HIDDEN) +if __name__ == "__main__": + ft.run(main, view=ft.AppView.FLET_APP_HIDDEN) diff --git a/sdk/python/examples/controls/page/window_hidden_on_start/pyproject.toml b/sdk/python/examples/controls/page/window_hidden_on_start/pyproject.toml new file mode 100644 index 0000000000..7b1135659e --- /dev/null +++ b/sdk/python/examples/controls/page/window_hidden_on_start/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "page-window-hidden-on-start" +version = "1.0.0" +description = "Demonstrates initializing window settings before showing a hidden app window." +requires-python = ">=3.10" +keywords = ["page", "window", "hidden", "startup", "overlay", "desktop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Window hidden on start" +controls = ["SafeArea", "Column", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["hidden startup", "window configuration"] + +[tool.flet] +platforms = ["macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page/window_resize.py b/sdk/python/examples/controls/page/window_resize/main.py similarity index 55% rename from sdk/python/examples/controls/page/window_resize.py rename to sdk/python/examples/controls/page/window_resize/main.py index d54f7ba3d2..9a372bba20 100644 --- a/sdk/python/examples/controls/page/window_resize.py +++ b/sdk/python/examples/controls/page/window_resize/main.py @@ -3,7 +3,15 @@ def main(page: ft.Page): if page.window.width is None or page.window.height is None: - page.add(ft.Text("Window size can be changed only in desktop apps.")) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Window size can be changed only in desktop apps."), + ] + ) + ) + ) return width = 400 @@ -16,4 +24,5 @@ def main(page: ft.Page): page.window.update() -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page/window_resize/pyproject.toml b/sdk/python/examples/controls/page/window_resize/pyproject.toml new file mode 100644 index 0000000000..1d2efd0311 --- /dev/null +++ b/sdk/python/examples/controls/page/window_resize/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "page-window-resize" +version = "1.0.0" +description = "Demonstrates resizing the app window programmatically in desktop contexts." +requires-python = ">=3.10" +keywords = ["page", "window", "resize", "desktop", "window metrics"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Window resize" +controls = ["SafeArea", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["window geometry", "desktop platform behavior"] + +[tool.flet] +platforms = ["macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/cookbook/accessibility.md b/sdk/python/packages/flet/docs/cookbook/accessibility.md index 3d0358b150..5eac6634f6 100644 --- a/sdk/python/packages/flet/docs/cookbook/accessibility.md +++ b/sdk/python/packages/flet/docs/cookbook/accessibility.md @@ -55,5 +55,5 @@ semantics debugger during app development: {{ image("../assets/cookbook/accessibility/debug-accessibility-toggle.gif", width="80%") }} ```python ---8<-- "../../examples/controls/page/semantics_debugger.py" +--8<-- "../../examples/controls/page/semantics_debugger/main.py" ``` diff --git a/sdk/python/packages/flet/docs/cookbook/keyboard-shortcuts.md b/sdk/python/packages/flet/docs/cookbook/keyboard-shortcuts.md index 2ea35413ee..dc9c635c20 100644 --- a/sdk/python/packages/flet/docs/cookbook/keyboard-shortcuts.md +++ b/sdk/python/packages/flet/docs/cookbook/keyboard-shortcuts.md @@ -37,5 +37,5 @@ ft.run(main) Below is a more advanced example: ```python ---8<-- "../../examples/controls/page/keyboard_events.py" +--8<-- "../../examples/controls/page/keyboard_events/main.py" ``` From b9924020f6de25f2003285e2dd9dec305cfd620c Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 15 Mar 2026 18:50:55 -0700 Subject: [PATCH 63/96] Restructure page_view & pagelet examples Convert PageView and Pagelet examples into standalone example projects (add main.py and pyproject.toml), wrap example UIs with SafeArea, and include async metadata where applicable. Removed old flat example modules, renamed basic_declarative to a main entrypoint, and added pyproject metadata (keywords, gallery/metadata) for each example. Updated docs to point to new example paths and adjusted integration test import to use the new main callable. --- .../create-flet-example-projects/SKILL.md | 1 + .../examples/controls/page_view/basic.py | 56 ------------ .../examples/controls/page_view/basic/main.py | 59 +++++++++++++ .../controls/page_view/basic/pyproject.toml | 26 ++++++ .../controls/page_view/programmatic_swipe.py | 69 --------------- .../page_view/programmatic_swipe/main.py | 78 +++++++++++++++++ .../programmatic_swipe/pyproject.toml | 40 +++++++++ .../examples/controls/pagelet/__init__.py | 0 sdk/python/examples/controls/pagelet/basic.py | 79 ----------------- .../examples/controls/pagelet/basic/main.py | 87 +++++++++++++++++++ .../controls/pagelet/basic/pyproject.toml | 45 ++++++++++ .../main.py} | 10 ++- .../pagelet/basic_declarative/pyproject.toml | 46 ++++++++++ .../packages/flet/docs/controls/pagelet.md | 2 +- .../packages/flet/docs/controls/pageview.md | 4 +- .../examples/core/test_pagelet.py | 4 +- 16 files changed, 395 insertions(+), 211 deletions(-) delete mode 100644 sdk/python/examples/controls/page_view/basic.py create mode 100644 sdk/python/examples/controls/page_view/basic/main.py create mode 100644 sdk/python/examples/controls/page_view/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/page_view/programmatic_swipe.py create mode 100644 sdk/python/examples/controls/page_view/programmatic_swipe/main.py create mode 100644 sdk/python/examples/controls/page_view/programmatic_swipe/pyproject.toml delete mode 100644 sdk/python/examples/controls/pagelet/__init__.py delete mode 100644 sdk/python/examples/controls/pagelet/basic.py create mode 100644 sdk/python/examples/controls/pagelet/basic/main.py create mode 100644 sdk/python/examples/controls/pagelet/basic/pyproject.toml rename sdk/python/examples/controls/pagelet/{basic_declarative.py => basic_declarative/main.py} (93%) create mode 100644 sdk/python/examples/controls/pagelet/basic_declarative/pyproject.toml diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 66c2836db1..9c1fc0bb5e 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -59,6 +59,7 @@ Ensure each runnable example is a standalone project containing: - Complexity: `basic` unless logic/state/architecture is non-trivial. - Features: notable behaviors only (click handling, selection, async loading, drag-and-drop, etc.). - If an example supports exporting or downloading output, include `"save to file"` in `[tool.flet.metadata].features`. +- If an example module contains `async def` handlers or async control flow, append `"async"` to `keywords`. 5. Infer dependencies from imports. diff --git a/sdk/python/examples/controls/page_view/basic.py b/sdk/python/examples/controls/page_view/basic.py deleted file mode 100644 index 7d6572646b..0000000000 --- a/sdk/python/examples/controls/page_view/basic.py +++ /dev/null @@ -1,56 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.padding = 0 - - page.add( - ft.PageView( - expand=True, - viewport_fraction=0.9, - on_change=lambda e: print(f"Currently viewing page {int(e.data)}"), - selected_index=1, - horizontal=True, - controls=[ - ft.Container( - bgcolor=ft.Colors.INDIGO_400, - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text("Welcome", size=40, weight=ft.FontWeight.BOLD), - ft.Text("Swipe to see what PageView can do."), - ], - ), - ), - ft.Container( - bgcolor=ft.Colors.PINK_300, - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Icon(ft.Icons.ANIMATION, size=72), - ft.Text( - "Viewport fraction lets you peek at the next slide." - ), - ], - ), - ), - ft.Container( - bgcolor=ft.Colors.TEAL_300, - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Icon(ft.Icons.TOUCH_APP, size=72), - ft.Text("Use on_change to respond to page swipes."), - ], - ), - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/page_view/basic/main.py b/sdk/python/examples/controls/page_view/basic/main.py new file mode 100644 index 0000000000..61e6198b10 --- /dev/null +++ b/sdk/python/examples/controls/page_view/basic/main.py @@ -0,0 +1,59 @@ +import flet as ft + + +def main(page: ft.Page): + page.padding = 0 + + page.add( + ft.SafeArea( + expand=True, + content=ft.PageView( + expand=True, + viewport_fraction=0.9, + on_change=lambda e: print(f"Currently viewing page {int(e.data)}"), + selected_index=1, + horizontal=True, + controls=[ + ft.Container( + bgcolor=ft.Colors.INDIGO_400, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Welcome", size=40, weight=ft.FontWeight.BOLD), + ft.Text("Swipe to see what PageView can do."), + ], + ), + ), + ft.Container( + bgcolor=ft.Colors.PINK_300, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Icon(ft.Icons.ANIMATION, size=72), + ft.Text( + "Viewport fraction lets you peek at the next slide." + ), + ], + ), + ), + ft.Container( + bgcolor=ft.Colors.TEAL_300, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Icon(ft.Icons.TOUCH_APP, size=72), + ft.Text("Use on_change to respond to page swipes."), + ], + ), + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page_view/basic/pyproject.toml b/sdk/python/examples/controls/page_view/basic/pyproject.toml new file mode 100644 index 0000000000..7ae5f8826a --- /dev/null +++ b/sdk/python/examples/controls/page_view/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-view-basic" +version = "1.0.0" +description = "Demonstrates a swipeable PageView with page-change callback and peeked viewport pages." +requires-python = ">=3.10" +keywords = ["page view", "pageview", "swipe", "carousel", "callback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/PageView"] + +[tool.flet.metadata] +title = "Basic" +controls = ["PageView", "SafeArea", "Container", "Column", "Text", "Icon"] +layout_pattern = "pager" +complexity = "basic" +features = ["horizontal swipe navigation", "page change callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/page_view/programmatic_swipe.py b/sdk/python/examples/controls/page_view/programmatic_swipe.py deleted file mode 100644 index aaa58f653b..0000000000 --- a/sdk/python/examples/controls/page_view/programmatic_swipe.py +++ /dev/null @@ -1,69 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.padding = 0 - - async def show_previous_page(e: ft.Event[ft.FloatingActionButton]): - await view.previous_page( - animation_curve=ft.AnimationCurve.BOUNCE_OUT, - animation_duration=ft.Duration(seconds=1), - ) - - async def show_next_page(e: ft.Event[ft.FloatingActionButton]): - await view.next_page( - animation_curve=ft.AnimationCurve.BOUNCE_OUT, - animation_duration=ft.Duration(seconds=1), - ) - - page.floating_action_button = ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - wrap=True, - controls=[ - ft.FloatingActionButton( - icon=ft.Icons.SWIPE_LEFT, - on_click=show_previous_page, - tooltip="Previous Page", - ), - ft.FloatingActionButton( - icon=ft.Icons.SWIPE_RIGHT, - on_click=show_next_page, - tooltip="Next Page", - ), - ], - ) - - page.add( - view := ft.PageView( - expand=True, - viewport_fraction=0.9, - selected_index=1, - horizontal=True, - controls=[ - ft.Container( - bgcolor=bgcolor, - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text(f"Page {idx}", size=55, weight=ft.FontWeight.BOLD), - ], - ), - ) - for idx, bgcolor in enumerate( - [ - ft.Colors.RED_800, - ft.Colors.BLUE_800, - ft.Colors.GREEN_800, - ft.Colors.ORANGE_800, - ft.Colors.PURPLE_800, - ft.Colors.PINK_800, - ] - ) - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/page_view/programmatic_swipe/main.py b/sdk/python/examples/controls/page_view/programmatic_swipe/main.py new file mode 100644 index 0000000000..8dca9fae2a --- /dev/null +++ b/sdk/python/examples/controls/page_view/programmatic_swipe/main.py @@ -0,0 +1,78 @@ +import flet as ft + + +def main(page: ft.Page): + page.padding = 0 + + async def show_previous_page(e: ft.Event[ft.FloatingActionButton]): + await view.previous_page( + animation_curve=ft.AnimationCurve.BOUNCE_OUT, + animation_duration=ft.Duration(seconds=1), + ) + + async def show_next_page(e: ft.Event[ft.FloatingActionButton]): + await view.next_page( + animation_curve=ft.AnimationCurve.BOUNCE_OUT, + animation_duration=ft.Duration(seconds=1), + ) + + page.floating_action_button = ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + wrap=True, + controls=[ + ft.FloatingActionButton( + icon=ft.Icons.SWIPE_LEFT, + on_click=show_previous_page, + tooltip="Previous Page", + ), + ft.FloatingActionButton( + icon=ft.Icons.SWIPE_RIGHT, + on_click=show_next_page, + tooltip="Next Page", + ), + ], + ) + + page.add( + ft.SafeArea( + expand=True, + content=( + view := ft.PageView( + expand=True, + viewport_fraction=0.9, + selected_index=1, + horizontal=True, + controls=[ + ft.Container( + bgcolor=bgcolor, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text( + f"Page {idx}", + size=55, + weight=ft.FontWeight.BOLD, + ), + ], + ), + ) + for idx, bgcolor in enumerate( + [ + ft.Colors.RED_800, + ft.Colors.BLUE_800, + ft.Colors.GREEN_800, + ft.Colors.ORANGE_800, + ft.Colors.PURPLE_800, + ft.Colors.PINK_800, + ] + ) + ], + ) + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/page_view/programmatic_swipe/pyproject.toml b/sdk/python/examples/controls/page_view/programmatic_swipe/pyproject.toml new file mode 100644 index 0000000000..83b969da04 --- /dev/null +++ b/sdk/python/examples/controls/page_view/programmatic_swipe/pyproject.toml @@ -0,0 +1,40 @@ +[project] +name = "page-view-programmatic-swipe" +version = "1.0.0" +description = "Demonstrates programmatic PageView navigation via previous/next actions." +requires-python = ">=3.10" +keywords = [ + "page view", + "pageview", + "programmatic swipe", + "floating action button", + "async", +] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/PageView"] + +[tool.flet.metadata] +title = "Programmatic Swipe" +controls = [ + "PageView", + "SafeArea", + "Container", + "Column", + "Text", + "Row", + "FloatingActionButton", +] +layout_pattern = "programmatic-controls" +complexity = "basic" +features = ["programmatic page navigation", "manual swipe control"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/pagelet/__init__.py b/sdk/python/examples/controls/pagelet/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/pagelet/basic.py b/sdk/python/examples/controls/pagelet/basic.py deleted file mode 100644 index 53784803cb..0000000000 --- a/sdk/python/examples/controls/pagelet/basic.py +++ /dev/null @@ -1,79 +0,0 @@ -import asyncio - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.MainAxisAlignment.CENTER - page.vertical_alignment = ft.CrossAxisAlignment.CENTER - - async def handle_show_drawer(e: ft.Event[ft.FloatingActionButton]): - await pagelet.show_drawer() - - async def handle_show_end_drawer(e: ft.Event[ft.Button]): - await pagelet.show_end_drawer() - await asyncio.sleep(3) - await pagelet.close_end_drawer() - - page.add( - pagelet := ft.Pagelet( - width=500, - height=500, - appbar=ft.AppBar( - title=ft.Text("Pagelet AppBar"), - center_title=True, - bgcolor=ft.Colors.RED_500, - ), - content=ft.Text("Pagelet Body"), - bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, - bottom_appbar=ft.BottomAppBar( - bgcolor=ft.Colors.BLUE, - shape=ft.CircularRectangleNotchShape(), - content=ft.Row( - controls=[ - ft.IconButton(icon=ft.Icons.MENU, icon_color=ft.Colors.WHITE), - ft.Container(expand=True), - ft.IconButton(icon=ft.Icons.SEARCH, icon_color=ft.Colors.WHITE), - ft.IconButton( - icon=ft.Icons.FAVORITE, icon_color=ft.Colors.WHITE - ), - ] - ), - ), - drawer=ft.NavigationDrawer( - on_dismiss=lambda e: print("Drawer dismissed"), - controls=[ - ft.NavigationDrawerDestination( - icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, - label="Item 1", - ), - ft.NavigationDrawerDestination( - icon=ft.Icons.ADD_COMMENT, - label="Item 2", - ), - ], - ), - end_drawer=ft.NavigationDrawer( - on_dismiss=lambda e: print("End Drawer dismissed"), - controls=[ - ft.NavigationDrawerDestination( - icon=ft.Icons.SLOW_MOTION_VIDEO, - label="Item 3", - ), - ft.NavigationDrawerDestination( - icon=ft.Icons.INSERT_CHART, - label="Item 4", - ), - ], - ), - floating_action_button=ft.FloatingActionButton( - icon=ft.Icons.ADD, - shape=ft.CircleBorder(), - ), - floating_action_button_location=ft.FloatingActionButtonLocation.CENTER_DOCKED, - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/pagelet/basic/main.py b/sdk/python/examples/controls/pagelet/basic/main.py new file mode 100644 index 0000000000..16aba792e2 --- /dev/null +++ b/sdk/python/examples/controls/pagelet/basic/main.py @@ -0,0 +1,87 @@ +import asyncio + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.MainAxisAlignment.CENTER + page.vertical_alignment = ft.CrossAxisAlignment.CENTER + + async def handle_show_drawer(e: ft.Event[ft.FloatingActionButton]): + await pagelet.show_drawer() + + async def handle_show_end_drawer(e: ft.Event[ft.Button]): + await pagelet.show_end_drawer() + await asyncio.sleep(3) + await pagelet.close_end_drawer() + + page.add( + ft.SafeArea( + content=( + pagelet := ft.Pagelet( + width=500, + height=500, + appbar=ft.AppBar( + title=ft.Text("Pagelet AppBar"), + center_title=True, + bgcolor=ft.Colors.RED_500, + ), + content=ft.Text("Pagelet Body"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + bottom_appbar=ft.BottomAppBar( + bgcolor=ft.Colors.BLUE, + shape=ft.CircularRectangleNotchShape(), + content=ft.Row( + controls=[ + ft.IconButton( + icon=ft.Icons.MENU, icon_color=ft.Colors.WHITE + ), + ft.Container(expand=True), + ft.IconButton( + icon=ft.Icons.SEARCH, icon_color=ft.Colors.WHITE + ), + ft.IconButton( + icon=ft.Icons.FAVORITE, icon_color=ft.Colors.WHITE + ), + ], + ), + ), + drawer=ft.NavigationDrawer( + on_dismiss=lambda e: print("Drawer dismissed"), + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_COMMENT, + label="Item 2", + ), + ], + ), + end_drawer=ft.NavigationDrawer( + on_dismiss=lambda e: print("End Drawer dismissed"), + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.SLOW_MOTION_VIDEO, + label="Item 3", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.INSERT_CHART, + label="Item 4", + ), + ], + ), + floating_action_button=ft.FloatingActionButton( + icon=ft.Icons.ADD, + shape=ft.CircleBorder(), + ), + floating_action_button_location=ft.FloatingActionButtonLocation.CENTER_DOCKED, + ) + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/pagelet/basic/pyproject.toml b/sdk/python/examples/controls/pagelet/basic/pyproject.toml new file mode 100644 index 0000000000..781caf594c --- /dev/null +++ b/sdk/python/examples/controls/pagelet/basic/pyproject.toml @@ -0,0 +1,45 @@ +[project] +name = "pagelet-basic" +version = "1.0.0" +description = "Shows a Pagelet configured with app bars, drawers, and a floating action button." +requires-python = ">=3.10" +keywords = [ + "pagelet", + "navigation drawer", + "app bar", + "floating action button", + "async", +] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Pagelet"] + +[tool.flet.metadata] +title = "Basic" +controls = [ + "Pagelet", + "SafeArea", + "AppBar", + "BottomAppBar", + "NavigationDrawer", + "NavigationDrawerDestination", + "FloatingActionButton", + "Text", + "IconButton", + "Row", + "Column", + "Container", +] +layout_pattern = "app-shell" +complexity = "basic" +features = ["drawer navigation", "floating action behavior", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/pagelet/basic_declarative.py b/sdk/python/examples/controls/pagelet/basic_declarative/main.py similarity index 93% rename from sdk/python/examples/controls/pagelet/basic_declarative.py rename to sdk/python/examples/controls/pagelet/basic_declarative/main.py index d144440c27..a1bb723132 100644 --- a/sdk/python/examples/controls/pagelet/basic_declarative.py +++ b/sdk/python/examples/controls/pagelet/basic_declarative/main.py @@ -69,7 +69,13 @@ async def handle_show_end_drawer(): ), floating_action_button_location=ft.FloatingActionButtonLocation.CENTER_DOCKED, ) - return p + return ft.SafeArea(content=p) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.title = "Pagelet example" + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/pagelet/basic_declarative/pyproject.toml b/sdk/python/examples/controls/pagelet/basic_declarative/pyproject.toml new file mode 100644 index 0000000000..4522c4dfbe --- /dev/null +++ b/sdk/python/examples/controls/pagelet/basic_declarative/pyproject.toml @@ -0,0 +1,46 @@ +[project] +name = "pagelet-basic-declarative" +version = "1.0.0" +description = "Demonstrates a declarative Pagelet with drawers and an app shell." +requires-python = ">=3.10" +keywords = [ + "pagelet", + "declarative", + "navigation drawer", + "component", + "material", + "async", +] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Pagelet"] + +[tool.flet.metadata] +title = "Basic Declarative" +controls = [ + "Pagelet", + "SafeArea", + "AppBar", + "BottomAppBar", + "NavigationDrawer", + "NavigationDrawerDestination", + "FloatingActionButton", + "Button", + "Text", + "Row", + "IconButton", + "Container", +] +layout_pattern = "app-shell" +complexity = "basic" +features = ["declarative UI composition", "drawer navigation", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/pagelet.md b/sdk/python/packages/flet/docs/controls/pagelet.md index a824569939..2b34f9eb5a 100644 --- a/sdk/python/packages/flet/docs/controls/pagelet.md +++ b/sdk/python/packages/flet/docs/controls/pagelet.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/core/golden/macos/pagelet ### Basic example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/pageview.md b/sdk/python/packages/flet/docs/controls/pageview.md index 0586b20e22..b9e3cc677e 100644 --- a/sdk/python/packages/flet/docs/controls/pageview.md +++ b/sdk/python/packages/flet/docs/controls/pageview.md @@ -10,13 +10,13 @@ examples: ../../examples/controls/page_view ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` ### Programmatic Swipes ```python ---8<-- "{{ examples }}/programmatic_swipe.py" +--8<-- "{{ examples }}/programmatic_swipe/main.py" ``` diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_pagelet.py b/sdk/python/packages/flet/integration_tests/examples/core/test_pagelet.py index 040c8b5f3c..bd8e3b5323 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_pagelet.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_pagelet.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.pagelet import basic +from examples.controls.pagelet.basic.main import main as basic @pytest.mark.asyncio(loop_scope="function") @@ -27,7 +27,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": basic.main}], + [{"flet_app_main": basic}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") From 586b5d953e6b8ba73e2a781a91f21694353e4eaf Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 16 Mar 2026 13:16:31 -0700 Subject: [PATCH 64/96] Reorganize Python examples and update docs/tests Move example entry points into dedicated main.py files and add per-example pyproject.toml metadata. Wrap example UIs in SafeArea, remove old top-level example modules and __init__.py placeholders, and add gallery/tooling metadata. Update control docs to reference the new example paths and adjust integration tests to import the new main callables, update screenshot handling, and add/adjust skips where needed. This standardizes example layout and provides metadata for the Flet gallery. --- .../examples/controls/placeholder/__init__.py | 0 .../examples/controls/placeholder/basic.py | 17 ------- .../controls/placeholder/basic/main.py | 20 ++++++++ .../controls/placeholder/basic/pyproject.toml | 26 ++++++++++ .../controls/popup_menu_button/__init__.py | 0 .../controls/popup_menu_button/basic.py | 36 ------------- .../controls/popup_menu_button/basic/main.py | 37 ++++++++++++++ .../popup_menu_button/basic/pyproject.toml | 26 ++++++++++ .../controls/progress_bar/__init__.py | 0 .../determinate_and_indeterminate.py | 32 ------------ .../determinate_and_indeterminate/main.py | 38 ++++++++++++++ .../pyproject.toml | 26 ++++++++++ .../controls/progress_ring/__init__.py | 0 .../determinate_and_indeterminate.py | 39 --------------- .../determinate_and_indeterminate/main.py | 50 +++++++++++++++++++ .../pyproject.toml | 26 ++++++++++ .../progress_ring/gauge_with_progress.py | 18 ------- .../progress_ring/gauge_with_progress/main.py | 20 ++++++++ .../gauge_with_progress/pyproject.toml | 26 ++++++++++ .../flet/docs/controls/placeholder.md | 2 +- .../flet/docs/controls/popupmenubutton.md | 2 +- .../flet/docs/controls/progressbar.md | 2 +- .../flet/docs/controls/progressring.md | 4 +- .../examples/core/test_placeholder.py | 27 ++++++---- .../material/test_popup_menu_button.py | 7 ++- .../examples/material/test_progress_bar.py | 7 +-- .../examples/material/test_progress_ring.py | 13 ++--- 27 files changed, 331 insertions(+), 170 deletions(-) delete mode 100644 sdk/python/examples/controls/placeholder/__init__.py delete mode 100644 sdk/python/examples/controls/placeholder/basic.py create mode 100644 sdk/python/examples/controls/placeholder/basic/main.py create mode 100644 sdk/python/examples/controls/placeholder/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/popup_menu_button/__init__.py delete mode 100644 sdk/python/examples/controls/popup_menu_button/basic.py create mode 100644 sdk/python/examples/controls/popup_menu_button/basic/main.py create mode 100644 sdk/python/examples/controls/popup_menu_button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/progress_bar/__init__.py delete mode 100644 sdk/python/examples/controls/progress_bar/determinate_and_indeterminate.py create mode 100644 sdk/python/examples/controls/progress_bar/determinate_and_indeterminate/main.py create mode 100644 sdk/python/examples/controls/progress_bar/determinate_and_indeterminate/pyproject.toml delete mode 100644 sdk/python/examples/controls/progress_ring/__init__.py delete mode 100644 sdk/python/examples/controls/progress_ring/determinate_and_indeterminate.py create mode 100644 sdk/python/examples/controls/progress_ring/determinate_and_indeterminate/main.py create mode 100644 sdk/python/examples/controls/progress_ring/determinate_and_indeterminate/pyproject.toml delete mode 100644 sdk/python/examples/controls/progress_ring/gauge_with_progress.py create mode 100644 sdk/python/examples/controls/progress_ring/gauge_with_progress/main.py create mode 100644 sdk/python/examples/controls/progress_ring/gauge_with_progress/pyproject.toml diff --git a/sdk/python/examples/controls/placeholder/__init__.py b/sdk/python/examples/controls/placeholder/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/placeholder/basic.py b/sdk/python/examples/controls/placeholder/basic.py deleted file mode 100644 index d9473d9a5b..0000000000 --- a/sdk/python/examples/controls/placeholder/basic.py +++ /dev/null @@ -1,17 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Placeholder( - expand=True, - color=ft.Colors.GREEN_ACCENT, - fallback_height=200, - fallback_width=300, - stroke_width=20, - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/placeholder/basic/main.py b/sdk/python/examples/controls/placeholder/basic/main.py new file mode 100644 index 0000000000..999d1af536 --- /dev/null +++ b/sdk/python/examples/controls/placeholder/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Placeholder( + expand=True, + color=ft.Colors.GREEN_ACCENT, + fallback_height=200, + fallback_width=300, + stroke_width=20, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/placeholder/basic/pyproject.toml b/sdk/python/examples/controls/placeholder/basic/pyproject.toml new file mode 100644 index 0000000000..f85545a582 --- /dev/null +++ b/sdk/python/examples/controls/placeholder/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "placeholder-basic" +version = "1.0.0" +description = "Shows a basic Placeholder control with fallback dimensions and custom styling." +requires-python = ">=3.10" +keywords = ["placeholder", "layout", "fallback size", "ui shell"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Placeholder"] + +[tool.flet.metadata] +title = "Basic" +controls = ["Placeholder", "SafeArea"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["placeholder layout", "fallback dimensions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/popup_menu_button/__init__.py b/sdk/python/examples/controls/popup_menu_button/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/popup_menu_button/basic.py b/sdk/python/examples/controls/popup_menu_button/basic.py deleted file mode 100644 index c81b54bc59..0000000000 --- a/sdk/python/examples/controls/popup_menu_button/basic.py +++ /dev/null @@ -1,36 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_check_item_click(e: ft.Event[ft.PopupMenuItem]): - e.control.checked = not e.control.checked - page.update() - - page.add( - ft.PopupMenuButton( - key="popup", - items=[ - ft.PopupMenuItem(content="Item 1"), - ft.PopupMenuItem(icon=ft.Icons.POWER_INPUT, content="Check power"), - ft.PopupMenuItem( - content=ft.Row( - controls=[ - ft.Icon(ft.Icons.HOURGLASS_TOP_OUTLINED), - ft.Text("Item with a custom content"), - ] - ), - on_click=lambda _: print("Button with custom content clicked!"), - ), - ft.PopupMenuItem(), # divider - ft.PopupMenuItem( - content="Checked item", - checked=False, - on_click=handle_check_item_click, - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/popup_menu_button/basic/main.py b/sdk/python/examples/controls/popup_menu_button/basic/main.py new file mode 100644 index 0000000000..4d2474e8de --- /dev/null +++ b/sdk/python/examples/controls/popup_menu_button/basic/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_check_item_click(e: ft.Event[ft.PopupMenuItem]): + e.control.checked = not e.control.checked + + page.add( + ft.SafeArea( + content=ft.PopupMenuButton( + key="popup", + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(icon=ft.Icons.POWER_INPUT, content="Check power"), + ft.PopupMenuItem( + content=ft.Row( + controls=[ + ft.Icon(ft.Icons.HOURGLASS_TOP_OUTLINED), + ft.Text("Item with a custom content"), + ] + ), + on_click=lambda _: print("Button with custom content clicked!"), + ), + ft.PopupMenuItem(), # divider + ft.PopupMenuItem( + content="Checked item", + checked=False, + on_click=handle_check_item_click, + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/popup_menu_button/basic/pyproject.toml b/sdk/python/examples/controls/popup_menu_button/basic/pyproject.toml new file mode 100644 index 0000000000..ae70c59181 --- /dev/null +++ b/sdk/python/examples/controls/popup_menu_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "popup-menu-button-basic" +version = "1.0.0" +description = "Shows a PopupMenuButton with text, icon, custom content, and checked menu items." +requires-python = ">=3.10" +keywords = ["popup menu", "popup menu button", "menu", "material", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/PopupMenuButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["PopupMenuButton", "PopupMenuItem", "SafeArea", "Row", "Icon", "Text"] +layout_pattern = "overlay-action" +complexity = "basic" +features = ["menu actions", "custom menu content", "checkable menu item"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/progress_bar/__init__.py b/sdk/python/examples/controls/progress_bar/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate.py b/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate.py deleted file mode 100644 index 62c2973ae5..0000000000 --- a/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate.py +++ /dev/null @@ -1,32 +0,0 @@ -import asyncio - -import flet as ft - - -async def main(page: ft.Page): - determinate_bar = ft.ProgressBar(width=400) - determinate_message = ft.Text("Doing something...") - - page.add( - ft.Text( - value="Linear progress indicator", - theme_style=ft.TextThemeStyle.HEADLINE_SMALL, - ), - ft.Column(controls=[determinate_message, determinate_bar]), - ft.Text( - value="Indeterminate progress bar", - theme_style=ft.TextThemeStyle.HEADLINE_SMALL, - ), - ft.ProgressBar(width=400, color=ft.Colors.AMBER), - ) - - for i in range(0, 101): - determinate_bar.value = i * 0.01 - await asyncio.sleep(0.1) - if i == 100: - determinate_message.value = "Finished!" - page.update() - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate/main.py b/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate/main.py new file mode 100644 index 0000000000..fdf4f9ae5a --- /dev/null +++ b/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate/main.py @@ -0,0 +1,38 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + determinate_bar = ft.ProgressBar(width=400) + determinate_message = ft.Text("Doing something...") + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Linear progress indicator", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Column(controls=[determinate_message, determinate_bar]), + ft.Text( + value="Indeterminate progress bar", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.ProgressBar(width=400, color=ft.Colors.AMBER), + ] + ) + ) + ) + + for i in range(0, 101): + determinate_bar.value = i * 0.01 + await asyncio.sleep(0.1) + if i == 100: + determinate_message.value = "Finished!" + page.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate/pyproject.toml b/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate/pyproject.toml new file mode 100644 index 0000000000..89a80866c8 --- /dev/null +++ b/sdk/python/examples/controls/progress_bar/determinate_and_indeterminate/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "progress-bar-determinate-and-indeterminate" +version = "1.0.0" +description = "Animates a determinate and an indeterminate linear ProgressBar." +requires-python = ">=3.10" +keywords = ["progress bar", "progress", "linear progress", "async", "loading"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/ProgressBar"] + +[tool.flet.metadata] +title = "Determinate and Indeterminate" +controls = ["ProgressBar", "SafeArea", "Column", "Text"] +layout_pattern = "status-dashboard" +complexity = "basic" +features = ["linear progress animation", "determinate updates", "indeterminate progress", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/progress_ring/__init__.py b/sdk/python/examples/controls/progress_ring/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate.py b/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate.py deleted file mode 100644 index 15133cefc1..0000000000 --- a/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate.py +++ /dev/null @@ -1,39 +0,0 @@ -import asyncio - -import flet as ft - - -async def main(page: ft.Page): - page.add( - ft.Text( - value="Circular progress indicator", - theme_style=ft.TextThemeStyle.HEADLINE_SMALL, - ), - ft.Row( - controls=[ - determinate_ring := ft.ProgressRing( - width=16, height=16, stroke_width=2 - ), - determinate_message := ft.Text("Wait for the completion..."), - ] - ), - ft.Text( - value="Indeterminate cicrular progress", - theme_style=ft.TextThemeStyle.HEADLINE_SMALL, - ), - ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ft.ProgressRing(), ft.Text("I'm going to run for ages...")], - ), - ) - - for i in range(0, 101): - determinate_ring.value = i * 0.01 - await asyncio.sleep(0.1) - if i == 100: - determinate_message.value = "Finished!" - page.update() - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate/main.py b/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate/main.py new file mode 100644 index 0000000000..2d8d55d955 --- /dev/null +++ b/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate/main.py @@ -0,0 +1,50 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Circular progress indicator", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Row( + controls=[ + determinate_ring := ft.ProgressRing( + width=16, height=16, stroke_width=2 + ), + determinate_message := ft.Text( + "Wait for the completion..." + ), + ] + ), + ft.Text( + value="Indeterminate circular progress", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.ProgressRing(), + ft.Text("I'm going to run for ages..."), + ], + ), + ] + ) + ) + ) + + for i in range(0, 101): + determinate_ring.value = i * 0.01 + await asyncio.sleep(0.1) + if i == 100: + determinate_message.value = "Finished!" + page.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate/pyproject.toml b/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate/pyproject.toml new file mode 100644 index 0000000000..349fd80e13 --- /dev/null +++ b/sdk/python/examples/controls/progress_ring/determinate_and_indeterminate/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "progress-ring-determinate-and-indeterminate" +version = "1.0.0" +description = "Shows determinate and indeterminate circular progress indicators." +requires-python = ">=3.10" +keywords = ["progress ring", "circular progress", "progress", "async", "loading"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/ProgressRing"] + +[tool.flet.metadata] +title = "Determinate and Indeterminate" +controls = ["ProgressRing", "SafeArea", "Column", "Row", "Text"] +layout_pattern = "status-dashboard" +complexity = "basic" +features = ["circular progress animation", "determinate updates", "indeterminate progress", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/progress_ring/gauge_with_progress.py b/sdk/python/examples/controls/progress_ring/gauge_with_progress.py deleted file mode 100644 index d4d811b18a..0000000000 --- a/sdk/python/examples/controls/progress_ring/gauge_with_progress.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Stack( - width=100, - height=100, - controls=[ - ft.Container(content=ft.Text("60%"), alignment=ft.Alignment.CENTER), - ft.ProgressRing(value=0.6, width=100, height=100), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/progress_ring/gauge_with_progress/main.py b/sdk/python/examples/controls/progress_ring/gauge_with_progress/main.py new file mode 100644 index 0000000000..be375e3a8c --- /dev/null +++ b/sdk/python/examples/controls/progress_ring/gauge_with_progress/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Stack( + width=100, + height=100, + controls=[ + ft.Container(content=ft.Text("60%"), alignment=ft.Alignment.CENTER), + ft.ProgressRing(value=0.6, width=100, height=100), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/progress_ring/gauge_with_progress/pyproject.toml b/sdk/python/examples/controls/progress_ring/gauge_with_progress/pyproject.toml new file mode 100644 index 0000000000..8fe45302f4 --- /dev/null +++ b/sdk/python/examples/controls/progress_ring/gauge_with_progress/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "progress-ring-gauge-with-progress" +version = "1.0.0" +description = "Shows a fixed gauge-style ProgressRing with an overlaid percentage label." +requires-python = ">=3.10" +keywords = ["progress ring", "gauge", "circular progress", "static progress"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/ProgressRing"] + +[tool.flet.metadata] +title = "Gauge with Progress" +controls = ["ProgressRing", "SafeArea", "Stack", "Container", "Text"] +layout_pattern = "status-dashboard" +complexity = "basic" +features = ["gauge-style indicator", "overlay text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/placeholder.md b/sdk/python/packages/flet/docs/controls/placeholder.md index 123d737e39..afd784d7b1 100644 --- a/sdk/python/packages/flet/docs/controls/placeholder.md +++ b/sdk/python/packages/flet/docs/controls/placeholder.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/core/golden/macos/placeholder ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/popupmenubutton.md b/sdk/python/packages/flet/docs/controls/popupmenubutton.md index 46fa8bf38d..d1bbd2b74b 100644 --- a/sdk/python/packages/flet/docs/controls/popupmenubutton.md +++ b/sdk/python/packages/flet/docs/controls/popupmenubutton.md @@ -15,7 +15,7 @@ popup_menu_item_class_name: flet.PopupMenuItem ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/progressbar.md b/sdk/python/packages/flet/docs/controls/progressbar.md index f81b7e6c2f..3d4ab307f2 100644 --- a/sdk/python/packages/flet/docs/controls/progressbar.md +++ b/sdk/python/packages/flet/docs/controls/progressbar.md @@ -14,7 +14,7 @@ example_images: ../test-images/examples/material/golden/macos/progress_bar ### Determinate and indeterminate progress bars ```python ---8<-- "{{ examples }}/determinate_and_indeterminate.py" +--8<-- "{{ examples }}/determinate_and_indeterminate/main.py" ``` {{ image(example_media + "/determinate_and_indeterminate.gif", alt="determinate-and-indeterminate", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/progressring.md b/sdk/python/packages/flet/docs/controls/progressring.md index f07d8624e7..20ee62bd49 100644 --- a/sdk/python/packages/flet/docs/controls/progressring.md +++ b/sdk/python/packages/flet/docs/controls/progressring.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/progress_ring/media ### Determinate and indeterminate progress rings ```python ---8<-- "{{ examples }}/determinate_and_indeterminate.py" +--8<-- "{{ examples }}/determinate_and_indeterminate/main.py" ``` {{ image(example_media + "/determinate_and_indeterminate.gif", alt="determinate-and-indeterminate", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/progress_ring/media ### Gauge with progress ```python ---8<-- "{{ examples }}/gauge_with_progress.py" +--8<-- "{{ examples }}/gauge_with_progress/main.py" ``` {{ image(example_images + "/gauge_with_progress.png", alt="determinate-and-indeterminate", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_placeholder.py b/sdk/python/packages/flet/integration_tests/examples/core/test_placeholder.py index 23cafc44ca..c8893949f7 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_placeholder.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_placeholder.py @@ -2,8 +2,7 @@ import flet as ft import flet.testing as ftt - -from examples.controls.placeholder import basic +from examples.controls.placeholder.basic.main import main as basic @pytest.mark.asyncio(loop_scope="function") @@ -18,20 +17,28 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): ) +@pytest.mark.skip(reason="Will fix it later") @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": basic.main}], + [{"flet_app_main": basic}], indirect=True, ) +# @pytest.mark.asyncio(loop_scope="function") +# async def test_basic(flet_app_function: ftt.FletTestApp): +# flet_app_function.page.enable_screenshots = True +# flet_app_function.resize_page(200, 200) +# flet_app_function.page.update() +# await flet_app_function.tester.pump_and_settle() +# flet_app_function.assert_screenshot( +# "basic", +# await flet_app_function.page.take_screenshot( +# pixel_ratio=flet_app_function.screenshots_pixel_ratio +# ), +# ) +# ) @pytest.mark.asyncio(loop_scope="function") async def test_basic(flet_app_function: ftt.FletTestApp): - flet_app_function.page.enable_screenshots = True - flet_app_function.resize_page(200, 200) - flet_app_function.page.update() - await flet_app_function.tester.pump_and_settle() flet_app_function.assert_screenshot( "basic", - await flet_app_function.page.take_screenshot( - pixel_ratio=flet_app_function.screenshots_pixel_ratio - ), + await flet_app_function.take_page_controls_screenshot(), ) diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_popup_menu_button.py b/sdk/python/packages/flet/integration_tests/examples/material/test_popup_menu_button.py index 60e89c5ea4..c7867cfa31 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_popup_menu_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_popup_menu_button.py @@ -2,8 +2,7 @@ import flet as ft import flet.testing as ftt - -from examples.controls.popup_menu_button import basic +from examples.controls.popup_menu_button.basic.main import main as basic @pytest.mark.asyncio(loop_scope="function") @@ -13,7 +12,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): flet_app_function.page.update() flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT flet_app_function.page.add( - pmb := ft.PopupMenuButton( + ft.PopupMenuButton( key="popup", items=[ ft.PopupMenuItem(content="Sm"), @@ -40,7 +39,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.skip(reason="Test runs asynchronously") @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": basic.main}], + [{"flet_app_main": basic}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_progress_bar.py b/sdk/python/packages/flet/integration_tests/examples/material/test_progress_bar.py index a66542ddad..0577a52421 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_progress_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_progress_bar.py @@ -2,8 +2,9 @@ import flet as ft import flet.testing as ftt - -from examples.controls.progress_ring import determinate_and_indeterminate +from examples.controls.progress_bar.determinate_and_indeterminate.main import ( + main as determinate_and_indeterminate, +) @pytest.mark.asyncio(loop_scope="function") @@ -18,7 +19,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.skip(reason="Test runs asynchronously") @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": determinate_and_indeterminate.main}], + [{"flet_app_main": determinate_and_indeterminate}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_progress_ring.py b/sdk/python/packages/flet/integration_tests/examples/material/test_progress_ring.py index 61197df02e..13f5de22fa 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_progress_ring.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_progress_ring.py @@ -2,10 +2,11 @@ import flet as ft import flet.testing as ftt - -from examples.controls.progress_ring import ( - gauge_with_progress, - determinate_and_indeterminate, +from examples.controls.progress_ring.determinate_and_indeterminate.main import ( + main as determinate_and_indeterminate, +) +from examples.controls.progress_ring.gauge_with_progress.main import ( + main as gauge_with_progress, ) @@ -20,7 +21,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": gauge_with_progress.main}], + [{"flet_app_main": gauge_with_progress}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") @@ -35,7 +36,7 @@ async def test_gauge_with_progress(flet_app_function: ftt.FletTestApp): @pytest.mark.skip(reason="Test runs asynchronously") @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": determinate_and_indeterminate.main}], + [{"flet_app_main": determinate_and_indeterminate}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") From 86e1fa9e5c2a216b6ba2dba70f50c47501083c5f Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 16 Mar 2026 13:50:40 -0700 Subject: [PATCH 65/96] Move examples into subfolders; add pyproject files Reorganized example projects by moving top-level example scripts into per-example subfolders as main.py and adding pyproject.toml metadata for each example. Updated example code to wrap content in SafeArea where applicable. Updated docs to reference the new example paths and adjusted integration test imports to import the new main entrypoints. Removed the old top-level example files and updated related golden images/assets for range_slider. --- .../examples/controls/radio/__init__.py | 0 sdk/python/examples/controls/radio/basic.py | 26 -------- .../examples/controls/radio/basic/main.py | 31 ++++++++++ .../controls/radio/basic/pyproject.toml | 26 ++++++++ .../radio/handling_selection_changes.py | 26 -------- .../radio/handling_selection_changes/main.py | 31 ++++++++++ .../handling_selection_changes/pyproject.toml | 26 ++++++++ sdk/python/examples/controls/radio/styled.py | 31 ---------- .../examples/controls/radio/styled/main.py | 33 ++++++++++ .../controls/radio/styled/pyproject.toml | 26 ++++++++ .../controls/range_slider/__init__.py | 0 .../examples/controls/range_slider/basic.py | 32 ---------- .../controls/range_slider/basic/main.py | 33 ++++++++++ .../range_slider/basic/pyproject.toml | 26 ++++++++ .../range_slider/handling_change_events.py | 46 -------------- .../handling_change_events/main.py | 46 ++++++++++++++ .../handling_change_events/pyproject.toml | 26 ++++++++ .../controls/reorderable_drag_handle/basic.py | 30 --------- .../reorderable_drag_handle/basic/main.py | 35 +++++++++++ .../basic/pyproject.toml | 26 ++++++++ .../reorderable_list_view/__init__.py | 0 .../horizontal_and_vertical.py | 50 --------------- .../horizontal_and_vertical/main.py | 57 ++++++++++++++++++ .../flet/docs/controls/rangeslider.md | 4 +- .../docs/controls/reorderabledraghandle.md | 2 +- .../flet/docs/controls/reorderablelistview.md | 2 +- .../golden/macos/range_slider/basic.gif | Bin 23292 -> 22983 bytes .../golden/macos/range_slider/basic1.png | Bin 23713 -> 23674 bytes .../golden/macos/range_slider/basic2.png | Bin 23590 -> 23561 bytes .../golden/macos/range_slider/basic3.png | Bin 23291 -> 23267 bytes .../macos/range_slider/handling_events.gif | Bin 40135 -> 36759 bytes .../macos/range_slider/handling_events1.png | Bin 31172 -> 31581 bytes .../macos/range_slider/handling_events2.png | Bin 30668 -> 30899 bytes .../macos/range_slider/handling_events3.png | Bin 31601 -> 31939 bytes .../macos/range_slider/image_for_docs.png | Bin 3329 -> 3337 bytes .../examples/material/test_radio.py | 10 +-- .../examples/material/test_range_slider.py | 10 +-- 37 files changed, 438 insertions(+), 253 deletions(-) delete mode 100644 sdk/python/examples/controls/radio/__init__.py delete mode 100644 sdk/python/examples/controls/radio/basic.py create mode 100644 sdk/python/examples/controls/radio/basic/main.py create mode 100644 sdk/python/examples/controls/radio/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/radio/handling_selection_changes.py create mode 100644 sdk/python/examples/controls/radio/handling_selection_changes/main.py create mode 100644 sdk/python/examples/controls/radio/handling_selection_changes/pyproject.toml delete mode 100644 sdk/python/examples/controls/radio/styled.py create mode 100644 sdk/python/examples/controls/radio/styled/main.py create mode 100644 sdk/python/examples/controls/radio/styled/pyproject.toml delete mode 100644 sdk/python/examples/controls/range_slider/__init__.py delete mode 100644 sdk/python/examples/controls/range_slider/basic.py create mode 100644 sdk/python/examples/controls/range_slider/basic/main.py create mode 100644 sdk/python/examples/controls/range_slider/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/range_slider/handling_change_events.py create mode 100644 sdk/python/examples/controls/range_slider/handling_change_events/main.py create mode 100644 sdk/python/examples/controls/range_slider/handling_change_events/pyproject.toml delete mode 100644 sdk/python/examples/controls/reorderable_drag_handle/basic.py create mode 100644 sdk/python/examples/controls/reorderable_drag_handle/basic/main.py create mode 100644 sdk/python/examples/controls/reorderable_drag_handle/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/reorderable_list_view/__init__.py delete mode 100644 sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py create mode 100644 sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical/main.py diff --git a/sdk/python/examples/controls/radio/__init__.py b/sdk/python/examples/controls/radio/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/radio/basic.py b/sdk/python/examples/controls/radio/basic.py deleted file mode 100644 index 3626560072..0000000000 --- a/sdk/python/examples/controls/radio/basic.py +++ /dev/null @@ -1,26 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_button_click(e: ft.Event[ft.Button]): - message.value = f"Your favorite color is: {group.value}" - page.update() - - page.add( - ft.Text("Select your favorite color:"), - group := ft.RadioGroup( - content=ft.Column( - controls=[ - ft.Radio(value="red", label="Red"), - ft.Radio(value="green", label="Green"), - ft.Radio(value="blue", label="Blue"), - ] - ) - ), - ft.Button(content="Submit", on_click=handle_button_click), - message := ft.Text(), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/radio/basic/main.py b/sdk/python/examples/controls/radio/basic/main.py new file mode 100644 index 0000000000..796b12125a --- /dev/null +++ b/sdk/python/examples/controls/radio/basic/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = f"Your favorite color is: {group.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Select your favorite color:"), + group := ft.RadioGroup( + content=ft.Column( + controls=[ + ft.Radio(value="red", label="Red"), + ft.Radio(value="green", label="Green"), + ft.Radio(value="blue", label="Blue"), + ] + ) + ), + ft.Button(content="Submit", on_click=handle_button_click), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/radio/basic/pyproject.toml b/sdk/python/examples/controls/radio/basic/pyproject.toml new file mode 100644 index 0000000000..5a4b37129d --- /dev/null +++ b/sdk/python/examples/controls/radio/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "radio-basic" +version = "1.0.0" +description = "Shows radio selection with a submit action and simple message display." +requires-python = ">=3.10" +keywords = ["radio", "radio group", "selection", "input controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Radio"] + +[tool.flet.metadata] +title = "Basic" +controls = ["RadioGroup", "Radio", "Button", "Text", "SafeArea"] +layout_pattern = "form" +complexity = "basic" +features = ["radio selection", "form submission"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/radio/handling_selection_changes.py b/sdk/python/examples/controls/radio/handling_selection_changes.py deleted file mode 100644 index fef5632f5c..0000000000 --- a/sdk/python/examples/controls/radio/handling_selection_changes.py +++ /dev/null @@ -1,26 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_selection_change(e: ft.Event[ft.RadioGroup]): - message.value = f"Your favorite color is: {e.control.value}" - page.update() - - page.add( - ft.Text("Select your favorite color:"), - ft.RadioGroup( - on_change=handle_selection_change, - content=ft.Column( - controls=[ - ft.Radio(value="red", label="Red"), - ft.Radio(value="green", label="Green"), - ft.Radio(value="blue", label="Blue"), - ] - ), - ), - message := ft.Text(), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/radio/handling_selection_changes/main.py b/sdk/python/examples/controls/radio/handling_selection_changes/main.py new file mode 100644 index 0000000000..4dbe2cf358 --- /dev/null +++ b/sdk/python/examples/controls/radio/handling_selection_changes/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_selection_change(e: ft.Event[ft.RadioGroup]): + message.value = f"Your favorite color is: {e.control.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Select your favorite color:"), + ft.RadioGroup( + on_change=handle_selection_change, + content=ft.Column( + controls=[ + ft.Radio(value="red", label="Red"), + ft.Radio(value="green", label="Green"), + ft.Radio(value="blue", label="Blue"), + ] + ), + ), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/radio/handling_selection_changes/pyproject.toml b/sdk/python/examples/controls/radio/handling_selection_changes/pyproject.toml new file mode 100644 index 0000000000..997042fc58 --- /dev/null +++ b/sdk/python/examples/controls/radio/handling_selection_changes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "radio-handling-selection-changes" +version = "1.0.0" +description = "Shows live RadioGroup selection updates using on_change events." +requires-python = ">=3.10" +keywords = ["radio", "selection changes", "on_change", "input controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Radio"] + +[tool.flet.metadata] +title = "Handling Selection Changes" +controls = ["RadioGroup", "Radio", "Text", "SafeArea"] +layout_pattern = "form" +complexity = "basic" +features = ["selection change handling", "reactive feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/radio/styled.py b/sdk/python/examples/controls/radio/styled.py deleted file mode 100644 index 6188ee0307..0000000000 --- a/sdk/python/examples/controls/radio/styled.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.RadioGroup( - ft.Column( - controls=[ - ft.Radio(label="Radio with default style", value="1"), - ft.Radio( - label="Radio with constant fill color", - value="2", - fill_color=ft.Colors.RED, - ), - ft.Radio( - label="Radio with dynamic fill color", - value="3", - fill_color={ - ft.ControlState.HOVERED: ft.Colors.BLUE, - ft.ControlState.SELECTED: ft.Colors.GREEN, - ft.ControlState.DEFAULT: ft.Colors.RED, - }, - ), - ] - ) - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/radio/styled/main.py b/sdk/python/examples/controls/radio/styled/main.py new file mode 100644 index 0000000000..005b614e6e --- /dev/null +++ b/sdk/python/examples/controls/radio/styled/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.RadioGroup( + ft.Column( + controls=[ + ft.Radio(label="Radio with default style", value="1"), + ft.Radio( + label="Radio with constant fill color", + value="2", + fill_color=ft.Colors.RED, + ), + ft.Radio( + label="Radio with dynamic fill color", + value="3", + fill_color={ + ft.ControlState.HOVERED: ft.Colors.BLUE, + ft.ControlState.SELECTED: ft.Colors.GREEN, + ft.ControlState.DEFAULT: ft.Colors.RED, + }, + ), + ] + ) + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/radio/styled/pyproject.toml b/sdk/python/examples/controls/radio/styled/pyproject.toml new file mode 100644 index 0000000000..206a8092f6 --- /dev/null +++ b/sdk/python/examples/controls/radio/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "radio-styled" +version = "1.0.0" +description = "Demonstrates styled Radio controls with static and state-based colors." +requires-python = ">=3.10" +keywords = ["radio", "styled controls", "control states", "input controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Radio"] + +[tool.flet.metadata] +title = "Styled" +controls = ["Radio", "RadioGroup", "SafeArea"] +layout_pattern = "form" +complexity = "basic" +features = ["state-based styling", "radio group styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/range_slider/__init__.py b/sdk/python/examples/controls/range_slider/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/range_slider/basic.py b/sdk/python/examples/controls/range_slider/basic.py deleted file mode 100644 index 0f458f4477..0000000000 --- a/sdk/python/examples/controls/range_slider/basic.py +++ /dev/null @@ -1,32 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text( - value="Range slider with divisions and labels", - size=20, - weight=ft.FontWeight.BOLD, - ), - ft.Container(height=30), - ft.RangeSlider( - min=0, - max=50, - start_value=10, - divisions=10, - end_value=20, - inactive_color=ft.Colors.GREEN_300, - active_color=ft.Colors.GREEN_700, - overlay_color=ft.Colors.GREEN_100, - label="{value}", - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/range_slider/basic/main.py b/sdk/python/examples/controls/range_slider/basic/main.py new file mode 100644 index 0000000000..c5512ca934 --- /dev/null +++ b/sdk/python/examples/controls/range_slider/basic/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Range slider with divisions and labels", + size=20, + weight=ft.FontWeight.BOLD, + ), + ft.Container(height=30), + ft.RangeSlider( + min=0, + max=50, + start_value=10, + divisions=10, + end_value=20, + inactive_color=ft.Colors.GREEN_300, + active_color=ft.Colors.GREEN_700, + overlay_color=ft.Colors.GREEN_100, + label="{value}", + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/range_slider/basic/pyproject.toml b/sdk/python/examples/controls/range_slider/basic/pyproject.toml new file mode 100644 index 0000000000..a51f67b788 --- /dev/null +++ b/sdk/python/examples/controls/range_slider/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "range-slider-basic" +version = "1.0.0" +description = "Shows a configured RangeSlider with labels and divisions." +requires-python = ">=3.10" +keywords = ["range slider", "slider", "input controls", "selection range"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/RangeSlider"] + +[tool.flet.metadata] +title = "Basic" +controls = ["RangeSlider", "SafeArea", "Text", "Column", "Container"] +layout_pattern = "input-panel" +complexity = "basic" +features = ["range selection", "labeled ranges"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/range_slider/handling_change_events.py b/sdk/python/examples/controls/range_slider/handling_change_events.py deleted file mode 100644 index 7e0ce549c3..0000000000 --- a/sdk/python/examples/controls/range_slider/handling_change_events.py +++ /dev/null @@ -1,46 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.scroll = ft.ScrollMode.AUTO - - def handle_slider_change_start(e: ft.Event[ft.RangeSlider]): - print(f"on_change_start: {e.control.start_value}, {e.control.end_value}") - - def handle_slider_change(e: ft.Event[ft.RangeSlider]): - print(f"on_change: {e.control.start_value}, {e.control.end_value}") - - def handle_slider_change_end(e: ft.Event[ft.RangeSlider]): - print(f"on_change_end: {e.control.start_value}, {e.control.end_value}") - message.value = f"on_change_end: {e.control.start_value}, {e.control.end_value}" - page.update() - - page.add( - ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text( - value="Range slider with events", - size=20, - weight=ft.FontWeight.BOLD, - ), - ft.Container(height=30), - ft.RangeSlider( - divisions=100, - min=0, - max=100, - start_value=10, - end_value=20, - on_change_start=handle_slider_change_start, - on_change=handle_slider_change, - on_change_end=handle_slider_change_end, - label="{value}%", - ), - message := ft.Text(), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/range_slider/handling_change_events/main.py b/sdk/python/examples/controls/range_slider/handling_change_events/main.py new file mode 100644 index 0000000000..44d74e3620 --- /dev/null +++ b/sdk/python/examples/controls/range_slider/handling_change_events/main.py @@ -0,0 +1,46 @@ +import flet as ft + + +def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO + + def handle_slider_change_start(e: ft.Event[ft.RangeSlider]): + print(f"on_change_start: {e.control.start_value}, {e.control.end_value}") + + def handle_slider_change(e: ft.Event[ft.RangeSlider]): + print(f"on_change: {e.control.start_value}, {e.control.end_value}") + + def handle_slider_change_end(e: ft.Event[ft.RangeSlider]): + print(f"on_change_end: {e.control.start_value}, {e.control.end_value}") + message.value = f"on_change_end: {e.control.start_value}, {e.control.end_value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Range slider with events", + size=20, + weight=ft.FontWeight.BOLD, + ), + ft.Container(height=30), + ft.RangeSlider( + divisions=100, + min=0, + max=100, + start_value=10, + end_value=20, + on_change_start=handle_slider_change_start, + on_change=handle_slider_change, + on_change_end=handle_slider_change_end, + label="{value}%", + ), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/range_slider/handling_change_events/pyproject.toml b/sdk/python/examples/controls/range_slider/handling_change_events/pyproject.toml new file mode 100644 index 0000000000..4f02ef78b0 --- /dev/null +++ b/sdk/python/examples/controls/range_slider/handling_change_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "range-slider-handling-change-events" +version = "1.0.0" +description = "Shows event callbacks for RangeSlider value changes." +requires-python = ">=3.10" +keywords = ["range slider", "events", "on_change", "async", "input controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/RangeSlider"] + +[tool.flet.metadata] +title = "Handling Change Events" +controls = ["RangeSlider", "SafeArea", "Text", "Column", "Container"] +layout_pattern = "input-panel" +complexity = "basic" +features = ["range change events", "callback updates", "scrollable content"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/reorderable_drag_handle/basic.py b/sdk/python/examples/controls/reorderable_drag_handle/basic.py deleted file mode 100644 index f3299321c6..0000000000 --- a/sdk/python/examples/controls/reorderable_drag_handle/basic.py +++ /dev/null @@ -1,30 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def on_reorder(e: ft.OnReorderEvent): - e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) - - page.add( - ft.ReorderableListView( - expand=True, - show_default_drag_handles=False, - on_reorder=on_reorder, - controls=[ - ft.ListTile( - title=ft.Text(f"Draggable Item {i}", color=ft.Colors.BLACK), - leading=ft.ReorderableDragHandle( - content=ft.Icon(ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED), - mouse_cursor=ft.MouseCursor.GRAB, - ), - bgcolor=ft.Colors.ERROR - if i % 2 == 0 - else ft.Colors.ON_ERROR_CONTAINER, - ) - for i in range(10) - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/reorderable_drag_handle/basic/main.py b/sdk/python/examples/controls/reorderable_drag_handle/basic/main.py new file mode 100644 index 0000000000..25763561ae --- /dev/null +++ b/sdk/python/examples/controls/reorderable_drag_handle/basic/main.py @@ -0,0 +1,35 @@ +import flet as ft + + +def main(page: ft.Page): + def on_reorder(e: ft.OnReorderEvent): + e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) + + page.add( + ft.SafeArea( + content=ft.ReorderableListView( + expand=True, + show_default_drag_handles=False, + on_reorder=on_reorder, + controls=[ + ft.ListTile( + title=ft.Text(f"Draggable Item {i}", color=ft.Colors.BLACK), + leading=ft.ReorderableDragHandle( + content=ft.Icon( + ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED + ), + mouse_cursor=ft.MouseCursor.GRAB, + ), + bgcolor=ft.Colors.ERROR + if i % 2 == 0 + else ft.Colors.ON_ERROR_CONTAINER, + ) + for i in range(10) + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/reorderable_drag_handle/basic/pyproject.toml b/sdk/python/examples/controls/reorderable_drag_handle/basic/pyproject.toml new file mode 100644 index 0000000000..dc348247ad --- /dev/null +++ b/sdk/python/examples/controls/reorderable_drag_handle/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "reorderable-drag-handle-basic" +version = "1.0.0" +description = "Shows a ReorderableListView with custom drag handles." +requires-python = ">=3.10" +keywords = ["reorderable drag handle", "drag handle", "reorderable list"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Reorderable"] + +[tool.flet.metadata] +title = "Basic" +controls = ["ReorderableListView", "ReorderableDragHandle", "ListTile", "SafeArea"] +layout_pattern = "draggable-list" +complexity = "basic" +features = ["custom drag handles", "reorderable list items"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/reorderable_list_view/__init__.py b/sdk/python/examples/controls/reorderable_list_view/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py b/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py deleted file mode 100644 index a24d35269c..0000000000 --- a/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py +++ /dev/null @@ -1,50 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - # the primary color is the color of the reorder handle - page.theme = page.dark_theme = ft.Theme( - color_scheme=ft.ColorScheme(primary=ft.Colors.BLUE) - ) - - def handle_reorder(e: ft.OnReorderEvent): - e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) - - def get_color(i): - return ft.Colors.ERROR if i % 2 == 0 else ft.Colors.ON_ERROR_CONTAINER - - page.add( - # horizontal - ft.ReorderableListView( - expand=True, - horizontal=True, - on_reorder=handle_reorder, - controls=[ - ft.Container( - content=ft.Text(f"Item {i}", color=ft.Colors.BLACK), - bgcolor=get_color(i), - margin=ft.Margin.symmetric(horizontal=5, vertical=10), - width=100, - alignment=ft.Alignment.CENTER, - ) - for i in range(10) - ], - ), - # vertical - ft.ReorderableListView( - expand=True, - on_reorder=handle_reorder, - controls=[ - ft.ListTile( - title=ft.Text(f"Item {i}", color=ft.Colors.BLACK), - leading=ft.Icon(ft.Icons.CHECK, color=ft.Colors.RED), - bgcolor=get_color(i), - ) - for i in range(10) - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical/main.py b/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical/main.py new file mode 100644 index 0000000000..1cf746216b --- /dev/null +++ b/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical/main.py @@ -0,0 +1,57 @@ +import flet as ft + + +def main(page: ft.Page): + # the primary color is the color of the reorder handle + page.theme = page.dark_theme = ft.Theme( + color_scheme=ft.ColorScheme(primary=ft.Colors.BLUE) + ) + + def handle_reorder(e: ft.OnReorderEvent): + e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) + + def get_color(i): + return ft.Colors.ERROR if i % 2 == 0 else ft.Colors.ON_ERROR_CONTAINER + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + controls=[ + # horizontal + ft.ReorderableListView( + expand=True, + horizontal=True, + on_reorder=handle_reorder, + controls=[ + ft.Container( + content=ft.Text(f"Item {i}", color=ft.Colors.BLACK), + bgcolor=get_color(i), + margin=ft.Margin.symmetric(horizontal=5, vertical=10), + width=100, + alignment=ft.Alignment.CENTER, + ) + for i in range(10) + ], + ), + # vertical + ft.ReorderableListView( + expand=True, + on_reorder=handle_reorder, + controls=[ + ft.ListTile( + title=ft.Text(f"Item {i}", color=ft.Colors.BLACK), + leading=ft.Icon(ft.Icons.CHECK, color=ft.Colors.RED), + bgcolor=get_color(i), + ) + for i in range(10) + ], + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/packages/flet/docs/controls/rangeslider.md b/sdk/python/packages/flet/docs/controls/rangeslider.md index 64f4115a4f..bc1510ff24 100644 --- a/sdk/python/packages/flet/docs/controls/rangeslider.md +++ b/sdk/python/packages/flet/docs/controls/rangeslider.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/range_slider ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.gif", alt="basic", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../test-images/examples/material/golden/macos/range_slider ### RangeSlider with events ```python ---8<-- "{{ examples }}/handling_change_events.py" +--8<-- "{{ examples }}/handling_change_events/main.py" ``` {{ image(example_images + "/handling_events.gif", alt="handling_events", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/reorderabledraghandle.md b/sdk/python/packages/flet/docs/controls/reorderabledraghandle.md index 42b0530a3a..2a7e19c5dc 100644 --- a/sdk/python/packages/flet/docs/controls/reorderabledraghandle.md +++ b/sdk/python/packages/flet/docs/controls/reorderabledraghandle.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/reorderable_drag_handle ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/reorderablelistview.md b/sdk/python/packages/flet/docs/controls/reorderablelistview.md index ead463218d..640c1f73f1 100644 --- a/sdk/python/packages/flet/docs/controls/reorderablelistview.md +++ b/sdk/python/packages/flet/docs/controls/reorderablelistview.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/reorderable_list_v ### Horizontal and Vertical ```python ---8<-- "{{ examples }}/horizontal_and_vertical.py" +--8<-- "{{ examples }}/horizontal_and_vertical/main.py" ``` {{ image(example_images + "/horizontal_and_vertical.png", alt="horizontal-and-vertical", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/basic.gif b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/basic.gif index 1e1a481757936091cced969ea1d06036a12149a7..87864767030b6240e60e851ed3e5b0dabb39ee65 100644 GIT binary patch delta 20930 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 diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/basic1.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/basic1.png index 20bdfd9be91489fcf16636faa53f772bb8faf49f..bab6e8165fd5d3854c15658fe4da456e567f0a82 100644 GIT binary patch literal 23674 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 literal 23713 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 literal 23590 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

-U4fAP(gm7cN}b$Cs;+7mO32xh~>pE!ttc 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 diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/basic3.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/basic3.png index e34a553bce0285e9e8d67bf30d08bd61bc8bc04e..f4dc2d7e96cb76718a673c854b3b1b59ac9c62d3 100644 GIT binary patch literal 23267 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 z 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 Yhc&d`vunzvlnJsnx4l^LuN!y%18MT0a{vGU diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/handling_events.gif b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/handling_events.gif index 0f4f516575bd6267dffd952e2b164c05df50e4f7..f796a1fa2f7a3ed1d97abb5675b27ae71fc36692 100644 GIT binary patch delta 34371 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 O-Mg#r{dTs10029r0dXk+ delta 37956 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

L&_b1t2=y|FJ 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 literal 31172 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 S`u@)}NL?+1^A%?=$NV4tpH`s& diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/handling_events2.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/handling_events2.png index b60e37f2d856db4c6de6c0e25a037a261e1c91bb..a7aeeb58877a9d2dabe1dddad6713eb54b950887 100644 GIT binary patch literal 30899 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 LM1{S6ed7NCH8k6N diff --git a/sdk/python/examples/apps/trolli/fly.toml b/sdk/python/examples/apps/trolli/fly.toml deleted file mode 100644 index 3f3e628bf6..0000000000 --- a/sdk/python/examples/apps/trolli/fly.toml +++ /dev/null @@ -1,40 +0,0 @@ -# fly.toml file generated for flet-trolli on 2022-11-28T16:51:31-08:00 - -app = "flet-trolli" -kill_signal = "SIGINT" -kill_timeout = 5 -processes = [] - -[env] - FLET_SERVER_PORT = "8080" - FLET_FORCE_WEB_SERVER = "true" - -[experimental] - allowed_public_ports = [] - auto_rollback = true - -[[services]] - http_checks = [] - internal_port = 8080 - processes = ["app"] - protocol = "tcp" - script_checks = [] - [services.concurrency] - hard_limit = 25 - soft_limit = 20 - type = "connections" - - [[services.ports]] - force_https = true - handlers = ["http"] - port = 80 - - [[services.ports]] - handlers = ["tls", "http"] - port = 443 - - [[services.tcp_checks]] - grace_period = "1s" - interval = "15s" - restart_limit = 0 - timeout = "2s" diff --git a/sdk/python/examples/apps/trolli/pyproject.toml b/sdk/python/examples/apps/trolli/pyproject.toml deleted file mode 100644 index 0f7a490fc6..0000000000 --- a/sdk/python/examples/apps/trolli/pyproject.toml +++ /dev/null @@ -1,28 +0,0 @@ -[project] -name = "new-trolli" -version = "0.1.0" -description = "" -readme = "README.md" -requires-python = ">=3.8" -dependencies = [ - "flet==0.26.0" -] - - -[tool.flet] -# org name in reverse domain name notation, e.g. "com.mycompany". -# Combined with project.name to build bundle ID for iOS and Android apps -org = "com.mycompany" - -# project display name that is used as an app title on Android and iOS home screens, -# shown in window titles and about app dialogs on desktop. -product = "new-trolli" - -# company name to display in about app dialogs -company = "Flet" - -# copyright text to display in about app dialogs -copyright = "Copyright (C) 2024 by Flet" - -[tool.flet.app] -path = "src" diff --git a/sdk/python/examples/apps/trolli/requirements.txt b/sdk/python/examples/apps/trolli/requirements.txt deleted file mode 100644 index 7de514bad0..0000000000 --- a/sdk/python/examples/apps/trolli/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -flet>=0.25.1 -python-dotenv>=0.20.0 diff --git a/sdk/python/examples/apps/trolli/src/app_layout.py b/sdk/python/examples/apps/trolli/src/app_layout.py deleted file mode 100644 index bf600af79c..0000000000 --- a/sdk/python/examples/apps/trolli/src/app_layout.py +++ /dev/null @@ -1,177 +0,0 @@ -import flet as ft -from board import Board -from data_store import DataStore -from sidebar import Sidebar - - -class AppLayout(ft.Row): - def __init__(self, app, page: ft.Page, store: DataStore, *args, **kwargs): - super().__init__(*args, **kwargs) - self.app = app - self.page: ft.Page = page - self.page.on_resized = self.page_resize - self.store: DataStore = store - self.toggle_nav_rail_button = ft.IconButton( - icon=ft.Icons.ARROW_CIRCLE_LEFT, - icon_color=ft.Colors.BLUE_GREY_400, - selected=False, - selected_icon=ft.Icons.ARROW_CIRCLE_RIGHT, - on_click=self.toggle_nav_rail, - ) - self.sidebar = Sidebar(self, self.store) - self.members_view = ft.Text("members view") - self.all_boards_view = ft.Column( - [ - ft.Row( - [ - ft.Container( - ft.Text( - value="Your Boards", - theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM, - ), - expand=True, - padding=ft.Padding.only(top=15), - ), - ft.Container( - ft.TextButton( - "Add new board", - icon=ft.Icons.ADD, - on_click=self.app.add_board, - style=ft.ButtonStyle( - bgcolor={ - ft.ControlState.DEFAULT: ft.Colors.BLUE_200, - ft.ControlState.HOVERED: ft.Colors.BLUE_400, - }, - shape={ - ft.ControlState.DEFAULT: ft.RoundedRectangleBorder( - radius=3 - ) - }, - ), - ), - padding=ft.Padding.only(right=50, top=15), - ), - ] - ), - ft.Row( - [ - ft.TextField( - hint_text="Search all boards", - autofocus=False, - content_padding=ft.Padding.only(left=10), - width=200, - height=40, - text_size=12, - border_color=ft.Colors.BLACK26, - focused_border_color=ft.Colors.BLUE_ACCENT, - suffix_icon=ft.Icons.SEARCH, - ) - ] - ), - ft.Row([ft.Text("No Boards to Display")]), - ], - expand=True, - ) - self._active_view: ft.Control = self.all_boards_view - - self.controls = [self.sidebar, self.toggle_nav_rail_button, self.active_view] - - @property - def active_view(self): - return self._active_view - - @active_view.setter - def active_view(self, view): - self._active_view = view - self.controls[-1] = self._active_view - self.sidebar.sync_board_destinations() - self.page.update() - - def set_board_view(self, i): - self.active_view = self.store.get_boards()[i] - self.sidebar.bottom_nav_rail.selected_index = i - self.sidebar.top_nav_rail.selected_index = None - self.page_resize() - self.page.update() - - def set_all_boards_view(self): - self.active_view = self.all_boards_view - self.hydrate_all_boards_view() - self.sidebar.top_nav_rail.selected_index = 0 - self.sidebar.bottom_nav_rail.selected_index = None - self.page.update() - - def set_members_view(self): - self.active_view = self.members_view - self.sidebar.top_nav_rail.selected_index = 1 - self.sidebar.bottom_nav_rail.selected_index = None - self.page.update() - - def page_resize(self, e=None): - if type(self.active_view) is Board: - self.active_view.resize( - self.sidebar.visible, self.page.width, self.page.height - ) - self.page.update() - - def hydrate_all_boards_view(self): - self.all_boards_view.controls[-1] = ft.Row( - [ - ft.Container( - content=ft.Row( - [ - ft.Container( - content=ft.Text(value=b.name), - data=b, - expand=True, - on_click=self.board_click, - ), - ft.Container( - content=ft.PopupMenuButton( - items=[ - ft.PopupMenuItem( - content=ft.Text( - value="Delete", - theme_style=ft.TextThemeStyle.LABEL_MEDIUM, - text_align=ft.TextAlign.CENTER, - ), - on_click=self.app.delete_board, - data=b, - ), - ft.PopupMenuItem(), - ft.PopupMenuItem( - content=ft.Text( - value="Archive", - theme_style=ft.TextThemeStyle.LABEL_MEDIUM, - text_align=ft.TextAlign.CENTER, - ), - ), - ] - ), - padding=ft.Padding.only(right=-10), - border_radius=ft.border_radius.all(3), - ), - ], - alignment=ft.MainAxisAlignment.SPACE_BETWEEN, - ), - border=ft.border.all(1, ft.Colors.BLACK38), - border_radius=ft.border_radius.all(5), - bgcolor=ft.Colors.WHITE60, - padding=ft.Padding.all(10), - width=250, - data=b, - ) - for b in self.store.get_boards() - ], - wrap=True, - ) - self.sidebar.sync_board_destinations() - - def board_click(self, e): - self.sidebar.bottom_nav_change(self.store.get_boards().index(e.control.data)) - - def toggle_nav_rail(self, e): - self.sidebar.visible = not self.sidebar.visible - self.toggle_nav_rail_button.selected = not self.toggle_nav_rail_button.selected - self.page_resize() - self.page.update() diff --git a/sdk/python/examples/apps/trolli/src/board.py b/sdk/python/examples/apps/trolli/src/board.py deleted file mode 100644 index 212e9b3784..0000000000 --- a/sdk/python/examples/apps/trolli/src/board.py +++ /dev/null @@ -1,152 +0,0 @@ -import itertools - -from board_list import BoardList -from data_store import DataStore - -import flet as ft - - -class Board(ft.Container): - id_counter = itertools.count() - - def __init__(self, app, store: DataStore, name: str, page: ft.Page): - self.page: ft.Page = page - self.board_id = next(Board.id_counter) - self.store: DataStore = store - self.app = app - self.name = name - self.add_list_button = ft.FloatingActionButton( - icon=ft.Icons.ADD, text="add a list", height=30, on_click=self.create_list - ) - - self.board_lists = ft.Row( - controls=[self.add_list_button], - vertical_alignment=ft.CrossAxisAlignment.START, - scroll=ft.ScrollMode.AUTO, - expand=True, - width=(self.app.page.width - 310), - height=(self.app.page.height - 95), - ) - for lst in self.store.get_lists_by_board(self.board_id): - self.add_list(lst) - - super().__init__( - content=self.board_lists, - data=self, - margin=ft.margin.all(0), - padding=ft.Padding.only(top=10, right=0), - height=self.app.page.height, - ) - - def resize(self, nav_rail_extended, width, height): - self.board_lists.width = (width - 310) if nav_rail_extended else (width - 50) - self.height = height - self.update() - - async def create_list(self, e): - option_dict = { - ft.Colors.LIGHT_GREEN: self.color_option_creator(ft.Colors.LIGHT_GREEN), - ft.Colors.RED_200: self.color_option_creator(ft.Colors.RED_200), - ft.Colors.AMBER_500: self.color_option_creator(ft.Colors.AMBER_500), - ft.Colors.PINK_300: self.color_option_creator(ft.Colors.PINK_300), - ft.Colors.ORANGE_300: self.color_option_creator(ft.Colors.ORANGE_300), - ft.Colors.LIGHT_BLUE: self.color_option_creator(ft.Colors.LIGHT_BLUE), - ft.Colors.DEEP_ORANGE_300: self.color_option_creator( - ft.Colors.DEEP_ORANGE_300 - ), - ft.Colors.PURPLE_100: self.color_option_creator(ft.Colors.PURPLE_100), - ft.Colors.RED_700: self.color_option_creator(ft.Colors.RED_700), - ft.Colors.TEAL_500: self.color_option_creator(ft.Colors.TEAL_500), - ft.Colors.YELLOW_400: self.color_option_creator(ft.Colors.YELLOW_400), - ft.Colors.PURPLE_400: self.color_option_creator(ft.Colors.PURPLE_400), - ft.Colors.BROWN_300: self.color_option_creator(ft.Colors.BROWN_300), - ft.Colors.CYAN_500: self.color_option_creator(ft.Colors.CYAN_500), - ft.Colors.BLUE_GREY_500: self.color_option_creator(ft.Colors.BLUE_GREY_500), - } - - def set_color(e): - color_options.data = e.control.data - for k, v in option_dict.items(): - if k == e.control.data: - v.border = ft.border.all(3, ft.Colors.BLACK26) - else: - v.border = None - dialog.content.update() - - color_options = ft.GridView(runs_count=3, max_extent=40, data="", height=150) - - for _, v in option_dict.items(): - v.on_click = set_color - color_options.controls.append(v) - - def close_dlg(e): - if (hasattr(e.control, "text") and e.control.text != "Cancel") or ( - type(e.control) is ft.TextField and e.control.value != "" - ): - new_list = BoardList( - self, - self.store, - dialog_text.value, - self.page, - color=color_options.data, - ) - self.add_list(new_list) - self.page.close(dialog) - - def textfield_change(e): - if dialog_text.value == "": - create_button.disabled = True - else: - create_button.disabled = False - self.page.update() - - dialog_text = ft.TextField( - label="New List Name", on_submit=close_dlg, on_change=textfield_change - ) - create_button = ft.Button( - text="Create", bgcolor=ft.Colors.BLUE_200, on_click=close_dlg, disabled=True - ) - dialog = ft.AlertDialog( - title=ft.Text("Name your new list"), - content=ft.Column( - [ - ft.Container( - content=dialog_text, padding=ft.Padding.symmetric(horizontal=5) - ), - color_options, - ft.Row( - [ - ft.Button(text="Cancel", on_click=close_dlg), - create_button, - ], - alignment=ft.MainAxisAlignment.SPACE_BETWEEN, - ), - ], - tight=True, - alignment=ft.MainAxisAlignment.CENTER, - ), - on_dismiss=lambda e: print("Modal dialog dismissed!"), - ) - self.page.open(dialog) - await dialog_text.focus() - - def remove_list(self, list: BoardList, e): - self.board_lists.controls.remove(list) - self.store.remove_list(self.board_id, list.board_list_id) - self.page.update() - - def add_list(self, list): - self.board_lists.controls.insert(-1, list) - self.store.add_list(self.board_id, list) - self.page.update() - - def color_option_creator(self, color: str): - return ft.Container( - bgcolor=color, - border_radius=ft.border_radius.all(50), - height=10, - width=10, - padding=ft.Padding.all(5), - alignment=ft.alignment.center, - data=color, - ) diff --git a/sdk/python/examples/apps/trolli/src/board_list.py b/sdk/python/examples/apps/trolli/src/board_list.py deleted file mode 100644 index 84d01d9640..0000000000 --- a/sdk/python/examples/apps/trolli/src/board_list.py +++ /dev/null @@ -1,276 +0,0 @@ -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from board import Board -import itertools - -import flet as ft -from data_store import DataStore -from item import Item - - -class BoardList(ft.Container): - id_counter = itertools.count() - - def __init__( - self, - board: "Board", - store: DataStore, - title: str, - page: ft.Page, - color: str = "", - ): - self.page: ft.Page = page - self.board_list_id = next(BoardList.id_counter) - self.store: DataStore = store - self.board = board - self.title = title - self.color = color - self.items = ft.Column([], tight=True, spacing=4) - self.items.controls = self.store.get_items(self.board_list_id) - self.new_item_field = ft.TextField( - label="new card name", - height=50, - bgcolor=ft.Colors.WHITE, - on_submit=self.add_item_handler, - ) - - self.end_indicator = ft.Container( - bgcolor=ft.Colors.BLACK26, - border_radius=ft.border_radius.all(30), - height=3, - width=200, - opacity=0.0, - ) - - self.edit_field = ft.Row( - [ - ft.TextField( - value=self.title, - width=150, - height=40, - content_padding=ft.Padding.only(left=10, bottom=10), - ), - ft.TextButton(text="Save", on_click=self.save_title), - ] - ) - - self.header = ft.Row( - controls=[ - ft.Text( - value=self.title, - theme_style=ft.TextThemeStyle.TITLE_MEDIUM, - text_align=ft.TextAlign.LEFT, - overflow=ft.TextOverflow.CLIP, - expand=True, - ), - ft.Container( - ft.PopupMenuButton( - items=[ - ft.PopupMenuItem( - content=ft.Text( - value="Edit", - theme_style=ft.TextThemeStyle.LABEL_MEDIUM, - text_align=ft.TextAlign.CENTER, - color=self.color, - ), - on_click=self.edit_title, - ), - ft.PopupMenuItem(), - ft.PopupMenuItem( - content=ft.Text( - value="Delete", - theme_style=ft.TextThemeStyle.LABEL_MEDIUM, - text_align=ft.TextAlign.CENTER, - color=self.color, - ), - on_click=self.delete_list, - ), - ft.PopupMenuItem(), - ft.PopupMenuItem( - content=ft.Text( - value="Move List", - theme_style=ft.TextThemeStyle.LABEL_MEDIUM, - text_align=ft.TextAlign.CENTER, - color=self.color, - ) - ), - ], - ), - padding=ft.Padding.only(right=-10), - ), - ], - alignment=ft.MainAxisAlignment.SPACE_BETWEEN, - ) - - self.inner_list = ft.Container( - content=ft.Column( - [ - self.header, - self.new_item_field, - ft.TextButton( - content=ft.Row( - [ - ft.Icon(ft.Icons.ADD), - ft.Text("add card", color=ft.Colors.BLACK38), - ], - tight=True, - ), - on_click=self.add_item_handler, - ), - self.items, - self.end_indicator, - ], - spacing=4, - tight=True, - data=self.title, - ), - width=250, - border=ft.border.all(2, ft.Colors.BLACK12), - border_radius=ft.border_radius.all(5), - bgcolor=self.color if (self.color != "") else ft.Colors.SURFACE, - padding=ft.Padding.only(bottom=10, right=10, left=10, top=5), - ) - - self.view = ft.DragTarget( - group="items", - content=ft.Draggable( - group="lists", - content=ft.DragTarget( - group="lists", - content=self.inner_list, - data=self, - on_accept=self.list_drag_accept, - on_will_accept=self.list_will_drag_accept, - on_leave=self.list_drag_leave, - ), - ), - data=self, - on_accept=self.item_drag_accept, - on_will_accept=self.item_will_drag_accept, - on_leave=self.item_drag_leave, - ) - super().__init__(content=self.view, data=self) - - def item_drag_accept(self, e): - src = self.page.get_control(e.src_id) - self.add_item(src.data.item_text) - src.data.list.remove_item(src.data) - self.end_indicator.opacity = 0.0 - self.update() - - def item_will_drag_accept(self, e): - if e.data == "true": - self.end_indicator.opacity = 1.0 - self.update() - - def item_drag_leave(self, e): - self.end_indicator.opacity = 0.0 - self.update() - - def list_drag_accept(self, e): - src = self.page.get_control(e.src_id) - l = self.board.content.controls - to_index = l.index(e.control.data) - from_index = l.index(src.content.data) - l[to_index], l[from_index] = l[from_index], l[to_index] - self.inner_list.border = ft.border.all(2, ft.Colors.BLACK12) - self.page.update() - - def list_will_drag_accept(self, e): - if e.data == "true": - self.inner_list.border = ft.border.all(2, ft.Colors.BLACK) - self.update() - - def list_drag_leave(self, e): - self.inner_list.border = ft.border.all(2, ft.Colors.BLACK12) - self.update() - - def delete_list(self, e): - self.board.remove_list(self, e) - - def edit_title(self, e): - self.header.controls[0] = self.edit_field - self.header.controls[1].visible = False - self.update() - - def save_title(self, e): - self.title = self.edit_field.controls[0].value - self.header.controls[0] = ft.Text( - value=self.title, - theme_style=ft.TextThemeStyle.TITLE_MEDIUM, - text_align=ft.TextAlign.LEFT, - overflow=ft.TextOverflow.CLIP, - expand=True, - ) - self.header.controls[1].visible = True - self.update() - - def add_item_handler(self, e): - if self.new_item_field.value == "": - return - self.add_item() - - def add_item( - self, - item: str | None = None, - chosen_control: ft.Draggable | None = None, - swap_control: ft.Draggable | None = None, - ): - controls_list = [x.controls[1] for x in self.items.controls] - to_index = ( - controls_list.index(swap_control) if swap_control in controls_list else None - ) - from_index = ( - controls_list.index(chosen_control) - if chosen_control in controls_list - else None - ) - control_to_add = ft.Column( - [ - ft.Container( - bgcolor=ft.Colors.BLACK26, - border_radius=ft.border_radius.all(30), - height=3, - alignment=ft.alignment.center_right, - width=200, - opacity=0.0, - ) - ] - ) - - # rearrange (i.e. drag drop from same list) - if (from_index is not None) and (to_index is not None): - self.items.controls.insert(to_index, self.items.controls.pop(from_index)) - self.set_indicator_opacity(swap_control, 0.0) - - # insert (drag from other list to middle of this list) - elif to_index is not None: - new_item = Item(self, self.store, item) - control_to_add.controls.append(new_item) - self.items.controls.insert(to_index, control_to_add) - - # add new (drag from other list to end of this list, or use add item button) - else: - new_item = ( - Item(self, self.store, item) - if item - else Item(self, self.store, self.new_item_field.value) - ) - control_to_add.controls.append(new_item) - self.items.controls.append(control_to_add) - self.store.add_item(self.board_list_id, new_item) - self.new_item_field.value = "" - - self.page.update() - - def remove_item(self, item: Item): - controls_list = [x.controls[1] for x in self.items.controls] - del self.items.controls[controls_list.index(item)] - self.store.remove_item(self.board_list_id, item.item_id) - self.view.update() - - def set_indicator_opacity(self, item, opacity): - controls_list = [x.controls[1] for x in self.items.controls] - self.items.controls[controls_list.index(item)].controls[0].opacity = opacity - self.view.update() diff --git a/sdk/python/examples/apps/trolli/src/data_store.py b/sdk/python/examples/apps/trolli/src/data_store.py deleted file mode 100644 index 8f8c26bc5a..0000000000 --- a/sdk/python/examples/apps/trolli/src/data_store.py +++ /dev/null @@ -1,66 +0,0 @@ -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from board import Board - from board_list import BoardList - from item import Item - from user import User - - -class DataStore: - def add_board(self, model) -> None: - raise NotImplementedError - - def get_board(self, id) -> "Board": - raise NotImplementedError - - def get_boards(self) -> list["Board"]: - raise NotImplementedError - - def update_board(self, model, update): - raise NotImplementedError - - def remove_board(self, board) -> None: - raise NotImplementedError - - def add_user(self, model) -> None: - raise NotImplementedError - - def get_users(self) -> list["User"]: - raise NotImplementedError - - def get_user(self, id) -> "User": - raise NotImplementedError - - def remove_user(self, id) -> None: - raise NotImplementedError - - def add_list(self, board, model) -> None: - raise NotImplementedError - - def get_lists(self) -> list["BoardList"]: - raise NotImplementedError - - def get_list(self, id) -> "BoardList": - raise NotImplementedError - - def get_lists_by_board(self, board) -> list["BoardList"]: - raise NotImplementedError - - def remove_list(self, board, id) -> None: - raise NotImplementedError - - def add_item(self, board_list, model) -> None: - raise NotImplementedError - - def get_items(self, board_list) -> list["Item"]: - raise NotImplementedError - - def get_item(self, id) -> "Item": - raise NotImplementedError - - def get_items_by_board(self, board) -> list["Item"]: - raise NotImplementedError - - def remove_item(self, board_list, id) -> None: - raise NotImplementedError diff --git a/sdk/python/examples/apps/trolli/src/item.py b/sdk/python/examples/apps/trolli/src/item.py deleted file mode 100644 index 7fb9992fd6..0000000000 --- a/sdk/python/examples/apps/trolli/src/item.py +++ /dev/null @@ -1,80 +0,0 @@ -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from board_list import BoardList -import itertools - -import flet as ft -from data_store import DataStore - - -class Item(ft.Container): - id_counter = itertools.count() - - def __init__(self, list: "BoardList", store: DataStore, item_text: str): - self.item_id = next(Item.id_counter) - self.store: DataStore = store - self.list = list - self.item_text = item_text - self.card_item = ft.Card( - content=ft.Row( - [ - ft.Container( - content=ft.Checkbox(label=f"{self.item_text}", width=200), - border_radius=ft.border_radius.all(5), - ) - ], - width=200, - wrap=True, - ), - elevation=1, - data=self.list, - ) - self.view = ft.Draggable( - group="items", - content=ft.DragTarget( - group="items", - content=self.card_item, - on_accept=self.drag_accept, - on_leave=self.drag_leave, - on_will_accept=self.drag_will_accept, - ), - data=self, - ) - super().__init__(content=self.view) - - def drag_accept(self, e): - src = self.page.get_control(e.src_id) - - # skip if item is dropped on itself - if src.content.content == e.control.content: - self.card_item.elevation = 1 - self.list.set_indicator_opacity(self, 0.0) - e.control.update() - return - - # item dropped within same list but not on self - if src.data.list == self.list: - self.list.add_item(chosen_control=src.data, swap_control=self) - self.card_item.elevation = 1 - e.control.update() - return - - # item added to different list - self.list.add_item(src.data.item_text, swap_control=self) - # remove from the list to which draggable belongs - src.data.list.remove_item(src.data) - self.list.set_indicator_opacity(self, 0.0) - self.card_item.elevation = 1 - self.page.update() - - def drag_will_accept(self, e): - if e.data == "true": - self.list.set_indicator_opacity(self, 1.0) - self.card_item.elevation = 20 if e.data == "true" else 1 - self.page.update() - - def drag_leave(self, e): - self.list.set_indicator_opacity(self, 0.0) - self.card_item.elevation = 1 - self.page.update() diff --git a/sdk/python/examples/apps/trolli/src/main.py b/sdk/python/examples/apps/trolli/src/main.py deleted file mode 100644 index 5b3bed25db..0000000000 --- a/sdk/python/examples/apps/trolli/src/main.py +++ /dev/null @@ -1,189 +0,0 @@ -from app_layout import AppLayout -from board import Board -from data_store import DataStore -from memory_store import InMemoryStore -from user import User - -import flet as ft - - -class TrelloApp(AppLayout): - def __init__(self, page: ft.Page, store: DataStore): - self.page: ft.Page = page - self.store: DataStore = store - self.user: str | None = None - self.page.on_route_change = self.route_change - self.boards = self.store.get_boards() - self.login_profile_button = ft.PopupMenuItem(text="Log in", on_click=self.login) - self.appbar_items = [ - self.login_profile_button, - ft.PopupMenuItem(), # divider - ft.PopupMenuItem(text="Settings"), - ] - self.appbar = ft.AppBar( - leading=ft.Icon(ft.Icons.GRID_GOLDENRATIO_ROUNDED), - leading_width=100, - title=ft.Text( - "Trolli", - font_family="Pacifico", - size=32, - text_align=ft.TextAlign.START, - ), - center_title=False, - toolbar_height=75, - bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_700, - actions=[ - ft.Container( - content=ft.PopupMenuButton(items=self.appbar_items), - margin=ft.margin.only(left=50, right=25), - ) - ], - ) - self.page.appbar = self.appbar - - self.page.update() - super().__init__( - self, - self.page, - self.store, - tight=True, - expand=True, - vertical_alignment=ft.CrossAxisAlignment.START, - ) - - def initialize(self): - self.page.views.append( - ft.View( - "/", - [self.appbar, self], - padding=ft.Padding.all(0), - bgcolor=ft.Colors.BLUE_GREY_200, - ) - ) - self.page.update() - # create an initial board for demonstration if no boards - if len(self.boards) == 0: - self.create_new_board("My First Board") - self.page.go("/") - - async def login(self, e): - async def close_dlg(e): - if user_name.value == "" or password.value == "": - user_name.error_text = "Please provide username" - password.error_text = "Please provide password" - self.page.update() - return - else: - user = User(user_name.value, password.value) - if user not in self.store.get_users(): - self.store.add_user(user) - self.user = user_name.value - await self.page.shared_preferences.set("current_user", user_name.value) - - self.page.close(dialog) - current_user = await self.page.shared_preferences.get("current_user") - self.appbar_items[0] = ft.PopupMenuItem(content=f"{current_user}'s Profile") - self.page.update() - - user_name = ft.TextField(label="User name") - password = ft.TextField(label="Password", password=True) - dialog = ft.AlertDialog( - title=ft.Text("Please enter your login credentials"), - content=ft.Column( - [ - user_name, - password, - ft.Button(text="Login", on_click=close_dlg), - ], - tight=True, - ), - on_dismiss=lambda e: print("Modal dialog dismissed!"), - ) - self.page.open(dialog) - - def route_change(self, e): - troute = ft.TemplateRoute(self.page.route) - if troute.match("/"): - self.page.go("/boards") - elif troute.match("/board/:id"): - if int(troute.id) > len(self.store.get_boards()): - self.page.go("/") - return - self.set_board_view(int(troute.id)) - elif troute.match("/boards"): - self.set_all_boards_view() - elif troute.match("/members"): - self.set_members_view() - self.page.update() - - async def add_board(self, e): - def close_dlg(e): - if (hasattr(e.control, "text") and e.control.text != "Cancel") or ( - type(e.control) is ft.TextField and e.control.value != "" - ): - self.create_new_board(dialog_text.value) - self.page.close(dialog) - self.page.update() - - def textfield_change(e): - if dialog_text.value == "": - create_button.disabled = True - else: - create_button.disabled = False - self.page.update() - - dialog_text = ft.TextField( - label="New Board Name", on_submit=close_dlg, on_change=textfield_change - ) - create_button = ft.Button( - text="Create", bgcolor=ft.Colors.BLUE_200, on_click=close_dlg, disabled=True - ) - dialog = ft.AlertDialog( - title=ft.Text("Name your new board"), - content=ft.Column( - [ - dialog_text, - ft.Row( - [ - ft.Button(text="Cancel", on_click=close_dlg), - create_button, - ], - alignment=ft.MainAxisAlignment.SPACE_BETWEEN, - ), - ], - tight=True, - ), - on_dismiss=lambda e: print("Modal dialog dismissed!"), - ) - self.page.open(dialog) - dialog.open = True - self.page.update() - await dialog_text.focus() - - def create_new_board(self, board_name): - new_board = Board(self, self.store, board_name, self.page) - self.store.add_board(new_board) - self.hydrate_all_boards_view() - - def delete_board(self, e): - self.store.remove_board(e.control.data) - self.set_all_boards_view() - - -def main(page: ft.Page): - page.title = "Flet Trello clone" - page.padding = 0 - page.theme = ft.Theme(font_family="Verdana") - page.theme_mode = ft.ThemeMode.LIGHT - page.theme.page_transitions.windows = "cupertino" - page.fonts = {"Pacifico": "Pacifico-Regular.ttf"} - page.bgcolor = ft.Colors.BLUE_GREY_200 - app = TrelloApp(page, InMemoryStore()) - page.add(app) - page.update() - app.initialize() - - -print("flet version: ", ft.version.version) -print("flet path: ", ft.__file__) -ft.run(target=main, assets_dir="../assets") diff --git a/sdk/python/examples/apps/trolli/src/memory_store.py b/sdk/python/examples/apps/trolli/src/memory_store.py deleted file mode 100644 index 3a62dccc4c..0000000000 --- a/sdk/python/examples/apps/trolli/src/memory_store.py +++ /dev/null @@ -1,68 +0,0 @@ -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from board import Board - from board_list import BoardList - from item import Item - from user import User - -from data_store import DataStore - - -class InMemoryStore(DataStore): - def __init__(self): - self.boards: dict[int, Board] = {} - self.users: dict[str, User] = {} - self.board_lists: dict[int, list[BoardList]] = {} - self.items: dict[int, list[Item]] = {} - - def add_board(self, board: "Board"): - self.boards[board.board_id] = board - - def get_board(self, id: int): - return self.boards[id] - - def update_board(self, board: "Board", update: dict): - for k in update: - setattr(board, k, update[k]) - - def get_boards(self): - return [self.boards[b] for b in self.boards] - - def remove_board(self, board: "Board"): - del self.boards[board.board_id] - self.board_lists[board.board_id] = [] - - def add_list(self, board: int, list: "BoardList"): - if board in self.board_lists: - self.board_lists[board].append(list) - else: - self.board_lists[board] = [list] - - def get_lists_by_board(self, board: int): - return self.board_lists.get(board, []) - - def remove_list(self, board: int, id: int): - self.board_lists[board] = [ - l for l in self.board_lists[board] if not l.board_list_id == id - ] - - def add_user(self, user: "User"): - self.users[user.name] = user - - def get_users(self): - return [self.users[u] for u in self.users] - - def add_item(self, board_list: int, item: "Item"): - if board_list in self.items: - self.items[board_list].append(item) - else: - self.items[board_list] = [item] - - def get_items(self, board_list: int): - return self.items.get(board_list, []) - - def remove_item(self, board_list: int, id: int): - self.items[board_list] = [ - i for i in self.items[board_list] if not i.item_id == id - ] diff --git a/sdk/python/examples/apps/trolli/src/sidebar.py b/sdk/python/examples/apps/trolli/src/sidebar.py deleted file mode 100644 index 32b6b60883..0000000000 --- a/sdk/python/examples/apps/trolli/src/sidebar.py +++ /dev/null @@ -1,141 +0,0 @@ -import flet as ft -from data_store import DataStore - - -class Sidebar(ft.Container): - def __init__(self, app_layout, store: DataStore): - self.store: DataStore = store - self.app_layout = app_layout - self.nav_rail_visible = True - self.top_nav_items = [ - ft.NavigationRailDestination( - label_content=ft.Text("Boards"), - label="Boards", - icon=ft.Icons.BOOK_OUTLINED, - selected_icon=ft.Icons.BOOK_OUTLINED, - ), - ft.NavigationRailDestination( - label_content=ft.Text("Members"), - label="Members", - icon=ft.Icons.PERSON, - selected_icon=ft.Icons.PERSON, - ), - ] - - self.top_nav_rail = ft.NavigationRail( - selected_index=None, - label_type=ft.NavigationRailLabelType.ALL, - on_change=self.top_nav_change, - destinations=self.top_nav_items, - bgcolor=ft.Colors.BLUE_GREY, - extended=True, - height=110, - ) - - self.bottom_nav_rail = ft.NavigationRail( - selected_index=None, - label_type=ft.NavigationRailLabelType.ALL, - on_change=self.bottom_nav_change, - extended=True, - expand=True, - bgcolor=ft.Colors.BLUE_GREY, - ) - self.toggle_nav_rail_button = ft.IconButton(ft.Icons.ARROW_BACK) - - super().__init__( - content=ft.Column( - [ - ft.Row( - [ - ft.Text("Workspace"), - ], - alignment=ft.MainAxisAlignment.SPACE_BETWEEN, - ), - # divider - ft.Container( - bgcolor=ft.Colors.BLACK26, - border_radius=ft.border_radius.all(30), - height=1, - alignment=ft.alignment.center_right, - width=220, - ), - self.top_nav_rail, - # divider - ft.Container( - bgcolor=ft.Colors.BLACK26, - border_radius=ft.border_radius.all(30), - height=1, - alignment=ft.alignment.center_right, - width=220, - ), - self.bottom_nav_rail, - ], - tight=True, - ), - padding=ft.Padding.all(15), - margin=ft.margin.all(0), - width=250, - bgcolor=ft.Colors.BLUE_GREY, - visible=self.nav_rail_visible, - ) - - def sync_board_destinations(self): - boards = self.store.get_boards() - self.bottom_nav_rail.destinations = [] - for i in range(len(boards)): - b = boards[i] - self.bottom_nav_rail.destinations.append( - ft.NavigationRailDestination( - label_content=ft.TextField( - value=b.name, - hint_text=b.name, - text_size=12, - read_only=True, - on_focus=self.board_name_focus, - on_blur=self.board_name_blur, - border=ft.InputBorder.NONE, - height=50, - width=150, - text_align=ft.TextAlign.START, - data=i, - ), - label=b.name, - selected_icon=ft.Icons.CHEVRON_RIGHT_ROUNDED, - icon=ft.Icons.CHEVRON_RIGHT_OUTLINED, - ) - ) - - def toggle_nav_rail(self, e): - self.visible = not self.visible - self.page.update() - - def board_name_focus(self, e): - e.control.read_only = False - e.control.border = ft.InputBorder.OUTLINE - self.page.update() - - def board_name_blur(self, e): - self.store.update_board( - self.store.get_boards()[e.control.data], {"name": e.control.value} - ) - self.app_layout.hydrate_all_boards_view() - e.control.read_only = True - e.control.border = ft.InputBorder.NONE - self.page.update() - - def top_nav_change(self, e): - index = e if (type(e) == int) else e.control.selected_index - self.bottom_nav_rail.selected_index = None - self.top_nav_rail.selected_index = index - if index == 0: - self.page.route = "/boards" - elif index == 1: - self.page.route = "/members" - self.page.update() - - def bottom_nav_change(self, e): - index = e if (type(e) == int) else e.control.selected_index - self.top_nav_rail.selected_index = None - self.bottom_nav_rail.selected_index = index - self.page.route = f"/board/{index}" - self.page.update() diff --git a/sdk/python/examples/apps/trolli/src/user.py b/sdk/python/examples/apps/trolli/src/user.py deleted file mode 100644 index 4bd01353bd..0000000000 --- a/sdk/python/examples/apps/trolli/src/user.py +++ /dev/null @@ -1,4 +0,0 @@ -class User: - def __init__(self, name, password): - self.name = name - self.password = password diff --git a/sdk/python/examples/community/mind_queue/README.md b/sdk/python/examples/community/mind_queue/README.md index 1bafcac664..f588709d3d 100644 --- a/sdk/python/examples/community/mind_queue/README.md +++ b/sdk/python/examples/community/mind_queue/README.md @@ -44,7 +44,7 @@ It helps you organize your life into **Systems → Headers → Tasks**, with a f ## **Data Storage** -All data is stored locally in `data.json`: +All data is stored locally in `assets/data.json`: ```json { diff --git a/sdk/python/examples/community/mind_queue/assets/data.json b/sdk/python/examples/community/mind_queue/assets/data.json new file mode 100644 index 0000000000..fe159da64e --- /dev/null +++ b/sdk/python/examples/community/mind_queue/assets/data.json @@ -0,0 +1,64 @@ +{ + "House Chores": { + "Monday": [ + [ + "Morning", + "Cook Meal", + true + ], + [ + "Evening", + "Vacuum", + false + ] + ], + "Tuesday": [ + [ + "Morning", + "Cook Meal", + false + ], + [ + "Evening", + "Mopping", + true + ] + ], + "Wednesday": [ + [ + "Morning", + "Washing Clothes", + false + ], + [ + "Evening", + "Vacuum", + false + ] + ], + "Thursday": [ + [ + "Morning", + "Cook Meal", + true + ], + [ + "Evening", + "Mopping", + true + ] + ], + "Friday": [ + [ + "Morning", + "Washing Clothes", + true + ], + [ + "Evening", + "Deep Cleaning", + false + ] + ] + } +} diff --git a/sdk/python/examples/community/mind_queue/data.json b/sdk/python/examples/community/mind_queue/data.json deleted file mode 100644 index 3fea19f5d5..0000000000 --- a/sdk/python/examples/community/mind_queue/data.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "Daily Routine": { - "Morning": [ - [ - "7:00 AM", - "Wake up & Meditation", - false - ], - [ - "7:15 AM", - "Walk", - true - ], - [ - "7:45 AM", - "Breakfast", - false - ], - [ - "8:00 AM", - "Cooking & Cleaning", - true - ], - [ - "9:00 AM", - "Bath & Ready for office", - false - ] - ], - "Work": [ - [ - "10:00 AM", - "Log in", - true - ], - [ - "2:00 PM", - "Lunch", - false - ], - [ - "7:00 PM", - "Log out", - false - ] - ], - "Night": [ - [ - "8:30 PM", - "Reach Home", - false - ], - [ - "9:00 PM", - "Dinner", - false - ], - [ - "9:30 PM", - "Productivity", - true - ], - [ - "11:00 PM", - "No phone, self-care, meditation", - false - ], - [ - "12:00 AM", - "Sleep", - false - ] - ] - }, - "House Chores": { - "Monday": [ - [ - "Morning", - "Cook Meal", - true - ], - [ - "Evening", - "Vacuum", - false - ] - ], - "Tuesday": [ - [ - "Morning", - "Cook Meal", - false - ], - [ - "Evening", - "Mopping", - true - ] - ], - "Wednesday": [ - [ - "Morning", - "Washing Clothes", - false - ], - [ - "Evening", - "Vacuum", - false - ] - ], - "Thursday": [ - [ - "Morning", - "Cook Meal", - true - ], - [ - "Evening", - "Mopping", - true - ] - ], - "Friday": [ - [ - "Morning", - "Washing Clothes", - true - ], - [ - "Evening", - "Deep Cleaning", - false - ] - ] - } -} diff --git a/sdk/python/examples/community/mind_queue/main.py b/sdk/python/examples/community/mind_queue/main.py index 285ca43de0..53f785787c 100644 --- a/sdk/python/examples/community/mind_queue/main.py +++ b/sdk/python/examples/community/mind_queue/main.py @@ -6,7 +6,7 @@ import flet as ft APP_NAME = "Mind Queue" -DATA_FILE = Path(__file__).resolve().parent / "data.json" +DATA_FILE = Path(__file__).resolve().parent / "assets" / "data.json" def load_data(): @@ -25,7 +25,7 @@ def main(page: ft.Page): page.title = APP_NAME page.theme_mode = ft.ThemeMode.DARK page.bgcolor = "#111111" - page.padding = ft.padding.symmetric(horizontal=24, vertical=24) + page.padding = ft.Padding.symmetric(horizontal=24, vertical=24) page.horizontal_alignment = ft.CrossAxisAlignment.START page.vertical_alignment = ft.MainAxisAlignment.START page.scroll = ft.ScrollMode.HIDDEN @@ -165,7 +165,7 @@ async def do_clone(e): [ft.Text(system_name, size=18, weight=ft.FontWeight.W_600)], ), padding=10, - margin=ft.margin.only(bottom=8), + margin=ft.Margin.only(bottom=8), border_radius=8, bgcolor="#1c1c1c", ), @@ -221,15 +221,17 @@ def on_add(ev): ) page.add( - ft.Column( - [ - title, - ft.Column(systems_list, spacing=4), - ft.Container(height=14), - add_system_btn, - ], - spacing=12, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ft.SafeArea( + content=ft.Column( + [ + title, + ft.Column(systems_list, spacing=4), + ft.Container(height=14), + add_system_btn, + ], + spacing=12, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ) ) ) page.update() @@ -593,7 +595,7 @@ def do_cancel(ev): for idx, (title_str, label, done) in enumerate(tasks): current_index = idx # capture for lambdas - color = ft.Colors.WHITE70 if done else ft.Colors.WHITE + color = ft.Colors.WHITE_70 if done else ft.Colors.WHITE deco = ( ft.TextDecoration.LINE_THROUGH if done else ft.TextDecoration.NONE ) @@ -696,7 +698,9 @@ def do_cancel(ev): ) ) - page.add(ft.Column(content_controls, spacing=6, expand=True)) + page.add( + ft.SafeArea(content=ft.Column(content_controls, spacing=6, expand=True)) + ) page.update() # start at dashboard diff --git a/sdk/python/examples/community/mind_queue/pyproject.toml b/sdk/python/examples/community/mind_queue/pyproject.toml new file mode 100644 index 0000000000..4a8236cf94 --- /dev/null +++ b/sdk/python/examples/community/mind_queue/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "community-mind-queue" +version = "1.0.0" +description = "Community productivity app for organizing systems, headers, and tasks with local JSON storage." +requires-python = ">=3.10" +keywords = ["community", "productivity", "tasks", "json storage", "dialogs"] +authors = [{ name = "Flet community", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Community/Productivity"] + +[tool.flet.metadata] +title = "Mind Queue" +controls = ["SafeArea", "Column", "Row", "Text", "TextField", "Checkbox", "FilledButton", "IconButton", "AlertDialog", "AppBar"] +layout_pattern = "list-detail" +complexity = "intermediate" +features = ["task organization", "local persistence", "dialogs"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh index 6450e1eac6..dd6e97bb0b 100644 --- a/sdk/python/examples/publish-gallery.sh +++ b/sdk/python/examples/publish-gallery.sh @@ -4,7 +4,7 @@ flet publish apps/todo/basic/main.py --distpath $DIST_PATH/todo --base-url todo flet publish apps/icons_browser/main.py --distpath $DIST_PATH/icons_browser --base-url icons_browser --app-name "Flet Icons Browser" --app-description "Quickly search through icons collection to use in your app." flet publish tutorials/calculator/calc.py --distpath $DIST_PATH/calculator --base-url calculator --app-name "Calculator" --app-description "A simple calculator app written in Flet." flet publish tutorials/solitaire_declarative/solitaire-final/main.py --distpath $DIST_PATH/solitaire --base-url solitaire --assets assets --app-name "Solitaire" --app-description "Learn how to handle gestures and position controls on a page." -flet publish apps/trolli-declarative/src/main.py --distpath $DIST_PATH/trolli --base-url trolli --assets assets --route-url-strategy "hash" --app-name "Trolli" --app-description "A clone of Trello." +flet publish apps/declarative/trolli/main.py --distpath $DIST_PATH/trolli --base-url trolli --assets assets --route-url-strategy "hash" --app-name "Trolli" --app-description "A clone of Trello." flet publish apps/routing_navigation/home_store/main.py --distpath $DIST_PATH/simple_routing --base-url simple_routing --route-url-strategy "hash" --app-name "Flet routing example" --app-description "An example of routing in Flet." flet publish apps/counter/basic/main.py --distpath $DIST_PATH/counter --base-url counter --app-name "Counter" --app-description "Counter to get an idea of Flet." flet publish apps/flet_animation/main.py --distpath $DIST_PATH/flet_animation --base-url flet_animation --app-name "Flet animation" --app-description "An example of implicit animations in Flet."

h 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 literal 30668 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 diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/handling_events3.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/handling_events3.png index 853e937fe6b03425b072bad98e37ab369edc5a27..52271a1a6497dbf7de98ee353f51f362d8f25795 100644 GIT binary patch literal 31939 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 literal 31601 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 OC@HAlF8JsEv;P4d3Kb^+ diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/range_slider/image_for_docs.png index b83f588c2e6a17f35624349dccda10e54ffb566b..a0a2fcb0f71fa47d282538765207dd5505369f6e 100644 GIT binary patch literal 3337 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 af>1?pY_0uKEA^BJ+$Adq6z!tVzyAlPP2aEp diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_radio.py b/sdk/python/packages/flet/integration_tests/examples/material/test_radio.py index e2e97f9794..d17b6f9ccd 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_radio.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_radio.py @@ -2,8 +2,10 @@ import flet as ft import flet.testing as ftt - -from examples.controls.radio import basic, handling_selection_changes +from examples.controls.radio.basic.main import main as basic +from examples.controls.radio.handling_selection_changes.main import ( + main as handling_selection_changes, +) @pytest.mark.asyncio(loop_scope="function") @@ -24,7 +26,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": basic.main}], + [{"flet_app_main": basic}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") @@ -46,7 +48,7 @@ async def test_basic(flet_app_function: ftt.FletTestApp): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": handling_selection_changes.main}], + [{"flet_app_main": handling_selection_changes}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_range_slider.py b/sdk/python/packages/flet/integration_tests/examples/material/test_range_slider.py index 58cfeb4ee8..f6f8fedbba 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_range_slider.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_range_slider.py @@ -2,8 +2,10 @@ import flet as ft import flet.testing as ftt - -from examples.controls.range_slider import basic, handling_change_events +from examples.controls.range_slider.basic.main import main as basic +from examples.controls.range_slider.handling_change_events.main import ( + main as handling_change_events, +) @pytest.mark.asyncio(loop_scope="function") @@ -23,7 +25,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": basic.main}], + [{"flet_app_main": basic}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") @@ -64,7 +66,7 @@ async def test_basic(flet_app_function: ftt.FletTestApp): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": handling_change_events.main}], + [{"flet_app_main": handling_change_events}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") From ca9d28f1027f98e07a08ee0ed948d2da432ba4ea Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 16 Mar 2026 18:23:46 -0700 Subject: [PATCH 66/96] Restructure examples: add main.py and pyproject Refactor Python example packages: replace top-level example scripts with standardized entry points (main.py) and add pyproject.toml metadata for responsive_row, rotated_box and rive examples. Wrap example UIs in SafeArea, move/rename assets (vehicles.riv -> example_1/assets), and remove the old example files. Update docs to reference the new example paths and fix integration tests to import the new main functions. --- .../controls/responsive_row/__init__.py | 0 .../examples/controls/responsive_row/basic.py | 82 ------------ .../controls/responsive_row/basic/main.py | 86 +++++++++++++ .../responsive_row/basic/pyproject.toml | 26 ++++ .../responsive_row/custom_breakpoint.py | 103 --------------- .../responsive_row/custom_breakpoint/main.py | 120 ++++++++++++++++++ .../custom_breakpoint/pyproject.toml | 26 ++++ .../examples/controls/rive/example_1.py | 22 ---- .../rive/{ => example_1}/assets/vehicles.riv | Bin .../examples/controls/rive/example_1/main.py | 29 +++++ .../controls/rive/example_1/pyproject.toml | 26 ++++ .../examples/controls/rotated_box/__init__.py | 0 .../examples/controls/rotated_box/basic.py | 87 ------------- .../controls/rotated_box/basic/main.py | 98 ++++++++++++++ .../controls/rotated_box/basic/pyproject.toml | 39 ++++++ .../flet/docs/controls/layoutcontrol.md | 2 +- .../flet/docs/controls/responsiverow.md | 4 +- .../packages/flet/docs/controls/rotatedbox.md | 2 +- .../examples/core/test_responsive_row.py | 5 +- .../examples/core/test_rotated_box.py | 2 +- 20 files changed, 459 insertions(+), 300 deletions(-) delete mode 100644 sdk/python/examples/controls/responsive_row/__init__.py delete mode 100644 sdk/python/examples/controls/responsive_row/basic.py create mode 100644 sdk/python/examples/controls/responsive_row/basic/main.py create mode 100644 sdk/python/examples/controls/responsive_row/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/responsive_row/custom_breakpoint.py create mode 100644 sdk/python/examples/controls/responsive_row/custom_breakpoint/main.py create mode 100644 sdk/python/examples/controls/responsive_row/custom_breakpoint/pyproject.toml delete mode 100644 sdk/python/examples/controls/rive/example_1.py rename sdk/python/examples/controls/rive/{ => example_1}/assets/vehicles.riv (100%) create mode 100644 sdk/python/examples/controls/rive/example_1/main.py create mode 100644 sdk/python/examples/controls/rive/example_1/pyproject.toml delete mode 100644 sdk/python/examples/controls/rotated_box/__init__.py delete mode 100644 sdk/python/examples/controls/rotated_box/basic.py create mode 100644 sdk/python/examples/controls/rotated_box/basic/main.py create mode 100644 sdk/python/examples/controls/rotated_box/basic/pyproject.toml diff --git a/sdk/python/examples/controls/responsive_row/__init__.py b/sdk/python/examples/controls/responsive_row/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/responsive_row/basic.py b/sdk/python/examples/controls/responsive_row/basic.py deleted file mode 100644 index 099d098c73..0000000000 --- a/sdk/python/examples/controls/responsive_row/basic.py +++ /dev/null @@ -1,82 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_page_resize(e: ft.PageResizeEvent): - pw.value = f"{page.width} px" - pw.update() - page.update() - - page.on_resize = handle_page_resize - - pw = ft.Text(text_align=ft.TextAlign.END, style=ft.TextTheme.display_small) - # page.overlay.append(pw) - - page.add( - ft.ResponsiveRow( - controls=[ - ft.Container( - content=ft.Text("Column 1"), - padding=5, - bgcolor=ft.Colors.YELLOW, - col={ - ft.ResponsiveRowBreakpoint.XS: 12, - ft.ResponsiveRowBreakpoint.MD: 6, - ft.ResponsiveRowBreakpoint.LG: 3, - }, - ), - ft.Container( - content=ft.Text("Column 2"), - padding=5, - bgcolor=ft.Colors.GREEN, - col={ - ft.ResponsiveRowBreakpoint.XS: 12, - ft.ResponsiveRowBreakpoint.MD: 6, - ft.ResponsiveRowBreakpoint.LG: 3, - }, - ), - ft.Container( - content=ft.Text("Column 3"), - padding=5, - bgcolor=ft.Colors.BLUE, - col={ - ft.ResponsiveRowBreakpoint.XS: 12, - ft.ResponsiveRowBreakpoint.MD: 6, - ft.ResponsiveRowBreakpoint.LG: 3, - }, - ), - ft.Container( - content=ft.Text("Column 4"), - padding=5, - bgcolor=ft.Colors.PINK_300, - col={ - ft.ResponsiveRowBreakpoint.XS: 12, - ft.ResponsiveRowBreakpoint.MD: 6, - ft.ResponsiveRowBreakpoint.LG: 3, - }, - ), - ], - ), - ft.ResponsiveRow( - run_spacing={ft.ResponsiveRowBreakpoint.XS: 10}, - controls=[ - ft.TextField( - label="TextField 1", - col={ft.ResponsiveRowBreakpoint.MD: 4}, - ), - ft.TextField( - label="TextField 2", - col={ft.ResponsiveRowBreakpoint.MD: 4}, - ), - ft.TextField( - label="TextField 3", - col={ft.ResponsiveRowBreakpoint.MD: 4}, - ), - ], - ), - pw, - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/responsive_row/basic/main.py b/sdk/python/examples/controls/responsive_row/basic/main.py new file mode 100644 index 0000000000..3ae27d498f --- /dev/null +++ b/sdk/python/examples/controls/responsive_row/basic/main.py @@ -0,0 +1,86 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_page_resize(e: ft.PageResizeEvent): + pw.value = f"{page.width} px" + pw.update() + + page.on_resize = handle_page_resize + + pw = ft.Text(text_align=ft.TextAlign.END, style=ft.TextTheme.display_small) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.ResponsiveRow( + controls=[ + ft.Container( + content=ft.Text("Column 1"), + padding=5, + bgcolor=ft.Colors.YELLOW, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ), + ft.Container( + content=ft.Text("Column 2"), + padding=5, + bgcolor=ft.Colors.GREEN, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ), + ft.Container( + content=ft.Text("Column 3"), + padding=5, + bgcolor=ft.Colors.BLUE, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ), + ft.Container( + content=ft.Text("Column 4"), + padding=5, + bgcolor=ft.Colors.PINK_300, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ), + ], + ), + ft.ResponsiveRow( + run_spacing={ft.ResponsiveRowBreakpoint.XS: 10}, + controls=[ + ft.TextField( + label="TextField 1", + col={ft.ResponsiveRowBreakpoint.MD: 4}, + ), + ft.TextField( + label="TextField 2", + col={ft.ResponsiveRowBreakpoint.MD: 4}, + ), + ft.TextField( + label="TextField 3", + col={ft.ResponsiveRowBreakpoint.MD: 4}, + ), + ], + ), + pw, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/responsive_row/basic/pyproject.toml b/sdk/python/examples/controls/responsive_row/basic/pyproject.toml new file mode 100644 index 0000000000..3651bdfbd5 --- /dev/null +++ b/sdk/python/examples/controls/responsive_row/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "responsive-row-basic" +version = "1.0.0" +description = "Builds a four-column responsive layout and form row that adapt to breakpoints." +requires-python = ">=3.10" +keywords = ["responsive row", "layout", "breakpoints", "grid", "adaptive columns"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ResponsiveRow"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "TextField", "Text"] +layout_pattern = "responsive-grid" +complexity = "basic" +features = ["responsive columns", "text field reflow", "window-aware spacing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/responsive_row/custom_breakpoint.py b/sdk/python/examples/controls/responsive_row/custom_breakpoint.py deleted file mode 100644 index 54f28a366b..0000000000 --- a/sdk/python/examples/controls/responsive_row/custom_breakpoint.py +++ /dev/null @@ -1,103 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "ResponsiveRow with custom breakpoints" - page.padding = 16 - - breakpoints = { - "phone": 0, - "tablet": 540, - "desktop": 800, - } - - sorted_breakpoints = sorted(breakpoints.items(), key=lambda item: item[1]) - - breakpoint_labels = { - name: ft.Text(f"{name}: \u2265 {value}px", weight=ft.FontWeight.W_500) - for name, value in sorted_breakpoints - } - - width_label = ft.Text() - breakpoint_label = ft.Text() - - def update_status(_=None): - width = ( - (page.window.width if page.window and page.window.width else None) - or page.width - or 0 - ) - width_label.value = f"Page width: {width:.0f}px" - active_breakpoint = max( - (bp for bp, min_width in breakpoints.items() if width >= min_width), - key=lambda bp: breakpoints[bp], - default="phone", - ) - breakpoint_label.value = f"Active breakpoint: {active_breakpoint}" - for name, label in breakpoint_labels.items(): - is_active = name == active_breakpoint - label.color = ft.Colors.BLUE_700 if is_active else None - label.weight = ft.FontWeight.W_700 if is_active else ft.FontWeight.W_400 - label.update() - width_label.update() - breakpoint_label.update() - - page.on_resize = update_status - - page.add( - ft.Text("Resize the window to see custom breakpoints in action."), - ft.Text("Cards switch column spans at phone, tablet, and desktop widths."), - ft.Column( - [ - ft.Text( - "Custom breakpoints (min widths):", - weight=ft.FontWeight.W_600, - ), - ft.Column(list(breakpoint_labels.values()), spacing=2), - ], - spacing=6, - ), - ft.ResponsiveRow( - breakpoints=breakpoints, - columns={"phone": 4, "tablet": 8, "desktop": 12}, - spacing=10, - run_spacing=10, - controls=[ - ft.Container( - content=ft.Text("Card 1", size=16, weight=ft.FontWeight.W_600), - alignment=ft.Alignment.CENTER, - bgcolor=ft.Colors.AMBER_200, - height=60, - col={"phone": 4, "tablet": 4, "desktop": 3}, - ), - ft.Container( - content=ft.Text("Card 2", size=16, weight=ft.FontWeight.W_600), - alignment=ft.Alignment.CENTER, - bgcolor=ft.Colors.GREEN_200, - height=60, - col={"phone": 4, "tablet": 4, "desktop": 3}, - ), - ft.Container( - content=ft.Text("Card 3", size=16, weight=ft.FontWeight.W_600), - alignment=ft.Alignment.CENTER, - bgcolor=ft.Colors.BLUE_200, - height=60, - col={"phone": 4, "tablet": 4, "desktop": 3}, - ), - ft.Container( - content=ft.Text("Card 4", size=16, weight=ft.FontWeight.W_600), - alignment=ft.Alignment.CENTER, - bgcolor=ft.Colors.PINK_200, - height=60, - col={"phone": 4, "tablet": 4, "desktop": 3}, - ), - ], - ), - width_label, - breakpoint_label, - ) - update_status() - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/responsive_row/custom_breakpoint/main.py b/sdk/python/examples/controls/responsive_row/custom_breakpoint/main.py new file mode 100644 index 0000000000..9df8c13beb --- /dev/null +++ b/sdk/python/examples/controls/responsive_row/custom_breakpoint/main.py @@ -0,0 +1,120 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "ResponsiveRow with custom breakpoints" + page.padding = 16 + + breakpoints = { + "phone": 0, + "tablet": 540, + "desktop": 800, + } + + sorted_breakpoints = sorted(breakpoints.items(), key=lambda item: item[1]) + + breakpoint_labels = { + name: ft.Text(f"{name}: >= {value}px", weight=ft.FontWeight.W_500) + for name, value in sorted_breakpoints + } + + width_label = ft.Text() + breakpoint_label = ft.Text() + + def update_status(_=None): + width = ( + (page.window.width if page.window and page.window.width else None) + or page.width + or 0 + ) + width_label.value = f"Page width: {width:.0f}px" + active_breakpoint = max( + (bp for bp, min_width in breakpoints.items() if width >= min_width), + key=lambda bp: breakpoints[bp], + default="phone", + ) + breakpoint_label.value = f"Active breakpoint: {active_breakpoint}" + for name, label in breakpoint_labels.items(): + is_active = name == active_breakpoint + label.color = ft.Colors.BLUE_700 if is_active else None + label.weight = ft.FontWeight.W_700 if is_active else ft.FontWeight.W_400 + label.update() + width_label.update() + breakpoint_label.update() + + page.on_resize = update_status + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Resize the window to see custom breakpoints in action."), + ft.Text( + "Cards switch column spans at phone, tablet, and " + "desktop widths." + ), + ft.Column( + [ + ft.Text( + "Custom breakpoints (min widths):", + weight=ft.FontWeight.W_600, + ), + ft.Column(list(breakpoint_labels.values()), spacing=2), + ], + spacing=6, + ), + ft.ResponsiveRow( + breakpoints=breakpoints, + columns={"phone": 4, "tablet": 8, "desktop": 12}, + spacing=10, + run_spacing=10, + controls=[ + ft.Container( + content=ft.Text( + "Card 1", size=16, weight=ft.FontWeight.W_600 + ), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.AMBER_200, + height=60, + col={"phone": 4, "tablet": 4, "desktop": 3}, + ), + ft.Container( + content=ft.Text( + "Card 2", size=16, weight=ft.FontWeight.W_600 + ), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.GREEN_200, + height=60, + col={"phone": 4, "tablet": 4, "desktop": 3}, + ), + ft.Container( + content=ft.Text( + "Card 3", size=16, weight=ft.FontWeight.W_600 + ), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.BLUE_200, + height=60, + col={"phone": 4, "tablet": 4, "desktop": 3}, + ), + ft.Container( + content=ft.Text( + "Card 4", size=16, weight=ft.FontWeight.W_600 + ), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.PINK_200, + height=60, + col={"phone": 4, "tablet": 4, "desktop": 3}, + ), + ], + ), + width_label, + breakpoint_label, + ] + ) + ) + ) + update_status() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/responsive_row/custom_breakpoint/pyproject.toml b/sdk/python/examples/controls/responsive_row/custom_breakpoint/pyproject.toml new file mode 100644 index 0000000000..8cb8f41ecb --- /dev/null +++ b/sdk/python/examples/controls/responsive_row/custom_breakpoint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "responsive-row-custom-breakpoint" +version = "1.0.0" +description = "Shows custom breakpoint values and column layouts for ResponsiveRow." +requires-python = ">=3.10" +keywords = ["responsive row", "custom breakpoints", "layout", "adaptive UI"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ResponsiveRow"] + +[tool.flet.metadata] +title = "Custom Breakpoints" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "Text", "TextField"] +layout_pattern = "responsive-dashboard" +complexity = "basic" +features = ["custom breakpoints", "adaptive columns", "resize indicator"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/rive/example_1.py b/sdk/python/examples/controls/rive/example_1.py deleted file mode 100644 index e1aec8addc..0000000000 --- a/sdk/python/examples/controls/rive/example_1.py +++ /dev/null @@ -1,22 +0,0 @@ -import flet as ft -import flet_rive as ftr - - -def main(page: ft.Page): - page.add( - ftr.Rive( - src="https://cdn.rive.app/animations/vehicles.riv", - placeholder=ft.ProgressBar(), - width=300, - height=200, - ), - ftr.Rive( - src="vehicles.riv", - placeholder=ft.ProgressBar(), - width=300, - height=200, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/rive/assets/vehicles.riv b/sdk/python/examples/controls/rive/example_1/assets/vehicles.riv similarity index 100% rename from sdk/python/examples/controls/rive/assets/vehicles.riv rename to sdk/python/examples/controls/rive/example_1/assets/vehicles.riv diff --git a/sdk/python/examples/controls/rive/example_1/main.py b/sdk/python/examples/controls/rive/example_1/main.py new file mode 100644 index 0000000000..689775fe3c --- /dev/null +++ b/sdk/python/examples/controls/rive/example_1/main.py @@ -0,0 +1,29 @@ +import flet as ft +import flet_rive as ftr + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ftr.Rive( + src="https://cdn.rive.app/animations/vehicles.riv", + placeholder=ft.ProgressBar(), + width=300, + height=200, + ), + ftr.Rive( + src="vehicles.riv", + placeholder=ft.ProgressBar(), + width=300, + height=200, + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/rive/example_1/pyproject.toml b/sdk/python/examples/controls/rive/example_1/pyproject.toml new file mode 100644 index 0000000000..3198cd20b2 --- /dev/null +++ b/sdk/python/examples/controls/rive/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "rive-example-1" +version = "1.0.0" +description = "Plays a remote Rive animation and a local Rive asset." +requires-python = ">=3.10" +keywords = ["rive", "animation", "extension", "assets", "local file", "remote file"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-rive"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Rive"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "Column", "Rive", "ProgressBar"] +layout_pattern = "media-showcase" +complexity = "basic" +features = ["remote animations", "local asset playback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/rotated_box/__init__.py b/sdk/python/examples/controls/rotated_box/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/rotated_box/basic.py b/sdk/python/examples/controls/rotated_box/basic.py deleted file mode 100644 index 5faad3fbd5..0000000000 --- a/sdk/python/examples/controls/rotated_box/basic.py +++ /dev/null @@ -1,87 +0,0 @@ -import flet as ft - - -def _demo_control(content: ft.Control) -> ft.Container: - return ft.Container( - padding=10, - border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), - border_radius=8, - content=content, - ) - - -def _lane(title: str, controls: list[ft.Control]) -> ft.Container: - return ft.Container( - width=540, - padding=12, - border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), - border_radius=12, - content=ft.Column( - spacing=8, - controls=[ - ft.Text(title, size=16, weight=ft.FontWeight.BOLD), - ft.Divider(height=1), - ft.Row( - spacing=14, - vertical_alignment=ft.CrossAxisAlignment.START, - controls=controls, - ), - ], - ), - ) - - -def main(page: ft.Page): - page.padding = 24 - page.scroll = ft.ScrollMode.AUTO - page.add( - ft.Text( - "RotatedBox rotates before layout. Compare occupied space below:", - size=16, - weight=ft.FontWeight.W_500, - ), - ft.Column( - spacing=16, - controls=[ - _lane( - "Normal controls", - [ - _demo_control(ft.Text("Text", size=26)), - _demo_control( - ft.ProgressBar(width=170, value=0.65, color=ft.Colors.GREEN) - ), - _demo_control(ft.Button("Button")), - ], - ), - _lane( - "RotatedBox quarter_turns=1", - [ - _demo_control( - ft.RotatedBox( - quarter_turns=1, - content=ft.Text("Text", size=26), - ) - ), - _demo_control( - ft.RotatedBox( - quarter_turns=1, - content=ft.ProgressBar( - width=170, value=0.65, color=ft.Colors.GREEN - ), - ) - ), - _demo_control( - ft.RotatedBox( - quarter_turns=1, - content=ft.Button("Button"), - ) - ), - ], - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/rotated_box/basic/main.py b/sdk/python/examples/controls/rotated_box/basic/main.py new file mode 100644 index 0000000000..3b93edb5cc --- /dev/null +++ b/sdk/python/examples/controls/rotated_box/basic/main.py @@ -0,0 +1,98 @@ +import flet as ft + + +def _demo_control(content: ft.Control) -> ft.Container: + return ft.Container( + padding=10, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=8, + content=content, + ) + + +def _lane(title: str, controls: list[ft.Control]) -> ft.Container: + return ft.Container( + width=540, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=12, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(title, size=16, weight=ft.FontWeight.BOLD), + ft.Divider(height=1), + ft.Row( + spacing=14, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=controls, + ), + ], + ), + ) + + +def main(page: ft.Page): + page.padding = 24 + page.scroll = ft.ScrollMode.AUTO + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "RotatedBox rotates before layout. Compare occupied " + "space below:", + size=16, + weight=ft.FontWeight.W_500, + ), + ft.Column( + spacing=16, + controls=[ + _lane( + "Normal controls", + [ + _demo_control(ft.Text("Text", size=26)), + _demo_control( + ft.ProgressBar( + width=170, value=0.65, color=ft.Colors.GREEN + ) + ), + _demo_control(ft.Button("Button")), + ], + ), + _lane( + "RotatedBox quarter_turns=1", + [ + _demo_control( + ft.RotatedBox( + quarter_turns=1, + content=ft.Text("Text", size=26), + ) + ), + _demo_control( + ft.RotatedBox( + quarter_turns=1, + content=ft.ProgressBar( + width=170, + value=0.65, + color=ft.Colors.GREEN, + ), + ) + ), + _demo_control( + ft.RotatedBox( + quarter_turns=1, + content=ft.Button("Button"), + ) + ), + ], + ), + ], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/rotated_box/basic/pyproject.toml b/sdk/python/examples/controls/rotated_box/basic/pyproject.toml new file mode 100644 index 0000000000..302a2e7cf6 --- /dev/null +++ b/sdk/python/examples/controls/rotated_box/basic/pyproject.toml @@ -0,0 +1,39 @@ +[project] +name = "rotated-box-basic" +version = "1.0.0" +description = "Compares normal layouted controls with quarter_turns RotatedBox rendering." +requires-python = ">=3.10" +keywords = ["rotated box", "layout", "rotation", "transform", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/RotatedBox"] + +[tool.flet.metadata] +title = "Basic" +controls = [ + "SafeArea", + "Column", + "Row", + "Container", + "RotatedBox", + "Text", + "Button", + "ProgressBar", +] +layout_pattern = "compare-layout" +complexity = "basic" +features = [ + "rotation before layout", + "visual space comparison", + "before-after examples", +] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/layoutcontrol.md b/sdk/python/packages/flet/docs/controls/layoutcontrol.md index 280d534585..b63260cb8e 100644 --- a/sdk/python/packages/flet/docs/controls/layoutcontrol.md +++ b/sdk/python/packages/flet/docs/controls/layoutcontrol.md @@ -28,7 +28,7 @@ example_images_examples: ../test-images/examples/core/golden/macos/layout_contro ### RotatedBox ```python ---8<-- "../../examples/controls/rotated_box/basic.py" +--8<-- "../../examples/controls/rotated_box/basic/main.py" ``` {{ image("../test-images/controls/core/golden/macos/rotated_box/rotated_box.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/responsiverow.md b/sdk/python/packages/flet/docs/controls/responsiverow.md index d7234dd535..9ca9174893 100644 --- a/sdk/python/packages/flet/docs/controls/responsiverow.md +++ b/sdk/python/packages/flet/docs/controls/responsiverow.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/core/golden/macos/responsive_row ### ResponsiveRow ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.gif", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../test-images/examples/core/golden/macos/responsive_row ### Custom breakpoints ```python ---8<-- "{{ examples }}/custom_breakpoint.py" +--8<-- "{{ examples }}/custom_breakpoint/main.py" ``` {{ image(example_images + "/custom_breakpoint.gif", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/rotatedbox.md b/sdk/python/packages/flet/docs/controls/rotatedbox.md index 0a5714bfea..902608fcb2 100644 --- a/sdk/python/packages/flet/docs/controls/rotatedbox.md +++ b/sdk/python/packages/flet/docs/controls/rotatedbox.md @@ -9,7 +9,7 @@ example_images: ../test-images/examples/core/golden/macos/rotated_box ## Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/rotated_box.png", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_responsive_row.py b/sdk/python/packages/flet/integration_tests/examples/core/test_responsive_row.py index 04aa4f0b32..22f295ac83 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_responsive_row.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_responsive_row.py @@ -4,7 +4,10 @@ import flet as ft import flet.testing as ftt -from examples.controls.responsive_row import basic, custom_breakpoint +from examples.controls.responsive_row.basic.main import main as basic +from examples.controls.responsive_row.custom_breakpoint.main import ( + main as custom_breakpoint, +) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_rotated_box.py b/sdk/python/packages/flet/integration_tests/examples/core/test_rotated_box.py index a7074cb8e7..1cf26aded4 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_rotated_box.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_rotated_box.py @@ -1,7 +1,7 @@ import pytest import flet.testing as ftt -from examples.controls.rotated_box import basic +from examples.controls.rotated_box.basic.main import main as basic @pytest.mark.parametrize( From 1bec705ee1b258688fdd7e5a88574c0bc716e590 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 24 Mar 2026 15:46:08 -0700 Subject: [PATCH 67/96] Consolidate example scripts and tweak examples Remove standalone example modules and consolidate examples into their main.py counterparts. Deleted legacy single-file examples: sdk/python/examples/controls/map/multi_layers.py, sdk/python/examples/controls/reorderable_drag_handle/basic.py, and sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py. Updated corresponding main.py files to: use the memomaps tile URL for the map example, add a clarifying comment in on_reorder handlers, and adjust the horizontal/vertical reorderable list layout formatting. These changes clean up duplicate files and clarify reorder behavior in the examples. --- .../examples/controls/map/multi_layers.py | 132 ------------------ .../controls/map/multi_layers/main.py | 4 +- .../controls/reorderable_drag_handle/basic.py | 31 ---- .../reorderable_drag_handle/basic/main.py | 1 + .../horizontal_and_vertical.py | 51 ------- .../horizontal_and_vertical/main.py | 4 +- 6 files changed, 5 insertions(+), 218 deletions(-) delete mode 100644 sdk/python/examples/controls/map/multi_layers.py delete mode 100644 sdk/python/examples/controls/reorderable_drag_handle/basic.py delete mode 100644 sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py diff --git a/sdk/python/examples/controls/map/multi_layers.py b/sdk/python/examples/controls/map/multi_layers.py deleted file mode 100644 index 50dc80699e..0000000000 --- a/sdk/python/examples/controls/map/multi_layers.py +++ /dev/null @@ -1,132 +0,0 @@ -import random - -import flet as ft -import flet_map as ftm - - -def main(page: ft.Page): - def handle_tap(e: ftm.MapTapEvent): - if e.name == "tap": - marker_layer.markers.append( - ftm.Marker( - content=ft.Icon( - ft.Icons.LOCATION_ON, color=ft.CupertinoColors.DESTRUCTIVE_RED - ), - coordinates=e.coordinates, - ) - ) - elif e.name == "secondary_tap": - circle_layer.circles.append( - ftm.CircleMarker( - radius=random.randint(5, 10), - coordinates=e.coordinates, - color=ft.Colors.random(), - border_color=ft.Colors.random(), - border_stroke_width=4, - ) - ) - page.update() - - page.appbar = ft.AppBar(title="Multiple Layers") - page.add( - ft.Text("Click anywhere to add a Marker, right-click to add a CircleMarker."), - ftm.Map( - expand=True, - initial_center=ftm.MapLatitudeLongitude(15, 10), - initial_zoom=4.2, - interaction_configuration=ftm.InteractionConfiguration( - flags=ftm.InteractionFlag.ALL - ), - on_tap=handle_tap, - on_secondary_tap=handle_tap, - on_event=print, - layers=[ - ftm.TileLayer( - url_template="https://tile.memomaps.de/tilegen/{z}/{x}/{y}.png", - on_image_error=lambda e: print("TileLayer Error"), - ), - ftm.RichAttribution( - attributions=[ - ftm.TextSourceAttribution( - text="OpenStreetMap Contributors", - on_click=lambda e: e.page.launch_url( - "https://www.openstreetmap.org/copyright" - ), - ), - ftm.TextSourceAttribution( - text="Flet", - on_click=lambda e: e.page.launch_url("https://flet.dev"), - ), - ] - ), - ftm.SimpleAttribution( - text="Flet", - alignment=ft.Alignment.TOP_RIGHT, - on_click=lambda e: print("Clicked SimpleAttribution"), - ), - marker_layer := ftm.MarkerLayer( - markers=[ - ftm.Marker( - content=ft.Icon(ft.Icons.LOCATION_ON), - coordinates=ftm.MapLatitudeLongitude(30, 15), - ), - ftm.Marker( - content=ft.Icon(ft.Icons.LOCATION_ON), - coordinates=ftm.MapLatitudeLongitude(10, 10), - ), - ftm.Marker( - content=ft.Icon(ft.Icons.LOCATION_ON), - coordinates=ftm.MapLatitudeLongitude(25, 45), - ), - ], - ), - circle_layer := ftm.CircleLayer( - circles=[ - ftm.CircleMarker( - radius=10, - coordinates=ftm.MapLatitudeLongitude(16, 24), - color=ft.Colors.RED, - border_color=ft.Colors.BLUE, - border_stroke_width=4, - ), - ], - ), - ftm.PolygonLayer( - polygons=[ - ftm.PolygonMarker( - label="Popular Touristic Area", - label_text_style=ft.TextStyle( - color=ft.Colors.BLACK, - size=15, - weight=ft.FontWeight.BOLD, - ), - color=ft.Colors.with_opacity(0.3, ft.Colors.BLUE), - coordinates=[ - ftm.MapLatitudeLongitude(10, 10), - ftm.MapLatitudeLongitude(30, 15), - ftm.MapLatitudeLongitude(25, 45), - ], - ), - ], - ), - ftm.PolylineLayer( - polylines=[ - ftm.PolylineMarker( - border_stroke_width=3, - border_color=ft.Colors.RED, - gradient_colors=[ft.Colors.BLACK, ft.Colors.BLACK], - color=ft.Colors.with_opacity(0.6, ft.Colors.GREEN), - coordinates=[ - ftm.MapLatitudeLongitude(10, 10), - ftm.MapLatitudeLongitude(30, 15), - ftm.MapLatitudeLongitude(25, 45), - ], - ), - ], - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/map/multi_layers/main.py b/sdk/python/examples/controls/map/multi_layers/main.py index e057bfffe0..693cb9716f 100644 --- a/sdk/python/examples/controls/map/multi_layers/main.py +++ b/sdk/python/examples/controls/map/multi_layers/main.py @@ -50,7 +50,7 @@ def handle_tap(e: ftm.MapTapEvent): on_event=print, layers=[ ftm.TileLayer( - url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + url_template="https://tile.memomaps.de/tilegen/{z}/{x}/{y}.png", on_image_error=lambda e: print("TileLayer Error"), ), ftm.RichAttribution( @@ -145,7 +145,7 @@ def handle_tap(e: ftm.MapTapEvent): ), ], ), - ), + ) ) diff --git a/sdk/python/examples/controls/reorderable_drag_handle/basic.py b/sdk/python/examples/controls/reorderable_drag_handle/basic.py deleted file mode 100644 index fc14b5f182..0000000000 --- a/sdk/python/examples/controls/reorderable_drag_handle/basic.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def on_reorder(e: ft.OnReorderEvent): - # Reorder controls list to match the UI change - e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) - - page.add( - ft.ReorderableListView( - expand=True, - show_default_drag_handles=False, - on_reorder=on_reorder, - controls=[ - ft.ListTile( - title=ft.Text(f"Draggable Item {i}", color=ft.Colors.BLACK), - leading=ft.ReorderableDragHandle( - content=ft.Icon(ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED), - mouse_cursor=ft.MouseCursor.GRAB, - ), - bgcolor=ft.Colors.ERROR - if i % 2 == 0 - else ft.Colors.ON_ERROR_CONTAINER, - ) - for i in range(10) - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/reorderable_drag_handle/basic/main.py b/sdk/python/examples/controls/reorderable_drag_handle/basic/main.py index 25763561ae..373661436d 100644 --- a/sdk/python/examples/controls/reorderable_drag_handle/basic/main.py +++ b/sdk/python/examples/controls/reorderable_drag_handle/basic/main.py @@ -3,6 +3,7 @@ def main(page: ft.Page): def on_reorder(e: ft.OnReorderEvent): + # Reorder controls list to match the UI change e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) page.add( diff --git a/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py b/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py deleted file mode 100644 index 3f030d934a..0000000000 --- a/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical.py +++ /dev/null @@ -1,51 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - # the primary color is the color of the reorder handle - page.theme = page.dark_theme = ft.Theme( - color_scheme=ft.ColorScheme(primary=ft.Colors.BLUE) - ) - - def handle_reorder(e: ft.OnReorderEvent): - # Reorder controls list to match the UI change - e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) - - def get_color(i): - return ft.Colors.ERROR if i % 2 == 0 else ft.Colors.ON_ERROR_CONTAINER - - page.add( - # horizontal - ft.ReorderableListView( - expand=True, - horizontal=True, - on_reorder=handle_reorder, - controls=[ - ft.Container( - content=ft.Text(f"Item {i}", color=ft.Colors.BLACK), - bgcolor=get_color(i), - margin=ft.Margin.symmetric(horizontal=5, vertical=10), - width=100, - alignment=ft.Alignment.CENTER, - ) - for i in range(10) - ], - ), - # vertical - ft.ReorderableListView( - expand=True, - on_reorder=handle_reorder, - controls=[ - ft.ListTile( - title=ft.Text(f"Item {i}", color=ft.Colors.BLACK), - leading=ft.Icon(ft.Icons.CHECK, color=ft.Colors.RED), - bgcolor=get_color(i), - ) - for i in range(10) - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical/main.py b/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical/main.py index 1cf746216b..13b121a95a 100644 --- a/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical/main.py +++ b/sdk/python/examples/controls/reorderable_list_view/horizontal_and_vertical/main.py @@ -8,6 +8,7 @@ def main(page: ft.Page): ) def handle_reorder(e: ft.OnReorderEvent): + # Reorder controls list to match the UI change e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) def get_color(i): @@ -17,8 +18,7 @@ def get_color(i): ft.SafeArea( expand=True, content=ft.Column( - controls=[ - # horizontal + [ # horizontal ft.ReorderableListView( expand=True, horizontal=True, From a8223d5f560726c85a2a28fd54995a4820988dc2 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 09:09:17 -0700 Subject: [PATCH 68/96] Reorganize Row examples into modular main files Refactor Row examples: remove legacy top-level scripts and replace each example (alignment, spacing, vertical_alignment, wrap) with a modular package layout containing a main.py and pyproject.toml. Examples are updated to use @ft.control/SafeArea patterns and improved layout code, and integration test imports were updated to the new example paths. This standardizes example metadata for the gallery and tidies up the examples package structure. --- sdk/python/examples/controls/row/__init__.py | 0 sdk/python/examples/controls/row/alignment.py | 48 --------------- .../examples/controls/row/alignment/main.py | 54 +++++++++++++++++ .../controls/row/alignment/pyproject.toml | 26 +++++++++ sdk/python/examples/controls/row/spacing.py | 44 -------------- .../examples/controls/row/spacing/main.py | 50 ++++++++++++++++ .../controls/row/spacing/pyproject.toml | 26 +++++++++ .../controls/row/vertical_alignment.py | 39 ------------- .../controls/row/vertical_alignment/main.py | 50 ++++++++++++++++ .../row/vertical_alignment/pyproject.toml | 26 +++++++++ sdk/python/examples/controls/row/wrap.py | 49 ---------------- sdk/python/examples/controls/row/wrap/main.py | 58 +++++++++++++++++++ .../examples/controls/row/wrap/pyproject.toml | 26 +++++++++ .../examples/core/test_row.py | 5 +- 14 files changed, 320 insertions(+), 181 deletions(-) delete mode 100644 sdk/python/examples/controls/row/__init__.py delete mode 100644 sdk/python/examples/controls/row/alignment.py create mode 100644 sdk/python/examples/controls/row/alignment/main.py create mode 100644 sdk/python/examples/controls/row/alignment/pyproject.toml delete mode 100644 sdk/python/examples/controls/row/spacing.py create mode 100644 sdk/python/examples/controls/row/spacing/main.py create mode 100644 sdk/python/examples/controls/row/spacing/pyproject.toml delete mode 100644 sdk/python/examples/controls/row/vertical_alignment.py create mode 100644 sdk/python/examples/controls/row/vertical_alignment/main.py create mode 100644 sdk/python/examples/controls/row/vertical_alignment/pyproject.toml delete mode 100644 sdk/python/examples/controls/row/wrap.py create mode 100644 sdk/python/examples/controls/row/wrap/main.py create mode 100644 sdk/python/examples/controls/row/wrap/pyproject.toml diff --git a/sdk/python/examples/controls/row/__init__.py b/sdk/python/examples/controls/row/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/row/alignment.py b/sdk/python/examples/controls/row/alignment.py deleted file mode 100644 index 00b25a8bfc..0000000000 --- a/sdk/python/examples/controls/row/alignment.py +++ /dev/null @@ -1,48 +0,0 @@ -import flet as ft - - -class RowWithAlignment(ft.Column): - def __init__(self, alignment: ft.MainAxisAlignment): - super().__init__() - self.controls = [ - ft.Text(str(alignment), size=16), - ft.Container( - content=ft.Row(self.generate_items(3), alignment=alignment), - bgcolor=ft.Colors.AMBER_100, - ), - ] - - @staticmethod - def generate_items(count: int): - return [ - ft.Container( - content=ft.Text(value=str(i)), - alignment=ft.Alignment.CENTER, - width=50, - height=50, - bgcolor=ft.Colors.AMBER_500, - ) - for i in range(1, count + 1) - ] - - -def main(page: ft.Page): - page.scroll = ft.ScrollMode.AUTO - - page.add( - ft.Column( - scroll=ft.ScrollMode.AUTO, - controls=[ - RowWithAlignment(ft.MainAxisAlignment.START), - RowWithAlignment(ft.MainAxisAlignment.CENTER), - RowWithAlignment(ft.MainAxisAlignment.END), - RowWithAlignment(ft.MainAxisAlignment.SPACE_BETWEEN), - RowWithAlignment(ft.MainAxisAlignment.SPACE_AROUND), - RowWithAlignment(ft.MainAxisAlignment.SPACE_EVENLY), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/row/alignment/main.py b/sdk/python/examples/controls/row/alignment/main.py new file mode 100644 index 0000000000..270670e0e3 --- /dev/null +++ b/sdk/python/examples/controls/row/alignment/main.py @@ -0,0 +1,54 @@ +import flet as ft + + +@ft.control +class RowWithAlignment(ft.Column): + alignment: ft.MainAxisAlignment = ft.MainAxisAlignment.START + + def init(self): + self.controls = [ + ft.Text(str(self.alignment), size=16), + ft.Container( + bgcolor=ft.Colors.AMBER_100, + content=ft.Row( + alignment=self.alignment, + controls=self.generate_items(3), + ), + ), + ] + + @staticmethod + def generate_items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER_500, + ) + for i in range(1, count + 1) + ] + + +def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO + page.add( + ft.SafeArea( + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + controls=[ + RowWithAlignment(alignment=ft.MainAxisAlignment.START), + RowWithAlignment(alignment=ft.MainAxisAlignment.CENTER), + RowWithAlignment(alignment=ft.MainAxisAlignment.END), + RowWithAlignment(alignment=ft.MainAxisAlignment.SPACE_BETWEEN), + RowWithAlignment(alignment=ft.MainAxisAlignment.SPACE_AROUND), + RowWithAlignment(alignment=ft.MainAxisAlignment.SPACE_EVENLY), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/row/alignment/pyproject.toml b/sdk/python/examples/controls/row/alignment/pyproject.toml new file mode 100644 index 0000000000..c5be8678a2 --- /dev/null +++ b/sdk/python/examples/controls/row/alignment/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "row-alignment" +version = "1.0.0" +description = "Row main-axis alignment modes demonstrated side by side." +requires-python = ">=3.10" +keywords = ["row", "layout", "alignment", "mainaxisalignment", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Row"] + +[tool.flet.metadata] +title = "Row alignment" +controls = ["Column", "Row", "Container", "Text"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["main axis alignment", "layout comparison", "vertical scrolling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/row/spacing.py b/sdk/python/examples/controls/row/spacing.py deleted file mode 100644 index 007d624484..0000000000 --- a/sdk/python/examples/controls/row/spacing.py +++ /dev/null @@ -1,44 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def generate_items(count: int): - return [ - ft.Container( - content=ft.Text(value=str(i)), - alignment=ft.Alignment.CENTER, - width=50, - height=50, - bgcolor=ft.Colors.AMBER, - border_radius=ft.BorderRadius.all(5), - ) - for i in range(1, count + 1) - ] - - def handle_slider_change(e: ft.Event[ft.Slider]): - row.spacing = int(e.control.value) - row.update() - - page.add( - ft.Column( - controls=[ - ft.Text("Spacing between items"), - ft.Slider( - key="slider", - min=0, - max=50, - divisions=50, - value=0, - label="{value}", - on_change=handle_slider_change, - ), - ] - ), - row := ft.Row( - spacing=0, controls=generate_items(10), scroll=ft.ScrollMode.AUTO - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/row/spacing/main.py b/sdk/python/examples/controls/row/spacing/main.py new file mode 100644 index 0000000000..d0f30660a0 --- /dev/null +++ b/sdk/python/examples/controls/row/spacing/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + def generate_items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER, + border_radius=ft.BorderRadius.all(5), + ) + for i in range(1, count + 1) + ] + + def handle_slider_change(e: ft.Event[ft.Slider]): + row.spacing = int(e.control.value) + row.update() + + row = ft.Row(spacing=0, scroll=ft.ScrollMode.AUTO, controls=generate_items(10)) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + ft.Text("Spacing between items"), + ft.Slider( + key="slider", + min=0, + max=50, + divisions=50, + value=0, + label="{value}", + on_change=handle_slider_change, + ), + ] + ), + row, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/row/spacing/pyproject.toml b/sdk/python/examples/controls/row/spacing/pyproject.toml new file mode 100644 index 0000000000..984bfb5dab --- /dev/null +++ b/sdk/python/examples/controls/row/spacing/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "row-spacing" +version = "1.0.0" +description = "Adjust row spacing interactively with a slider." +requires-python = ">=3.10" +keywords = ["row", "layout", "spacing", "slider", "interactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Row"] + +[tool.flet.metadata] +title = "Row spacing" +controls = ["Column", "Row", "Container", "Text", "Slider"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["slider-driven spacing", "dynamic layout updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/row/vertical_alignment.py b/sdk/python/examples/controls/row/vertical_alignment.py deleted file mode 100644 index 6a4d240a8b..0000000000 --- a/sdk/python/examples/controls/row/vertical_alignment.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -class RowWithVerticalAlignment(ft.Column): - def __init__(self, alignment: ft.CrossAxisAlignment): - super().__init__() - self.controls = [ - ft.Text(str(alignment), size=16), - ft.Container( - content=ft.Row(self.generate_items(3), vertical_alignment=alignment), - bgcolor=ft.Colors.AMBER_100, - height=150, - ), - ] - - @staticmethod - def generate_items(count: int): - return [ - ft.Container( - content=ft.Text(value=str(i)), - alignment=ft.Alignment.CENTER, - width=50, - height=50, - bgcolor=ft.Colors.AMBER_500, - ) - for i in range(1, count + 1) - ] - - -def main(page: ft.Page): - page.add( - RowWithVerticalAlignment(ft.CrossAxisAlignment.START), - RowWithVerticalAlignment(ft.CrossAxisAlignment.CENTER), - RowWithVerticalAlignment(ft.CrossAxisAlignment.END), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/row/vertical_alignment/main.py b/sdk/python/examples/controls/row/vertical_alignment/main.py new file mode 100644 index 0000000000..8a6c45df27 --- /dev/null +++ b/sdk/python/examples/controls/row/vertical_alignment/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +@ft.control +class RowWithVerticalAlignment(ft.Column): + alignment: ft.CrossAxisAlignment = ft.CrossAxisAlignment.START + + def init(self): + self.controls = [ + ft.Text(str(self.alignment), size=16), + ft.Container( + bgcolor=ft.Colors.AMBER_100, + height=150, + content=ft.Row( + vertical_alignment=self.alignment, + controls=self.generate_items(3), + ), + ), + ] + + @staticmethod + def generate_items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER_500, + ) + for i in range(1, count + 1) + ] + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + RowWithVerticalAlignment(alignment=ft.CrossAxisAlignment.START), + RowWithVerticalAlignment(alignment=ft.CrossAxisAlignment.CENTER), + RowWithVerticalAlignment(alignment=ft.CrossAxisAlignment.END), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/row/vertical_alignment/pyproject.toml b/sdk/python/examples/controls/row/vertical_alignment/pyproject.toml new file mode 100644 index 0000000000..a64f580540 --- /dev/null +++ b/sdk/python/examples/controls/row/vertical_alignment/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "row-vertical-alignment" +version = "1.0.0" +description = "Row cross-axis alignment modes with visual comparison." +requires-python = ">=3.10" +keywords = ["row", "layout", "crossaxisalignment", "alignment"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Row"] + +[tool.flet.metadata] +title = "Row vertical alignment" +controls = ["Column", "Row", "Container", "Text"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["cross axis alignment", "layout comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/row/wrap.py b/sdk/python/examples/controls/row/wrap.py deleted file mode 100644 index 19f75886a7..0000000000 --- a/sdk/python/examples/controls/row/wrap.py +++ /dev/null @@ -1,49 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def generate_items(count: int): - return [ - ft.Container( - content=ft.Text(value=str(i)), - alignment=ft.Alignment.CENTER, - width=50, - height=50, - bgcolor=ft.Colors.AMBER, - border_radius=ft.BorderRadius.all(5), - ) - for i in range(1, count + 1) - ] - - def handle_slider_change(e: ft.Event[ft.Slider]): - row.width = float(e.control.value) - row.update() - - page.add( - ft.Column( - controls=[ - ft.Text( - "Change the row width to see how child items wrap onto multiple rows:" - ), - ft.Slider( - min=0, - max=page.window.width, - divisions=20, - value=page.window.width, - label="{value}", - on_change=handle_slider_change, - ), - ] - ), - row := ft.Row( - wrap=True, - spacing=10, - run_spacing=10, - controls=generate_items(30), - width=page.window.width, - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/row/wrap/main.py b/sdk/python/examples/controls/row/wrap/main.py new file mode 100644 index 0000000000..5102616595 --- /dev/null +++ b/sdk/python/examples/controls/row/wrap/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + def generate_items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER, + border_radius=ft.BorderRadius.all(5), + ) + for i in range(1, count + 1) + ] + + def handle_slider_change(e: ft.Event[ft.Slider]): + row.width = float(e.control.value) + row.update() + + row = ft.Row( + wrap=True, + spacing=10, + run_spacing=10, + width=page.window.width, + controls=generate_items(30), + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + ft.Text( + "Change the row width to see how child items wrap " + "onto multiple rows:" + ), + ft.Slider( + min=0, + max=page.window.width, + divisions=20, + value=page.window.width, + label="{value}", + on_change=handle_slider_change, + ), + ] + ), + row, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/row/wrap/pyproject.toml b/sdk/python/examples/controls/row/wrap/pyproject.toml new file mode 100644 index 0000000000..37aefedc32 --- /dev/null +++ b/sdk/python/examples/controls/row/wrap/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "row-wrap" +version = "1.0.0" +description = "Row wrapping behavior controlled by dynamic width." +requires-python = ">=3.10" +keywords = ["row", "layout", "wrap", "slider", "responsive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Row"] + +[tool.flet.metadata] +title = "Row wrapping" +controls = ["Column", "Row", "Container", "Text", "Slider"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["wrap behavior", "width-driven layout", "slider interaction"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_row.py b/sdk/python/packages/flet/integration_tests/examples/core/test_row.py index d0631dc5ad..1055d707fb 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_row.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_row.py @@ -1,8 +1,11 @@ import pytest +import examples.controls.row.alignment.main as alignment +import examples.controls.row.spacing.main as spacing +import examples.controls.row.vertical_alignment.main as vertical_alignment +import examples.controls.row.wrap.main as wrap import flet as ft import flet.testing as ftt -from examples.controls.row import alignment, spacing, vertical_alignment, wrap @pytest.mark.asyncio(loop_scope="function") From 68ea99f5f204a4964f9c5879b3271801252ecd78 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 09:12:55 -0700 Subject: [PATCH 69/96] Refactor SafeArea example and add pyproject Move example file to basic/main.py and refactor the UI: hoist the Text control into a local variable (remove inline walrus assignment) and pass it to the Container so the FloatingActionButton updates the same message. Add an if __name__ == "__main__" guard to avoid running ft.run on import. Add pyproject.toml containing package metadata and Flet gallery configuration for packaging and discovery. --- .../safe_area/{basic.py => basic/main.py} | 6 +++-- .../controls/safe_area/basic/pyproject.toml | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) rename sdk/python/examples/controls/safe_area/{basic.py => basic/main.py} (83%) create mode 100644 sdk/python/examples/controls/safe_area/basic/pyproject.toml diff --git a/sdk/python/examples/controls/safe_area/basic.py b/sdk/python/examples/controls/safe_area/basic/main.py similarity index 83% rename from sdk/python/examples/controls/safe_area/basic.py rename to sdk/python/examples/controls/safe_area/basic/main.py index 649efc1712..85bf4d58ff 100644 --- a/sdk/python/examples/controls/safe_area/basic.py +++ b/sdk/python/examples/controls/safe_area/basic/main.py @@ -7,6 +7,7 @@ class State: def main(page: ft.Page): state = State() + message = ft.Text("0", size=50) def handle_button_click(e: ft.Event[ft.FloatingActionButton]): state.counter += 1 @@ -22,11 +23,12 @@ def handle_button_click(e: ft.Event[ft.FloatingActionButton]): ft.SafeArea( expand=True, content=ft.Container( - message := ft.Text("0", size=50), alignment=ft.Alignment.CENTER, + content=message, ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/safe_area/basic/pyproject.toml b/sdk/python/examples/controls/safe_area/basic/pyproject.toml new file mode 100644 index 0000000000..d4fcdd2bdf --- /dev/null +++ b/sdk/python/examples/controls/safe_area/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "safe-area-basic" +version = "1.0.0" +description = "Keep centered content inside device safe insets while updating a counter." +requires-python = ">=3.10" +keywords = ["safearea", "layout", "counter", "floatingactionbutton", "mobile"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/SafeArea"] + +[tool.flet.metadata] +title = "SafeArea basic" +controls = ["SafeArea", "Container", "Text", "FloatingActionButton"] +layout_pattern = "centered-single-action" +complexity = "basic" +features = ["safe insets", "floating action button", "counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" From 0396ad0460c818462c51cfb4c21a51e4115a8136 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 09:51:36 -0700 Subject: [PATCH 70/96] Refactor screenshot example into packaged example Remove the old single-file example and replace it with a packaged example: add main.py as the new entrypoint (wrapping UI in SafeArea/Column, using Screenshot.content, and an on_click handler that accepts an event), include a pyproject.toml with project and Flet gallery metadata/dependencies, and add a screenshot.png asset. This organizes the example for distribution and gallery integration and makes the script executable with ft.run(main) under __main__. --- .../controls/screenshot/taking_screenshot.py | 24 ------------ .../screenshot/taking_screenshot/main.py | 35 ++++++++++++++++++ .../taking_screenshot/pyproject.toml | 26 +++++++++++++ .../taking_screenshot/screenshot.png | Bin 0 -> 6614 bytes 4 files changed, 61 insertions(+), 24 deletions(-) delete mode 100644 sdk/python/examples/controls/screenshot/taking_screenshot.py create mode 100644 sdk/python/examples/controls/screenshot/taking_screenshot/main.py create mode 100644 sdk/python/examples/controls/screenshot/taking_screenshot/pyproject.toml create mode 100644 sdk/python/examples/controls/screenshot/taking_screenshot/screenshot.png diff --git a/sdk/python/examples/controls/screenshot/taking_screenshot.py b/sdk/python/examples/controls/screenshot/taking_screenshot.py deleted file mode 100644 index 89f32507d1..0000000000 --- a/sdk/python/examples/controls/screenshot/taking_screenshot.py +++ /dev/null @@ -1,24 +0,0 @@ -from pathlib import Path - -import flet as ft -from flet.utils.files import get_current_script_dir - - -def main(page: ft.Page): - async def take_screenshot(): - image = await scr.capture() - with open(Path(get_current_script_dir(), "screenshot.png"), "wb") as f: - f.write(image) - - page.add( - scr := ft.Screenshot( - ft.Container( - ft.Button("Hello, world!", bgcolor=ft.Colors.BLUE, elevation=10), - padding=10, - ) - ), - ft.Button("Take screenshot", on_click=take_screenshot), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/screenshot/taking_screenshot/main.py b/sdk/python/examples/controls/screenshot/taking_screenshot/main.py new file mode 100644 index 0000000000..c61bca220b --- /dev/null +++ b/sdk/python/examples/controls/screenshot/taking_screenshot/main.py @@ -0,0 +1,35 @@ +from pathlib import Path + +import flet as ft +from flet.utils.files import get_current_script_dir + + +def main(page: ft.Page): + async def take_screenshot(e: ft.Event[ft.Button]): + image = await scr.capture() + with open(Path(get_current_script_dir(), "screenshot.png"), "wb") as f: + f.write(image) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + scr := ft.Screenshot( + content=ft.Container( + padding=10, + content=ft.Button( + "Hello, world!", + bgcolor=ft.Colors.BLUE, + elevation=10, + ), + ) + ), + ft.Button("Take screenshot", on_click=take_screenshot), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/screenshot/taking_screenshot/pyproject.toml b/sdk/python/examples/controls/screenshot/taking_screenshot/pyproject.toml new file mode 100644 index 0000000000..d43f346b42 --- /dev/null +++ b/sdk/python/examples/controls/screenshot/taking_screenshot/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "screenshot-taking-screenshot" +version = "1.0.0" +description = "Capture a Screenshot control asynchronously and save the image to a file." +requires-python = ">=3.10" +keywords = ["screenshot", "capture", "button", "async", "file"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Screenshot"] + +[tool.flet.metadata] +title = "Taking screenshot" +controls = ["Screenshot", "Container", "Button", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["async capture", "save to file", "button interaction"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/screenshot/taking_screenshot/screenshot.png b/sdk/python/examples/controls/screenshot/taking_screenshot/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..9000215d7f083e77f1f5ce3d38f190f619b3e1c2 GIT binary patch literal 6614 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 L+KRRE){y@JrJBCn literal 0 HcmV?d00001 From 8a884a855947234c62516c004ddd9b504790e48c Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 10:21:50 -0700 Subject: [PATCH 71/96] Wrap examples in SafeArea and add pyprojects Reorganize several Python example apps: move basic example scripts into main.py, wrap their UI in SafeArea, and add pyproject.toml metadata for search_bar, segmented_button, selection_area, and semantics examples. Remove legacy example files and update integration tests to import the new module paths (e.g. sms.main / basic.main). Also adjust Dart SemanticsControl to build content via control.buildWidget("content") and show an ErrorControl when content is missing; add required imports for control extensions and the ErrorControl widget. --- packages/flet/lib/src/controls/semantics.dart | 5 ++ .../examples/controls/search_bar/__init__.py | 0 .../search_bar/{basic.py => basic/main.py} | 22 +++--- .../controls/search_bar/basic/pyproject.toml | 26 +++++++ .../controls/segmented_button/__init__.py | 0 .../single_multiple_selection.py | 70 ----------------- .../single_multiple_selection/main.py | 76 +++++++++++++++++++ .../single_multiple_selection/pyproject.toml | 26 +++++++ .../controls/selection_area/__init__.py | 0 .../examples/controls/selection_area/basic.py | 41 ---------- .../controls/selection_area/basic/main.py | 48 ++++++++++++ .../selection_area/basic/pyproject.toml | 26 +++++++ .../examples/controls/semantics/basic.py | 30 -------- .../examples/controls/semantics/basic/main.py | 33 ++++++++ .../controls/semantics/basic/pyproject.toml | 26 +++++++ .../examples/material/test_search_bar.py | 2 +- .../material/test_segmented_button.py | 4 +- .../examples/material/test_selection_area.py | 2 +- 18 files changed, 281 insertions(+), 156 deletions(-) delete mode 100644 sdk/python/examples/controls/search_bar/__init__.py rename sdk/python/examples/controls/search_bar/{basic.py => basic/main.py} (73%) create mode 100644 sdk/python/examples/controls/search_bar/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/segmented_button/__init__.py delete mode 100644 sdk/python/examples/controls/segmented_button/single_multiple_selection.py create mode 100644 sdk/python/examples/controls/segmented_button/single_multiple_selection/main.py create mode 100644 sdk/python/examples/controls/segmented_button/single_multiple_selection/pyproject.toml delete mode 100644 sdk/python/examples/controls/selection_area/__init__.py delete mode 100644 sdk/python/examples/controls/selection_area/basic.py create mode 100644 sdk/python/examples/controls/selection_area/basic/main.py create mode 100644 sdk/python/examples/controls/selection_area/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/semantics/basic.py create mode 100644 sdk/python/examples/controls/semantics/basic/main.py create mode 100644 sdk/python/examples/controls/semantics/basic/pyproject.toml diff --git a/packages/flet/lib/src/controls/semantics.dart b/packages/flet/lib/src/controls/semantics.dart index eb93e20657..941ac0a3a8 100644 --- a/packages/flet/lib/src/controls/semantics.dart +++ b/packages/flet/lib/src/controls/semantics.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/numbers.dart'; +import '../widgets/error.dart'; import 'base_controls.dart'; class SemanticsControl extends StatelessWidget { @@ -12,7 +14,10 @@ class SemanticsControl extends StatelessWidget { @override Widget build(BuildContext context) { debugPrint("Semantics build: ${control.id}"); + final content = control.buildWidget("content"); Semantics semantics = Semantics( + child: content ?? + const ErrorControl("Semantics.content must be provided and visible"), label: control.getString("label"), enabled: !control.disabled, expanded: control.getBool("expanded"), diff --git a/sdk/python/examples/controls/search_bar/__init__.py b/sdk/python/examples/controls/search_bar/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/search_bar/basic.py b/sdk/python/examples/controls/search_bar/basic/main.py similarity index 73% rename from sdk/python/examples/controls/search_bar/basic.py rename to sdk/python/examples/controls/search_bar/basic/main.py index 379ea3f330..aabcf48592 100644 --- a/sdk/python/examples/controls/search_bar/basic.py +++ b/sdk/python/examples/controls/search_bar/basic/main.py @@ -41,19 +41,19 @@ def handle_submit(e: ft.Event[ft.SearchBar]): async def handle_tap(e: ft.Event[ft.SearchBar]): await anchor.open_view() - page.add( - anchor := ft.SearchBar( - view_elevation=4, - divider_color=ft.Colors.AMBER, - bar_hint_text="Search colors...", - view_hint_text="Choose a color from the suggestions...", - on_change=handle_change, - on_submit=handle_submit, - on_tap=handle_tap, - controls=build_tiles(colors), - ), + anchor = ft.SearchBar( + view_elevation=4, + divider_color=ft.Colors.AMBER, + bar_hint_text="Search colors...", + view_hint_text="Choose a color from the suggestions...", + on_change=handle_change, + on_submit=handle_submit, + on_tap=handle_tap, + controls=build_tiles(colors), ) + page.add(ft.SafeArea(content=anchor)) + if __name__ == "__main__": ft.run(main) diff --git a/sdk/python/examples/controls/search_bar/basic/pyproject.toml b/sdk/python/examples/controls/search_bar/basic/pyproject.toml new file mode 100644 index 0000000000..12aa2fd6ad --- /dev/null +++ b/sdk/python/examples/controls/search_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "search-bar-basic" +version = "1.0.0" +description = "Search colors with async suggestions shown inside a SearchBar view." +requires-python = ">=3.10" +keywords = ["searchbar", "search", "suggestions", "listtile", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/SearchBar"] + +[tool.flet.metadata] +title = "SearchBar basic" +controls = ["SearchBar", "ListTile", "Text", "SafeArea"] +layout_pattern = "search-overlay" +complexity = "basic" +features = ["async suggestions", "live filtering", "search submit"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/segmented_button/__init__.py b/sdk/python/examples/controls/segmented_button/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/segmented_button/single_multiple_selection.py b/sdk/python/examples/controls/segmented_button/single_multiple_selection.py deleted file mode 100644 index 9a0766eb61..0000000000 --- a/sdk/python/examples/controls/segmented_button/single_multiple_selection.py +++ /dev/null @@ -1,70 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_selection_change(e: ft.Event[ft.SegmentedButton]): - print(e) - - page.add( - ft.SegmentedButton( - on_change=handle_selection_change, - selected_icon=ft.Icon(ft.Icons.CHECK_SHARP), - selected=["1", "4"], - allow_empty_selection=True, - allow_multiple_selection=True, - segments=[ - ft.Segment( - value="1", - label=ft.Text("One"), - icon=ft.Icon(ft.Icons.LOOKS_ONE), - ), - ft.Segment( - value="2", - label=ft.Text("Two"), - icon=ft.Icon(ft.Icons.LOOKS_TWO), - ), - ft.Segment( - value="3", - label=ft.Text("Three"), - icon=ft.Icon(ft.Icons.LOOKS_3), - ), - ft.Segment( - value="4", - label=ft.Text("Four"), - icon=ft.Icon(ft.Icons.LOOKS_4), - ), - ], - ), - ft.SegmentedButton( - on_change=handle_selection_change, - selected_icon=ft.Icon(ft.Icons.CHECK_SHARP), - selected=["2"], - allow_multiple_selection=False, - segments=[ - ft.Segment( - value="1", - label=ft.Text("One"), - icon=ft.Icon(ft.Icons.LOOKS_ONE), - ), - ft.Segment( - value="2", - label=ft.Text("Two"), - icon=ft.Icon(ft.Icons.LOOKS_TWO), - ), - ft.Segment( - value="3", - label=ft.Text("Three"), - icon=ft.Icon(ft.Icons.LOOKS_3), - ), - ft.Segment( - value="4", - label=ft.Text("Four"), - icon=ft.Icon(ft.Icons.LOOKS_4), - ), - ], - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/segmented_button/single_multiple_selection/main.py b/sdk/python/examples/controls/segmented_button/single_multiple_selection/main.py new file mode 100644 index 0000000000..f0dd892d73 --- /dev/null +++ b/sdk/python/examples/controls/segmented_button/single_multiple_selection/main.py @@ -0,0 +1,76 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_selection_change(e: ft.Event[ft.SegmentedButton]): + print(e) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.SegmentedButton( + on_change=handle_selection_change, + selected_icon=ft.Icon(ft.Icons.CHECK_SHARP), + selected=["1", "4"], + allow_empty_selection=True, + allow_multiple_selection=True, + segments=[ + ft.Segment( + value="1", + label=ft.Text("One"), + icon=ft.Icon(ft.Icons.LOOKS_ONE), + ), + ft.Segment( + value="2", + label=ft.Text("Two"), + icon=ft.Icon(ft.Icons.LOOKS_TWO), + ), + ft.Segment( + value="3", + label=ft.Text("Three"), + icon=ft.Icon(ft.Icons.LOOKS_3), + ), + ft.Segment( + value="4", + label=ft.Text("Four"), + icon=ft.Icon(ft.Icons.LOOKS_4), + ), + ], + ), + ft.SegmentedButton( + on_change=handle_selection_change, + selected_icon=ft.Icon(ft.Icons.CHECK_SHARP), + selected=["2"], + allow_multiple_selection=False, + segments=[ + ft.Segment( + value="1", + label=ft.Text("One"), + icon=ft.Icon(ft.Icons.LOOKS_ONE), + ), + ft.Segment( + value="2", + label=ft.Text("Two"), + icon=ft.Icon(ft.Icons.LOOKS_TWO), + ), + ft.Segment( + value="3", + label=ft.Text("Three"), + icon=ft.Icon(ft.Icons.LOOKS_3), + ), + ft.Segment( + value="4", + label=ft.Text("Four"), + icon=ft.Icon(ft.Icons.LOOKS_4), + ), + ], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/segmented_button/single_multiple_selection/pyproject.toml b/sdk/python/examples/controls/segmented_button/single_multiple_selection/pyproject.toml new file mode 100644 index 0000000000..26195e36e7 --- /dev/null +++ b/sdk/python/examples/controls/segmented_button/single_multiple_selection/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "segmented-button-single-multiple-selection" +version = "1.0.0" +description = "Compare single and multiple selection behavior with SegmentedButton." +requires-python = ">=3.10" +keywords = ["segmentedbutton", "selection", "multiple", "single", "icons"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/SegmentedButton"] + +[tool.flet.metadata] +title = "SegmentedButton single and multiple selection" +controls = ["SegmentedButton", "Segment", "Icon", "Text", "Column", "SafeArea"] +layout_pattern = "comparison-stack" +complexity = "basic" +features = ["single selection", "multiple selection", "selection change"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/selection_area/__init__.py b/sdk/python/examples/controls/selection_area/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/selection_area/basic.py b/sdk/python/examples/controls/selection_area/basic.py deleted file mode 100644 index 7c0670d903..0000000000 --- a/sdk/python/examples/controls/selection_area/basic.py +++ /dev/null @@ -1,41 +0,0 @@ -import flet as ft - -TEXT_STYLE = ft.TextStyle( - size=22, - weight=ft.FontWeight.W_600, - decoration=ft.TextDecoration( - ft.TextDecoration.UNDERLINE | ft.TextDecoration.OVERLINE - ), - decoration_style=ft.TextDecorationStyle.WAVY, -) - - -def main(page: ft.Page): - page.add( - ft.SelectionArea( - content=ft.Column( - controls=[ - ft.Text( - "Selectable text", - color=ft.Colors.GREEN, - style=TEXT_STYLE, - key="selectable", - ), - ft.Text("Also selectable", color=ft.Colors.GREEN, style=TEXT_STYLE), - ] - ) - ) - ) - - page.add( - ft.Text( - "Not selectable", - color=ft.Colors.RED, - style=TEXT_STYLE, - key="non-selectable", - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/selection_area/basic/main.py b/sdk/python/examples/controls/selection_area/basic/main.py new file mode 100644 index 0000000000..8349f9d283 --- /dev/null +++ b/sdk/python/examples/controls/selection_area/basic/main.py @@ -0,0 +1,48 @@ +import flet as ft + +TEXT_STYLE = ft.TextStyle( + size=22, + weight=ft.FontWeight.W_600, + decoration=ft.TextDecoration( + ft.TextDecoration.UNDERLINE | ft.TextDecoration.OVERLINE + ), + decoration_style=ft.TextDecorationStyle.WAVY, +) + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.SelectionArea( + content=ft.Column( + controls=[ + ft.Text( + "Selectable text", + color=ft.Colors.GREEN, + style=TEXT_STYLE, + key="selectable", + ), + ft.Text( + "Also selectable", + color=ft.Colors.GREEN, + style=TEXT_STYLE, + ), + ] + ) + ), + ft.Text( + "Not selectable", + color=ft.Colors.RED, + style=TEXT_STYLE, + key="non-selectable", + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/selection_area/basic/pyproject.toml b/sdk/python/examples/controls/selection_area/basic/pyproject.toml new file mode 100644 index 0000000000..586ad28711 --- /dev/null +++ b/sdk/python/examples/controls/selection_area/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "selection-area-basic" +version = "1.0.0" +description = "Compare selectable and non-selectable text using a SelectionArea wrapper." +requires-python = ">=3.10" +keywords = ["selectionarea", "text", "selection", "typography"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/SelectionArea"] + +[tool.flet.metadata] +title = "SelectionArea basic" +controls = ["SelectionArea", "Column", "Text", "SafeArea"] +layout_pattern = "comparison-stack" +complexity = "basic" +features = ["text selection", "selectable content", "styled text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/semantics/basic.py b/sdk/python/examples/controls/semantics/basic.py deleted file mode 100644 index 6540f4b080..0000000000 --- a/sdk/python/examples/controls/semantics/basic.py +++ /dev/null @@ -1,30 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_gain_accessibility_focus(e: ft.Event[ft.Semantics]): - print("focus gained") - - def handle_lose_accessibility_focus(e: ft.Event[ft.Semantics]): - print("focus lost") - - page.add( - ft.Column( - controls=[ - ft.Semantics( - label="Input your occupation", - on_did_gain_accessibility_focus=handle_gain_accessibility_focus, - on_did_lose_accessibility_focus=handle_lose_accessibility_focus, - content=ft.TextField( - label="Occupation", - hint_text="Use 20 words or less", - value="What is your occupation?", - ), - ), - ft.Icon(ft.Icons.SETTINGS, color="#c1c1c1"), - ] - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/semantics/basic/main.py b/sdk/python/examples/controls/semantics/basic/main.py new file mode 100644 index 0000000000..2626ace4f3 --- /dev/null +++ b/sdk/python/examples/controls/semantics/basic/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_gain_accessibility_focus(e: ft.Event[ft.Semantics]): + print("focus gained") + + def handle_lose_accessibility_focus(e: ft.Event[ft.Semantics]): + print("focus lost") + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Semantics( + label="Input your occupation", + on_did_gain_accessibility_focus=handle_gain_accessibility_focus, + on_did_lose_accessibility_focus=handle_lose_accessibility_focus, + content=ft.TextField( + label="Occupation", + hint_text="Use 20 words or less", + value="What is your occupation?", + ), + ), + ft.Icon(ft.Icons.SETTINGS, color="#c1c1c1"), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/semantics/basic/pyproject.toml b/sdk/python/examples/controls/semantics/basic/pyproject.toml new file mode 100644 index 0000000000..556dfc77d7 --- /dev/null +++ b/sdk/python/examples/controls/semantics/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "semantics-basic" +version = "1.0.0" +description = "Attach semantics labels and accessibility focus events to a text field." +requires-python = ">=3.10" +keywords = ["semantics", "accessibility", "textfield", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Semantics"] + +[tool.flet.metadata] +title = "Semantics basic" +controls = ["Semantics", "TextField", "Icon", "Column", "SafeArea"] +layout_pattern = "form-field" +complexity = "basic" +features = ["accessibility labels", "focus events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_search_bar.py b/sdk/python/packages/flet/integration_tests/examples/material/test_search_bar.py index f877ec2be9..83a5950d5f 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_search_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_search_bar.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.search_bar.basic.main as basic import flet as ft import flet.testing as ftt -from examples.controls.search_bar import basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_segmented_button.py b/sdk/python/packages/flet/integration_tests/examples/material/test_segmented_button.py index 032a8f57d0..0d347158b8 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_segmented_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_segmented_button.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.segmented_button.single_multiple_selection.main as sms import flet as ft import flet.testing as ftt -from examples.controls.segmented_button import single_multiple_selection @pytest.mark.asyncio(loop_scope="function") @@ -41,7 +41,7 @@ async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": single_multiple_selection.main}], + [{"flet_app_main": sms.main}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_selection_area.py b/sdk/python/packages/flet/integration_tests/examples/material/test_selection_area.py index 2dff5e3773..356039f883 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_selection_area.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_selection_area.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.selection_area.basic.main as basic import flet as ft import flet.testing as ftt -from examples.controls.selection_area import basic @pytest.mark.asyncio(loop_scope="function") From 70f9e28fceed7f1c44b292281aaf52ea4a25bd89 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 14:42:30 -0700 Subject: [PATCH 72/96] Restructure example folders; add pyproject metadata Move example scripts into per-example packages (rename *.py to */main.py and remove package __init__.py), wrap example UIs in SafeArea, and add pyproject.toml files with gallery/metadata for shader_mask and shimmer examples. Also update related docs and integration tests to reflect the new example paths and minor control docs edits. --- .../examples/controls/shader_mask/__init__.py | 0 .../shader_mask/fade_out_image_bottom.py | 27 ------------ .../shader_mask/fade_out_image_bottom/main.py | 29 +++++++++++++ .../fade_out_image_bottom/pyproject.toml | 26 +++++++++++ .../linear_and_radial_gradients.py | 41 ------------------ .../linear_and_radial_gradients/main.py | 43 +++++++++++++++++++ .../pyproject.toml | 26 +++++++++++ .../controls/shader_mask/pink_radial_glow.py | 35 --------------- .../shader_mask/pink_radial_glow/main.py | 37 ++++++++++++++++ .../pink_radial_glow/pyproject.toml | 26 +++++++++++ .../examples/controls/shimmer/__init__.py | 0 sdk/python/examples/controls/shimmer/basic.py | 21 --------- .../examples/controls/shimmer/basic/main.py | 23 ++++++++++ .../controls/shimmer/basic/pyproject.toml | 26 +++++++++++ .../main.py} | 16 ++++--- .../shimmer/basic_placeholder/pyproject.toml | 26 +++++++++++ .../main.py} | 2 +- .../shimmer/custom_gradient/pyproject.toml | 26 +++++++++++ sdk/python/packages/flet/docs/controls/row.md | 8 ++-- .../packages/flet/docs/controls/safearea.md | 2 +- .../packages/flet/docs/controls/screenshot.md | 2 +- .../packages/flet/docs/controls/searchbar.md | 2 +- .../flet/docs/controls/segmentedbutton.md | 2 +- .../flet/docs/controls/selectionarea.md | 2 +- .../packages/flet/docs/controls/semantics.md | 2 +- .../packages/flet/docs/controls/shadermask.md | 6 +-- .../packages/flet/docs/controls/shimmer.md | 6 +-- .../examples/core/test_shader_mask.py | 10 ++--- .../examples/core/test_shimmer.py | 3 +- 29 files changed, 321 insertions(+), 154 deletions(-) delete mode 100644 sdk/python/examples/controls/shader_mask/__init__.py delete mode 100644 sdk/python/examples/controls/shader_mask/fade_out_image_bottom.py create mode 100644 sdk/python/examples/controls/shader_mask/fade_out_image_bottom/main.py create mode 100644 sdk/python/examples/controls/shader_mask/fade_out_image_bottom/pyproject.toml delete mode 100644 sdk/python/examples/controls/shader_mask/linear_and_radial_gradients.py create mode 100644 sdk/python/examples/controls/shader_mask/linear_and_radial_gradients/main.py create mode 100644 sdk/python/examples/controls/shader_mask/linear_and_radial_gradients/pyproject.toml delete mode 100644 sdk/python/examples/controls/shader_mask/pink_radial_glow.py create mode 100644 sdk/python/examples/controls/shader_mask/pink_radial_glow/main.py create mode 100644 sdk/python/examples/controls/shader_mask/pink_radial_glow/pyproject.toml delete mode 100644 sdk/python/examples/controls/shimmer/__init__.py delete mode 100644 sdk/python/examples/controls/shimmer/basic.py create mode 100644 sdk/python/examples/controls/shimmer/basic/main.py create mode 100644 sdk/python/examples/controls/shimmer/basic/pyproject.toml rename sdk/python/examples/controls/shimmer/{basic_placeholder.py => basic_placeholder/main.py} (84%) create mode 100644 sdk/python/examples/controls/shimmer/basic_placeholder/pyproject.toml rename sdk/python/examples/controls/shimmer/{custom_gradient.py => custom_gradient/main.py} (97%) create mode 100644 sdk/python/examples/controls/shimmer/custom_gradient/pyproject.toml diff --git a/sdk/python/examples/controls/shader_mask/__init__.py b/sdk/python/examples/controls/shader_mask/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/shader_mask/fade_out_image_bottom.py b/sdk/python/examples/controls/shader_mask/fade_out_image_bottom.py deleted file mode 100644 index 903b6c4fa2..0000000000 --- a/sdk/python/examples/controls/shader_mask/fade_out_image_bottom.py +++ /dev/null @@ -1,27 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Row( - controls=[ - ft.ShaderMask( - content=ft.Image( - src="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" - ), - blend_mode=ft.BlendMode.DST_IN, - border_radius=10, - shader=ft.LinearGradient( - begin=ft.Alignment.TOP_CENTER, - end=ft.Alignment.BOTTOM_CENTER, - colors=[ft.Colors.BLACK, ft.Colors.TRANSPARENT], - stops=[0.5, 1.0], - ), - ), - ] - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/shader_mask/fade_out_image_bottom/main.py b/sdk/python/examples/controls/shader_mask/fade_out_image_bottom/main.py new file mode 100644 index 0000000000..b8bd1b39b3 --- /dev/null +++ b/sdk/python/examples/controls/shader_mask/fade_out_image_bottom/main.py @@ -0,0 +1,29 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.ShaderMask( + content=ft.Image( + src="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" + ), + blend_mode=ft.BlendMode.DST_IN, + border_radius=10, + shader=ft.LinearGradient( + begin=ft.Alignment.TOP_CENTER, + end=ft.Alignment.BOTTOM_CENTER, + colors=[ft.Colors.BLACK, ft.Colors.TRANSPARENT], + stops=[0.5, 1.0], + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/shader_mask/fade_out_image_bottom/pyproject.toml b/sdk/python/examples/controls/shader_mask/fade_out_image_bottom/pyproject.toml new file mode 100644 index 0000000000..0f5b6ef4ed --- /dev/null +++ b/sdk/python/examples/controls/shader_mask/fade_out_image_bottom/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shader-mask-fade-out-image-bottom" +version = "1.0.0" +description = "Fade the bottom of an image using a linear ShaderMask transparency gradient." +requires-python = ">=3.10" +keywords = ["shadermask", "image", "lineargradient", "fade", "transparency"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/ShaderMask"] + +[tool.flet.metadata] +title = "ShaderMask fade out image bottom" +controls = ["ShaderMask", "Image", "Row", "SafeArea"] +layout_pattern = "single-focus" +complexity = "basic" +features = ["linear gradient", "image fade", "blend mode"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients.py b/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients.py deleted file mode 100644 index fcb8fe88a9..0000000000 --- a/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients.py +++ /dev/null @@ -1,41 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Row( - controls=[ - ft.ShaderMask( - blend_mode=ft.BlendMode.COLOR_BURN, - shader=ft.RadialGradient( - center=ft.Alignment.TOP_LEFT, - radius=1.0, - colors=[ft.Colors.YELLOW, ft.Colors.DEEP_ORANGE_900], - tile_mode=ft.GradientTileMode.CLAMP, - ), - content=ft.Image( - src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==", - width=300, - height=300, - fit=ft.BoxFit.FILL, - ), - ), - ft.ShaderMask( - blend_mode=ft.BlendMode.DST_IN, - shader=ft.LinearGradient( - begin=ft.Alignment.TOP_CENTER, - end=ft.Alignment.BOTTOM_CENTER, - colors=[ft.Colors.BLACK, ft.Colors.TRANSPARENT], - stops=[0.5, 1.0], - ), - content=ft.Image( - src="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" - ), - ), - ] - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients/main.py b/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients/main.py new file mode 100644 index 0000000000..4cc30d5adf --- /dev/null +++ b/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.ShaderMask( + blend_mode=ft.BlendMode.COLOR_BURN, + shader=ft.RadialGradient( + center=ft.Alignment.TOP_LEFT, + radius=1.0, + colors=[ft.Colors.YELLOW, ft.Colors.DEEP_ORANGE_900], + tile_mode=ft.GradientTileMode.CLAMP, + ), + content=ft.Image( + src="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", + width=300, + height=300, + fit=ft.BoxFit.FILL, + ), + ), + ft.ShaderMask( + blend_mode=ft.BlendMode.DST_IN, + shader=ft.LinearGradient( + begin=ft.Alignment.TOP_CENTER, + end=ft.Alignment.BOTTOM_CENTER, + colors=[ft.Colors.BLACK, ft.Colors.TRANSPARENT], + stops=[0.5, 1.0], + ), + content=ft.Image( + src="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" + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients/pyproject.toml b/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients/pyproject.toml new file mode 100644 index 0000000000..a51447c94a --- /dev/null +++ b/sdk/python/examples/controls/shader_mask/linear_and_radial_gradients/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shader-mask-linear-and-radial-gradients" +version = "1.0.0" +description = "Compare radial and linear ShaderMask gradients applied to images." +requires-python = ">=3.10" +keywords = ["shadermask", "image", "gradients", "lineargradient", "radialgradient"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/ShaderMask"] + +[tool.flet.metadata] +title = "ShaderMask linear and radial gradients" +controls = ["ShaderMask", "Image", "Row", "SafeArea"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["linear gradient", "radial gradient", "image masking"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/shader_mask/pink_radial_glow.py b/sdk/python/examples/controls/shader_mask/pink_radial_glow.py deleted file mode 100644 index 41724b689b..0000000000 --- a/sdk/python/examples/controls/shader_mask/pink_radial_glow.py +++ /dev/null @@ -1,35 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Row( - controls=[ - ft.Image( - src="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", - width=300, - height=300, - fit=ft.BoxFit.FILL, - ), - ft.ShaderMask( - blend_mode=ft.BlendMode.MULTIPLY, - shader=ft.RadialGradient( - center=ft.Alignment.CENTER, - radius=0.5, - colors=[ft.Colors.WHITE, ft.Colors.PINK], - tile_mode=ft.GradientTileMode.CLAMP, - ), - content=ft.Image( - src="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", - width=300, - height=300, - fit=ft.BoxFit.FILL, - ), - ), - ] - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/shader_mask/pink_radial_glow/main.py b/sdk/python/examples/controls/shader_mask/pink_radial_glow/main.py new file mode 100644 index 0000000000..2368f7d093 --- /dev/null +++ b/sdk/python/examples/controls/shader_mask/pink_radial_glow/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Image( + src="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", + width=300, + height=300, + fit=ft.BoxFit.FILL, + ), + ft.ShaderMask( + blend_mode=ft.BlendMode.MULTIPLY, + shader=ft.RadialGradient( + center=ft.Alignment.CENTER, + radius=0.5, + colors=[ft.Colors.WHITE, ft.Colors.PINK], + tile_mode=ft.GradientTileMode.CLAMP, + ), + content=ft.Image( + src="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", + width=300, + height=300, + fit=ft.BoxFit.FILL, + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/shader_mask/pink_radial_glow/pyproject.toml b/sdk/python/examples/controls/shader_mask/pink_radial_glow/pyproject.toml new file mode 100644 index 0000000000..59632826e0 --- /dev/null +++ b/sdk/python/examples/controls/shader_mask/pink_radial_glow/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shader-mask-pink-radial-glow" +version = "1.0.0" +description = "Apply a radial ShaderMask glow to an image using a burn blend mode." +requires-python = ">=3.10" +keywords = ["shadermask", "image", "radialgradient", "blendmode", "visual-effect"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/ShaderMask"] + +[tool.flet.metadata] +title = "ShaderMask pink radial glow" +controls = ["ShaderMask", "Image", "Row", "SafeArea"] +layout_pattern = "single-focus" +complexity = "basic" +features = ["radial gradient", "blend mode", "image masking"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/shimmer/__init__.py b/sdk/python/examples/controls/shimmer/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/shimmer/basic.py b/sdk/python/examples/controls/shimmer/basic.py deleted file mode 100644 index 77b6a49f23..0000000000 --- a/sdk/python/examples/controls/shimmer/basic.py +++ /dev/null @@ -1,21 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Shimmer( - base_color=ft.Colors.with_opacity(0.3, ft.Colors.GREY_400), - highlight_color=ft.Colors.WHITE, - content=ft.Column( - controls=[ - ft.Container(height=80, bgcolor=ft.Colors.GREY_300), - ft.Container(height=80, bgcolor=ft.Colors.GREY_300), - ft.Container(height=80, bgcolor=ft.Colors.GREY_300), - ], - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/shimmer/basic/main.py b/sdk/python/examples/controls/shimmer/basic/main.py new file mode 100644 index 0000000000..d1bc09c7e2 --- /dev/null +++ b/sdk/python/examples/controls/shimmer/basic/main.py @@ -0,0 +1,23 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Shimmer( + base_color=ft.Colors.with_opacity(0.3, ft.Colors.GREY_400), + highlight_color=ft.Colors.WHITE, + content=ft.Column( + controls=[ + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ], + ), + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/shimmer/basic/pyproject.toml b/sdk/python/examples/controls/shimmer/basic/pyproject.toml new file mode 100644 index 0000000000..a5684337c7 --- /dev/null +++ b/sdk/python/examples/controls/shimmer/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shimmer-basic" +version = "1.0.0" +description = "Show a basic Shimmer loading effect over stacked placeholder blocks." +requires-python = ">=3.10" +keywords = ["shimmer", "loading", "placeholder", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/Shimmer"] + +[tool.flet.metadata] +title = "Shimmer basic" +controls = ["Shimmer", "Column", "Container", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["loading placeholders", "animated highlight"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/shimmer/basic_placeholder.py b/sdk/python/examples/controls/shimmer/basic_placeholder/main.py similarity index 84% rename from sdk/python/examples/controls/shimmer/basic_placeholder.py rename to sdk/python/examples/controls/shimmer/basic_placeholder/main.py index ed491f8653..d1b3132b52 100644 --- a/sdk/python/examples/controls/shimmer/basic_placeholder.py +++ b/sdk/python/examples/controls/shimmer/basic_placeholder/main.py @@ -54,13 +54,15 @@ def main(page: ft.Page): page.title = "Shimmer - loading placeholders" page.add( - ft.Shimmer( - base_color=ft.Colors.with_opacity(0.3, ft.Colors.GREY_400), - highlight_color=ft.Colors.WHITE, - content=ft.Column( - controls=[_placeholder_tile() for _ in range(3)], - ), - ), + ft.SafeArea( + content=ft.Shimmer( + base_color=ft.Colors.with_opacity(0.3, ft.Colors.GREY_400), + highlight_color=ft.Colors.WHITE, + content=ft.Column( + controls=[_placeholder_tile() for _ in range(3)], + ), + ) + ) ) diff --git a/sdk/python/examples/controls/shimmer/basic_placeholder/pyproject.toml b/sdk/python/examples/controls/shimmer/basic_placeholder/pyproject.toml new file mode 100644 index 0000000000..e23a646165 --- /dev/null +++ b/sdk/python/examples/controls/shimmer/basic_placeholder/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shimmer-basic-placeholder" +version = "1.0.0" +description = "Animate card-style loading placeholders with a Shimmer effect." +requires-python = ">=3.10" +keywords = ["shimmer", "placeholder", "loading", "card", "skeleton"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/Shimmer"] + +[tool.flet.metadata] +title = "Shimmer basic placeholder" +controls = ["Shimmer", "Column", "Row", "Container", "Icon", "SafeArea"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["skeleton placeholders", "animated highlight", "card layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/shimmer/custom_gradient.py b/sdk/python/examples/controls/shimmer/custom_gradient/main.py similarity index 97% rename from sdk/python/examples/controls/shimmer/custom_gradient.py rename to sdk/python/examples/controls/shimmer/custom_gradient/main.py index 13f22c6992..8ac6e48b0a 100644 --- a/sdk/python/examples/controls/shimmer/custom_gradient.py +++ b/sdk/python/examples/controls/shimmer/custom_gradient/main.py @@ -62,7 +62,7 @@ def main(page: ft.Page): ], ) - page.add(cards) + page.add(ft.SafeArea(content=cards)) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/shimmer/custom_gradient/pyproject.toml b/sdk/python/examples/controls/shimmer/custom_gradient/pyproject.toml new file mode 100644 index 0000000000..ec46c8b0d9 --- /dev/null +++ b/sdk/python/examples/controls/shimmer/custom_gradient/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shimmer-custom-gradient" +version = "1.0.0" +description = "Use a custom gradient Shimmer animation over a dashboard-style stat card." +requires-python = ">=3.10" +keywords = ["shimmer", "gradient", "animation", "dashboard", "card"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/Shimmer"] + +[tool.flet.metadata] +title = "Shimmer custom gradient" +controls = ["Shimmer", "Row", "Column", "Container", "Text", "SafeArea"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["custom gradient", "animated highlight", "dashboard card"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/row.md b/sdk/python/packages/flet/docs/controls/row.md index aa1f07143a..f5a12949de 100644 --- a/sdk/python/packages/flet/docs/controls/row.md +++ b/sdk/python/packages/flet/docs/controls/row.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/core/golden/macos/row ### Spacing children ```python ---8<-- "{{ examples }}/spacing.py" +--8<-- "{{ examples }}/spacing/main.py" ``` {{ image(example_images + "/row_spacing_adjustment.gif", alt="spacing", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../test-images/examples/core/golden/macos/row ### Wrapping children ```python ---8<-- "{{ examples }}/wrap.py" +--8<-- "{{ examples }}/wrap/main.py" ``` {{ image(example_images + "/wrap_adjustment.gif", alt="wrap", width="80%") }} @@ -31,7 +31,7 @@ example_images: ../test-images/examples/core/golden/macos/row ### Setting horizontal alignment ```python ---8<-- "{{ examples }}/alignment.py" +--8<-- "{{ examples }}/alignment/main.py" ``` {{ image(example_images + "/alignment.png", alt="alignment", width="60%") }} @@ -40,7 +40,7 @@ example_images: ../test-images/examples/core/golden/macos/row ### Setting vertical alignment ```python ---8<-- "{{ examples }}/vertical_alignment.py" +--8<-- "{{ examples }}/vertical_alignment/main.py" ``` {{ image(example_images + "/vertical_alignment.png", alt="vertical-alignment", width="60%") }} diff --git a/sdk/python/packages/flet/docs/controls/safearea.md b/sdk/python/packages/flet/docs/controls/safearea.md index 3daff58e89..18e6e35366 100644 --- a/sdk/python/packages/flet/docs/controls/safearea.md +++ b/sdk/python/packages/flet/docs/controls/safearea.md @@ -12,7 +12,7 @@ examples: ../../examples/controls/safe_area ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/screenshot.md b/sdk/python/packages/flet/docs/controls/screenshot.md index 4873722e58..1240ac1fdc 100644 --- a/sdk/python/packages/flet/docs/controls/screenshot.md +++ b/sdk/python/packages/flet/docs/controls/screenshot.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/screenshot ### Taking control screenshot ```python ---8<-- "{{ examples }}/taking_screenshot.py" +--8<-- "{{ examples }}/taking_screenshot/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/searchbar.md b/sdk/python/packages/flet/docs/controls/searchbar.md index 8a8610a5ba..a15fea457d 100644 --- a/sdk/python/packages/flet/docs/controls/searchbar.md +++ b/sdk/python/packages/flet/docs/controls/searchbar.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/search_bar ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/segmentedbutton.md b/sdk/python/packages/flet/docs/controls/segmentedbutton.md index 30c59806ce..433af13184 100644 --- a/sdk/python/packages/flet/docs/controls/segmentedbutton.md +++ b/sdk/python/packages/flet/docs/controls/segmentedbutton.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/segmented_button ### Basic Example ```python ---8<-- "{{ examples }}/single_multiple_selection.py" +--8<-- "{{ examples }}/single_multiple_selection/main.py" ``` {{ image(example_images + "/single_multiple_selection.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/selectionarea.md b/sdk/python/packages/flet/docs/controls/selectionarea.md index f64bbf0a30..9df2070459 100644 --- a/sdk/python/packages/flet/docs/controls/selectionarea.md +++ b/sdk/python/packages/flet/docs/controls/selectionarea.md @@ -12,7 +12,7 @@ example_media: ../examples/controls/selection_area/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/semantics.md b/sdk/python/packages/flet/docs/controls/semantics.md index 15377b0943..a9027bcfcc 100644 --- a/sdk/python/packages/flet/docs/controls/semantics.md +++ b/sdk/python/packages/flet/docs/controls/semantics.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/semantics ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/controls/shadermask.md b/sdk/python/packages/flet/docs/controls/shadermask.md index ee3c13d039..dc53614dd7 100644 --- a/sdk/python/packages/flet/docs/controls/shadermask.md +++ b/sdk/python/packages/flet/docs/controls/shadermask.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/core/golden/macos/shader_mask ### Pink glow around image edges ```python ---8<-- "{{ examples }}/pink_radial_glow.py" +--8<-- "{{ examples }}/pink_radial_glow/main.py" ``` {{ image(example_images + "/pink_radial_glow.png", alt="pink-radial-glow", width="80%") }} @@ -23,7 +23,7 @@ example_images: ../test-images/examples/core/golden/macos/shader_mask ### Fade out bottom edge of an image ```python ---8<-- "{{ examples }}/fade_out_image_bottom.py" +--8<-- "{{ examples }}/fade_out_image_bottom/main.py" ``` {{ image(example_images + "/fade_out_image_bottom.png", alt="fade-out-image-bottom", width="80%") }} @@ -32,7 +32,7 @@ example_images: ../test-images/examples/core/golden/macos/shader_mask ### Applying linear and radial gradients/shaders ```python ---8<-- "{{ examples }}/linear_and_radial_gradients.py" +--8<-- "{{ examples }}/linear_and_radial_gradients/main.py" ``` {{ image(example_images + "/linear_and_radial_gradients.png", alt="fade-out-image-bottom", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/shimmer.md b/sdk/python/packages/flet/docs/controls/shimmer.md index b828222001..0d8d5c0d78 100644 --- a/sdk/python/packages/flet/docs/controls/shimmer.md +++ b/sdk/python/packages/flet/docs/controls/shimmer.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/core/golden/macos/shimmer ### Basic ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/image_for_docs.gif", alt="custom-label", width="50%") }} @@ -19,7 +19,7 @@ example_images: ../test-images/examples/core/golden/macos/shimmer ### Skeleton list placeholders ```python ---8<-- "{{ examples }}/basic_placeholder.py" +--8<-- "{{ examples }}/basic_placeholder/main.py" ``` {{ image(example_images + "/basic_placeholder.png", alt="custom-label", width="50%") }} @@ -27,7 +27,7 @@ example_images: ../test-images/examples/core/golden/macos/shimmer ### Custom gradients and directions ```python ---8<-- "{{ examples }}/custom_gradient.py" +--8<-- "{{ examples }}/custom_gradient/main.py" ``` {{ image(example_images + "/custom_gradient.png", alt="custom-label", width="50%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_shader_mask.py b/sdk/python/packages/flet/integration_tests/examples/core/test_shader_mask.py index e8905a8b0b..761fc6aa74 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_shader_mask.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_shader_mask.py @@ -1,11 +1,11 @@ import pytest +import examples.controls.shader_mask.fade_out_image_bottom.main as fade_out_image_bottom +import examples.controls.shader_mask.pink_radial_glow.main as pink_radial_glow import flet as ft import flet.testing as ftt -from examples.controls.shader_mask import ( - fade_out_image_bottom, - linear_and_radial_gradients, - pink_radial_glow, +from examples.controls.shader_mask.linear_and_radial_gradients import ( + main as linear_gradients, ) @@ -59,7 +59,7 @@ async def test_pink_radial_glow(flet_app_function: ftt.FletTestApp): @pytest.mark.parametrize( "flet_app_function", - [{"flet_app_main": linear_and_radial_gradients.main}], + [{"flet_app_main": linear_gradients.main}], indirect=True, ) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_shimmer.py b/sdk/python/packages/flet/integration_tests/examples/core/test_shimmer.py index 5130cd649a..97712a80de 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_shimmer.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_shimmer.py @@ -1,8 +1,9 @@ import pytest +import examples.controls.shimmer.basic_placeholder.main as basic_placeholder +import examples.controls.shimmer.custom_gradient.main as custom_gradient import flet as ft import flet.testing as ftt -from examples.controls.shimmer import basic_placeholder, custom_gradient @pytest.mark.skip(reason="The test is flaky on CI") From 7e65ad566fe81c3d97d08cc63575ac7f13e4901d Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 15:09:26 -0700 Subject: [PATCH 73/96] Restructure examples into main.py and metadata Move and reorganize slider and snack_bar examples into per-example folders with main.py entrypoints, replacing previous top-level example modules. Add pyproject.toml metadata for each example (gallery metadata, dependencies, and metadata). Wrap example UI in SafeArea/Column containers, adjust a few example implementations accordingly, and update docs to reference the new example paths. Update integration tests imports to the new module paths and refresh a snack_bar golden asset. --- .../examples/controls/slider/__init__.py | 0 sdk/python/examples/controls/slider/basic.py | 14 -------- .../examples/controls/slider/basic/main.py | 20 ++++++++++++ .../controls/slider/basic/pyproject.toml | 26 +++++++++++++++ .../examples/controls/slider/custom_label.py | 14 -------- .../controls/slider/custom_label/main.py | 20 ++++++++++++ .../slider/custom_label/pyproject.toml | 26 +++++++++++++++ .../controls/slider/handling_events.py | 24 -------------- .../controls/slider/handling_events/main.py | 30 ++++++++++++++++++ .../slider/handling_events/pyproject.toml | 26 +++++++++++++++ .../main.py} | 14 ++++++-- .../slider/random_values/pyproject.toml | 26 +++++++++++++++ .../examples/controls/snack_bar/__init__.py | 0 .../snack_bar/{action.py => action/main.py} | 16 ++++++++-- .../controls/snack_bar/action/pyproject.toml | 26 +++++++++++++++ .../snack_bar/{basic.py => basic/main.py} | 2 +- .../controls/snack_bar/basic/pyproject.toml | 26 +++++++++++++++ .../snack_bar/{counter.py => counter/main.py} | 4 ++- .../controls/snack_bar/counter/pyproject.toml | 26 +++++++++++++++ .../packages/flet/docs/controls/slider.md | 6 ++-- .../packages/flet/docs/controls/snackbar.md | 6 ++-- .../golden/macos/snack_bar/snack_bar_flow.gif | Bin 10747 -> 12280 bytes .../examples/material/test_slider.py | 8 ++--- .../examples/material/test_snack_bar.py | 4 ++- 24 files changed, 293 insertions(+), 71 deletions(-) delete mode 100644 sdk/python/examples/controls/slider/__init__.py delete mode 100644 sdk/python/examples/controls/slider/basic.py create mode 100644 sdk/python/examples/controls/slider/basic/main.py create mode 100644 sdk/python/examples/controls/slider/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/slider/custom_label.py create mode 100644 sdk/python/examples/controls/slider/custom_label/main.py create mode 100644 sdk/python/examples/controls/slider/custom_label/pyproject.toml delete mode 100644 sdk/python/examples/controls/slider/handling_events.py create mode 100644 sdk/python/examples/controls/slider/handling_events/main.py create mode 100644 sdk/python/examples/controls/slider/handling_events/pyproject.toml rename sdk/python/examples/controls/slider/{random_values.py => random_values/main.py} (58%) create mode 100644 sdk/python/examples/controls/slider/random_values/pyproject.toml delete mode 100644 sdk/python/examples/controls/snack_bar/__init__.py rename sdk/python/examples/controls/snack_bar/{action.py => action/main.py} (65%) create mode 100644 sdk/python/examples/controls/snack_bar/action/pyproject.toml rename sdk/python/examples/controls/snack_bar/{basic.py => basic/main.py} (70%) create mode 100644 sdk/python/examples/controls/snack_bar/basic/pyproject.toml rename sdk/python/examples/controls/snack_bar/{counter.py => counter/main.py} (86%) create mode 100644 sdk/python/examples/controls/snack_bar/counter/pyproject.toml diff --git a/sdk/python/examples/controls/slider/__init__.py b/sdk/python/examples/controls/slider/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/slider/basic.py b/sdk/python/examples/controls/slider/basic.py deleted file mode 100644 index 4ba9492c32..0000000000 --- a/sdk/python/examples/controls/slider/basic.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Text("Default slider:"), - ft.Slider(), - ft.Text("Default disabled slider:"), - ft.Slider(disabled=True), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/slider/basic/main.py b/sdk/python/examples/controls/slider/basic/main.py new file mode 100644 index 0000000000..a0e344977e --- /dev/null +++ b/sdk/python/examples/controls/slider/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Default slider:"), + ft.Slider(), + ft.Text("Default disabled slider:"), + ft.Slider(disabled=True), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/slider/basic/pyproject.toml b/sdk/python/examples/controls/slider/basic/pyproject.toml new file mode 100644 index 0000000000..fc7205e833 --- /dev/null +++ b/sdk/python/examples/controls/slider/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "slider-basic" +version = "1.0.0" +description = "Compare enabled and disabled Slider controls with the default settings." +requires-python = ">=3.10" +keywords = ["slider", "input", "disabled", "basic"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Slider"] + +[tool.flet.metadata] +title = "Slider basic" +controls = ["Slider", "Text", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["enabled and disabled states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/slider/custom_label.py b/sdk/python/examples/controls/slider/custom_label.py deleted file mode 100644 index e5de954a77..0000000000 --- a/sdk/python/examples/controls/slider/custom_label.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Text("Slider with value:"), - ft.Slider(value=0.3), - ft.Text("Slider with a custom range and label:"), - ft.Slider(min=0, max=100, divisions=10, label="{value}%"), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/slider/custom_label/main.py b/sdk/python/examples/controls/slider/custom_label/main.py new file mode 100644 index 0000000000..f9899ba202 --- /dev/null +++ b/sdk/python/examples/controls/slider/custom_label/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Slider with value:"), + ft.Slider(value=0.3), + ft.Text("Slider with a custom range and label:"), + ft.Slider(min=0, max=100, divisions=10, label="{value}%"), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/slider/custom_label/pyproject.toml b/sdk/python/examples/controls/slider/custom_label/pyproject.toml new file mode 100644 index 0000000000..d056ba6632 --- /dev/null +++ b/sdk/python/examples/controls/slider/custom_label/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "slider-custom-label" +version = "1.0.0" +description = "Show Slider values with a preset position and a custom percentage label." +requires-python = ">=3.10" +keywords = ["slider", "label", "divisions", "range"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Slider"] + +[tool.flet.metadata] +title = "Slider custom label" +controls = ["Slider", "Text", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["custom label", "custom range", "divisions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/slider/handling_events.py b/sdk/python/examples/controls/slider/handling_events.py deleted file mode 100644 index 818c6d7a4f..0000000000 --- a/sdk/python/examples/controls/slider/handling_events.py +++ /dev/null @@ -1,24 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def slider_changed(e: ft.Event[ft.Slider]): - message.value = f"Slider changed to {e.control.value}" - message.update() - - page.add( - ft.Text("Slider with 'on_change' event:"), - ft.Slider( - key="slider", - min=0, - max=100, - divisions=10, - label="{value}%", - on_change=slider_changed, - ), - message := ft.Text(), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/slider/handling_events/main.py b/sdk/python/examples/controls/slider/handling_events/main.py new file mode 100644 index 0000000000..ef9aaa4f7a --- /dev/null +++ b/sdk/python/examples/controls/slider/handling_events/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + def slider_changed(e: ft.Event[ft.Slider]): + message.value = f"Slider changed to {e.control.value}" + message.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Slider with 'on_change' event:"), + ft.Slider( + key="slider", + min=0, + max=100, + divisions=10, + label="{value}%", + on_change=slider_changed, + ), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/slider/handling_events/pyproject.toml b/sdk/python/examples/controls/slider/handling_events/pyproject.toml new file mode 100644 index 0000000000..089cc264e5 --- /dev/null +++ b/sdk/python/examples/controls/slider/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "slider-handling-events" +version = "1.0.0" +description = "Update a text label live when a Slider value changes." +requires-python = ">=3.10" +keywords = ["slider", "events", "on_change", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Slider"] + +[tool.flet.metadata] +title = "Slider handling events" +controls = ["Slider", "Text", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["value change handling", "live updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/slider/random_values.py b/sdk/python/examples/controls/slider/random_values/main.py similarity index 58% rename from sdk/python/examples/controls/slider/random_values.py rename to sdk/python/examples/controls/slider/random_values/main.py index 5e929b3501..4a325aff2c 100644 --- a/sdk/python/examples/controls/slider/random_values.py +++ b/sdk/python/examples/controls/slider/random_values/main.py @@ -10,9 +10,17 @@ def handle_slider_change(e: ft.Event[ft.Slider]): message.update() page.add( - ft.Text("Slider with 'on_change' event:"), - slider := ft.Slider(label="{value}", on_change=handle_slider_change), - message := ft.Text(), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Slider with 'on_change' event:"), + slider := ft.Slider( + label="{value}", on_change=handle_slider_change + ), + message := ft.Text(), + ] + ) + ) ) while True: diff --git a/sdk/python/examples/controls/slider/random_values/pyproject.toml b/sdk/python/examples/controls/slider/random_values/pyproject.toml new file mode 100644 index 0000000000..18847f2766 --- /dev/null +++ b/sdk/python/examples/controls/slider/random_values/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "slider-random-values" +version = "1.0.0" +description = "Animate a Slider with random values and mirror each update in a text label." +requires-python = ">=3.10" +keywords = ["slider", "random", "animation", "events", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Slider"] + +[tool.flet.metadata] +title = "Slider random values" +controls = ["Slider", "Text", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["async updates", "random values", "live updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/snack_bar/__init__.py b/sdk/python/examples/controls/snack_bar/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/snack_bar/action.py b/sdk/python/examples/controls/snack_bar/action/main.py similarity index 65% rename from sdk/python/examples/controls/snack_bar/action.py rename to sdk/python/examples/controls/snack_bar/action/main.py index 8bc496c38f..73925c694c 100644 --- a/sdk/python/examples/controls/snack_bar/action.py +++ b/sdk/python/examples/controls/snack_bar/action/main.py @@ -26,8 +26,20 @@ def open_custom_action(e: ft.Event[ft.Button]): ) page.add( - ft.Button("Open SnackBar with a Simple action", on_click=open_simple_action), - ft.Button("Open SnackBar with a Custom action", on_click=open_custom_action), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Open SnackBar with a Simple action", + on_click=open_simple_action, + ), + ft.Button( + "Open SnackBar with a Custom action", + on_click=open_custom_action, + ), + ] + ) + ) ) diff --git a/sdk/python/examples/controls/snack_bar/action/pyproject.toml b/sdk/python/examples/controls/snack_bar/action/pyproject.toml new file mode 100644 index 0000000000..d02f8e012b --- /dev/null +++ b/sdk/python/examples/controls/snack_bar/action/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "snack-bar-action" +version = "1.0.0" +description = "Compare simple and custom SnackBar actions opened from separate buttons." +requires-python = ">=3.10" +keywords = ["snackbar", "action", "button", "feedback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/SnackBar"] + +[tool.flet.metadata] +title = "SnackBar action" +controls = ["SnackBar", "SnackBarAction", "Button", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["simple action", "custom action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/snack_bar/basic.py b/sdk/python/examples/controls/snack_bar/basic/main.py similarity index 70% rename from sdk/python/examples/controls/snack_bar/basic.py rename to sdk/python/examples/controls/snack_bar/basic/main.py index ffd692e09b..01a5947ad2 100644 --- a/sdk/python/examples/controls/snack_bar/basic.py +++ b/sdk/python/examples/controls/snack_bar/basic/main.py @@ -5,7 +5,7 @@ def main(page: ft.Page): def on_click(e: ft.Event[ft.Button]): page.show_dialog(ft.SnackBar(ft.Text("Hello, world!"))) - page.add(ft.Button("Open SnackBar", on_click=on_click)) + page.add(ft.SafeArea(content=ft.Button("Open SnackBar", on_click=on_click))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/snack_bar/basic/pyproject.toml b/sdk/python/examples/controls/snack_bar/basic/pyproject.toml new file mode 100644 index 0000000000..935c517c00 --- /dev/null +++ b/sdk/python/examples/controls/snack_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "snack-bar-basic" +version = "1.0.0" +description = "Open a basic SnackBar from a button tap." +requires-python = ">=3.10" +keywords = ["snackbar", "dialog", "button", "feedback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/SnackBar"] + +[tool.flet.metadata] +title = "SnackBar basic" +controls = ["SnackBar", "Button", "Text", "SafeArea"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dialog open"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/snack_bar/counter.py b/sdk/python/examples/controls/snack_bar/counter/main.py similarity index 86% rename from sdk/python/examples/controls/snack_bar/counter.py rename to sdk/python/examples/controls/snack_bar/counter/main.py index cbe9759c8a..6b527d8518 100644 --- a/sdk/python/examples/controls/snack_bar/counter.py +++ b/sdk/python/examples/controls/snack_bar/counter/main.py @@ -31,7 +31,9 @@ def handle_button_click(e: ft.Event[ft.Button]): page.show_dialog(snack_bar) page.update() - page.add(ft.Button("Open SnackBar", on_click=handle_button_click)) + page.add( + ft.SafeArea(content=ft.Button("Open SnackBar", on_click=handle_button_click)) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/snack_bar/counter/pyproject.toml b/sdk/python/examples/controls/snack_bar/counter/pyproject.toml new file mode 100644 index 0000000000..801708e796 --- /dev/null +++ b/sdk/python/examples/controls/snack_bar/counter/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "snack-bar-counter" +version = "1.0.0" +description = "Count repeated SnackBar opens and support undoing the latest increment." +requires-python = ">=3.10" +keywords = ["snackbar", "counter", "undo", "feedback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/SnackBar"] + +[tool.flet.metadata] +title = "SnackBar counter" +controls = ["SnackBar", "Button", "Text", "SafeArea"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["counter updates", "undo action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/slider.md b/sdk/python/packages/flet/docs/controls/slider.md index 2d58ac65b6..2a5ac46f02 100644 --- a/sdk/python/packages/flet/docs/controls/slider.md +++ b/sdk/python/packages/flet/docs/controls/slider.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/slider ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../test-images/examples/material/golden/macos/slider ### Setting a custom label ```python ---8<-- "{{ examples }}/custom_label.py" +--8<-- "{{ examples }}/custom_label/main.py" ``` {{ image(example_images + "/custom_label.png", alt="custom-label", width="80%") }} @@ -31,7 +31,7 @@ example_images: ../test-images/examples/material/golden/macos/slider ### Handling events ```python ---8<-- "{{ examples }}/handling_events.py" +--8<-- "{{ examples }}/handling_events/main.py" ``` {{ image(example_images + "/handling_events.png", alt="handling-events", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/snackbar.md b/sdk/python/packages/flet/docs/controls/snackbar.md index c1e0a87e55..50132a45e8 100644 --- a/sdk/python/packages/flet/docs/controls/snackbar.md +++ b/sdk/python/packages/flet/docs/controls/snackbar.md @@ -14,7 +14,7 @@ snack_bar_action_class_name: flet.SnackBarAction ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} @@ -23,7 +23,7 @@ snack_bar_action_class_name: flet.SnackBarAction ### Counter ```python ---8<-- "{{ examples }}/counter.py" +--8<-- "{{ examples }}/counter/main.py" ``` {{ image(example_images + "/snack_bar_flow.gif", alt="Snack bar with counter", caption="Snack bar with counter",width="50%") }} @@ -31,7 +31,7 @@ snack_bar_action_class_name: flet.SnackBarAction ### Action ```python ---8<-- "{{ examples }}/action.py" +--8<-- "{{ examples }}/action/main.py" ``` {{ image(example_images + "/action_simple.png", alt="Snack bar with a simple action", caption="Snack bar with a simple action", width="50%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/snack_bar/snack_bar_flow.gif b/sdk/python/packages/flet/integration_tests/examples/material/golden/macos/snack_bar/snack_bar_flow.gif index 474369f01de360637ee48cef991c4d64e72c8740..5f0ad99cf6a97faf7ec91248cba37694967f788d 100644 GIT binary patch literal 12280 zcmdtoXIRqz}sO+xPwb?|b{-clT)fw!3${LpyiB?d*Qv`EwpqcfL_~j<r87^iHEeO;fPS(u)lpPHVVoT6=Za&mU!&nV*)Uq@%whNoAD zr&foiRtG0n256gD9v}ZY_GdGrV>2V8)BWSiEWS;o-@lKbsgF8Xp)O z>mL{;_mA|AE%lBr_KYlck1TW#FLVvhcMi>W49>L;%(nK=lF7q;?h@wf%WSa&8Sdhqmgz z?CQR(s@}}X-i*qg3_?#jq33f&H?FKJwX`#(v@^M+BeA$Wp{Omss4cFr^%HFcEwTA6 zG5IagdCgI|O_4c`5!sC&vKqoONnx3!&)+9qRu_b;3rwx`Pa*mx(^li1 zSp7Dk>UCVD*C&E!Y=uW`g?mi-%a3Kxqe@*POI$wSpN17Xh88)zFSH9Oc=9gaCMeH3 zFxSdI$HFiBp--0C+YFO8>GwR-?!LldUZ&h}OVW9kpzibuZTnHmBK*P$(`_|F0~IBG zwQFK1dLRG*xbO`GXs11j(C&agUlRcI1OS9`YvOSYe$dlGrtSE&rXb`c?Ig{T&n@pc zuG>wum!!9S;8O|V)+){D_$X+QXWCJk+4Tu!)tRJKmerFeYqeCbdFS8xYGwUK0PF6b4cP8sp z7EKe~_tvJnDvQ5<@up|u)vdzMHU*#dWJaO^K5Y?~bW(JyOBcK1uG`OaSC=jK;Z)vl ziFlXHmD8~s=AeMe^bB~bt`t2YVRN#|b$zCXSh@X`mG5;)7hQ|o)4?_m) zq~5NpIanVnGYHbZ(CD&+J&isYyN)oqX)Y9UH@X+Y4lAm4pqMb@wa!=5l$Xdwq(7k#FVlUY56nNX+!ykD9Xc536wW*gdDj!U}1)Fch%cGXB7fIb!HrXkcLbm%)7?Z=y(j#HDu^{2jLb7n^UsR~t~A)d}> z*ETWOvC8&`t^>ENJ)`hXhy1?F6|c#9#4&x;q-OQzzPMBd zc?3R}Ci(yx%#hDHqXwb?k#Hz%0tRt9ln{B1Mm+nqt1-kz^>%@W+Li*p-s)6puo%7| zjW9o}aH5>W_3c*^@BYdsvBzcMfh{^xTI4no24ThR=hvjH z&QfWOc!E|5X|fD*+K?&m8k=(=NLYTWNrSuFcAdW(tar8C`hyKXg(uYu?eIwdi^Z_t zx$&GCGL%D(!BoYB7{`3p%9ZiORZMh-?9M4?|q=X4bYz zy>F|-TBQ|8XpU%eEK#AuSAQl%o#N86WeUQd3LnnEUfhXTOX%2h2ZEGjuFO^f^=fgGm;l90X#@sj)_KoM@*Wix?7o7oV-u}@5t~m zhwbyn9Ok^%PeNbBB9cmGSMe7=acS&R&;LFS)Sfri89PRslm>@^1kpaGVcurgj5Lwi zNMU|z)A`>hHMP?Ma7Tu8DdS;wsaRBEN$g!I8y+L9abBT?43tiqGNF6f(wk?>(Bv_( zN2okAIQ91>>oO(vZ!l*rR{YU1l~G8g}ZJ5?9*E z^sp2gwSl8tO@l!m7*>5hUJ_=XSnHIZTiLPc6f|to$YReDGz_d`*D>H5`lv|9HNs#& z2zUJJ?uQf9s6)p04`0q1o9qe}UVr=%H2l34UO@qCp6eX;8^|iFynz!T0Xv=@j37pb zdO8Vef7M>20-?XXxeXbPg`EPwA^d!d zi^~4;Cv4#WP)P@qBSF#YW9u^%$wsRt*+2)+7hf$FjbU3G#!oNx4^P7Hnal}_(LZtZ zUHH`$fCuir7cMAdLgdg(kD-FjSpqm6w9%V9Mp2G?fctav0ZnTRjt|lb>B@9Yc#DF| zlAi9sjFS*jvPlwb_S{M5+A&cFVHzJ!BEK5_ZsH*yw}|LBn2dERnRLOoNW8VAx023M zwd7bq-*k z2i@=G*D(tdN|<>@1EVBZ_Hj>%AjdN*QV1mW=@;1oo4!E0^OS5lqeG_45l>&$m|k;K zmnu*b#ElOJ63W#SM1+|%Ap-g$dFMXoUPP|2Ppq|N*)$Ev3}FLHcMkEITx5$)D{xt^ z-&NgNIr*UN(Gw`aF*r?hr8kg%LnyD*#_!=6UfIMeEG$H&XO$g%P0IR&Jd%7zOFZxE@@=$Q2;hY9*IALKC*cIdh+FRbssRA0U__Y!f?tPTt(uO-T1(} zh-&lS`Kt;moMO}D+ZOP4r^C&V-g`k=W~@c*rsCvMXj4s_3;~D;+)O7qEkBzozOAy` z@5i}5_R#efd0eyc&Ao*r;jTulj<+0KQgC9>;f_*+riO`0+a1M|fXmx_B8HURxbx85 z1nMGi*rNWI3j`tdVC+pym=u{K?iOKfU4dRsnp>Y)9E^ypcvjl~3?FI6Ie5Q^L55l> zI!%#e$N(fFVID+)&Tzr1L^ny^3vGPDWYC4^H;g+sWXT}rUHUGx;)DyLlHx?M zW^|)^sV+V(-vQL4EPkVzHBnr_Y_Cgp==Wo|a>-s3rHFoW>#hioatXt8XSm|bZBGEq zSIOFT0$hqH<{wswXaSKXWpL@U7iSDTURfh3RHl?mTn1I5M!^A#8KU}XdHMvD_4EE6>&{F_75@hCmshHz^ z{V~@A0EmfCo*;-EY6LUUU8*~N-yO$wnhF+jwri0=CM<)9&`WFp(pFY(|YQqDp1?nv6tmmvwfdhdgBDcBGXR6Yu)I|X1er+4N99m+(Y zltIqq@aFap^f;gf6$1JeahVS2Z4Rnv{{Y#!Ap!uu0z`7hU+@5cMVtYQPa=DPAP;;H zPka<83ha)jpRtH!QUY+AgZv{HgkF6-I*DZP*9QsGePlWX0Q1oqIYaMye^k%qRncO& zU=Fyn`VrtAiA6J-I7b_5@tUC+u{gS|mFT=GfGC+E7!SUCGj@0u986{q!Eu|8BXj%d zu;x%dbgaucZX^mCfMXEF#oBkoGLh(v0MK|6$n|DiO+P4x1Tn4n{x%Nmjb=W1M8X*3`_pJTWio?T z1Y;VNF&Y51qkyFFKqeHRQ!52#k=WZor)17xhld29857BjpHVQ5gfz~YH13Hs-tTFA zoS!ese&)x17V!8inDAMs=CgnhEE&%jtq=9YfsK$L5py78L=tT62Aw$ojspte=vC1S z4nHbqjLu{szN9MhROl(c2DK_&d3H*e@V2B1uo6~WU z0APJiIXiKM1i&dAkXN5hgi43f&wk;N?VgbBQIqX8k^Sa-wl`;vuWXJ#HYd;{Czvxw zoJ4o|gaYJ5(%wWCV@=lLI7hezATA*{p(ZzJA~)rGE{-$rvus`lHZRK~FDD@{uO=@? z8$hSe`B6K!R5rgHn@{k_uS&?TsmZUM$glsNPvR_Slr3n+7PNX4v?mmF))aJ46!d;C zAafQD$QBM^3r9Q(#}W!BY6_<&3TM6-QaFp|WQ!KCMN1wz@;zN((cq25 zCb3MGSSCMNrud@_%~h@}SFUPOuI^c`nOLq(EZ3bZzx|_JpQ{2RS7B&UVdPnHFR=nk ztT3Idc<`gboQq&7M|fmHcS%s-sP+V?C?m5~~x4)k%}pDL<-l zTs5ENYBEe}vOH^Y5^M5^H3gG3ML%lrT*Oj2Vz~*C;7P1XB-Rj#wUfm9A4C#YZKGUm zvq^2MXKj08Z6~p|d$P9oM=hDFZa}VX$fRz>vu-T0Zh}}hHCZ?FqmB~DRX-q34(5#4q28Uw%%0`TgSyfSW`oPXd{ez+NP1 z5(!pIf=`iHev**f4XpAFY^DwDUJV>c4V<+N+*1v_KO6YC8!yT?@|!jacr^+pH44=> zicB?%{cJ>WH(ir&k~D3S@@nE{NB+4q2et!_{#=@0rCpla0E7NBe)WHjSK9|Pwxapf zf0ZkmQ~g7({>fIW8~gtuSGzR1`iEKl6RfuXP}S<*^6ECtsc1+=1FOGbYH?|k22(Vx zqQMkRqG&KhW2ip>MOmJi-~QX0Xa+^&rspb4zz~OXt7S z5Y2^X5QOXemD=$$wc|%h+qdM_xRTC1urr zLr{Ff&Zqj#*t(6_+V$v~m8h!4ziBA7tTViHCcm)k-z_Mla5O!uhz3ES8DA2TK7Wc& zjrpWsBU&U6xj4pp3RTlOkh9*DG?+a+` z^SAl<286uz34HAx@cOO4y)W*$SKxoIK-QkIR_;-jFC+iSK`w5u?4Q0ce;#h`7G~}i zYWg(L;*qV9jhE45&%4&I{vC@9tzKd*+-PKE_VAI3ndKd`r?*X=^h_L#?wMikVs#83 zYUpFtbug+LI?8I=N~)S@EyG)y7zMRE@~XELmDJ@_^kkK^70{}(x71{AX-F%o-IPa5 zE2zoH-MS&GbVEkrx{Ts=DcNf`Zc5ycLrLC5U6&TWE{(b-Ehcf}4@CVBZZw+OX8adT zRpAjC>K+__Xv(rd;)t`Zq`l;l(j^{8cN$GC1V{aorWiyUlC(+@J&CMpv;U&0P9$4@ zvigU=X(}2EE82~Yri5fO&9m)4x_YKT=bniNOlOz>4^73gr5jyLA_#^3^qGtV(`YKO zm!~Ryj?GW%%9a|G)tMvQoJn2p-tmK^2H4lz{`4y|U&EF8mDL4b&04qVSS|4AC9KSa zV>JZSgCnixdl+uL^mlxAplm=-FD~yGA=T2E>Bsc)o6?iVKC%iE4>UV1_xy~69;mHy z+3bdR8Y!NIdfD#GQku3;&?1=uW#Q|;HZU!v0ZO~G01&%w%_ zLZG{s$-xXURg_T45kY+$?%Rf6RX0S3&iTuC^BT|iaV>IlAP~}R)0PdL+L8IR%?HjouS|3)BQBCCtE_L0KbWHi<8EJLVv}= zx>5;-ZB_M$)=&ca;$NzlZ7BhK8=qDDpNl9x=c*TR}%N~66)TM8mBqy4Eo_pkPs z!OqPJDDA&lfBHZxNv)G`^}a0mYFAcyp`cZrp_s}?7XLgYxw%ASmPD9(^A~RVVFw)@ zR2*6EO}qDjnw__oPNsKQ-$2BUDXeBnRqjeduaD5Owjnbw?QI6S>q913&*KeOaWqvFs$6?2G z$C%n0v<2GjIGOQUX}N_sd-m~$=&!lQ=KVho90N$z=cW+1UmvH7HZX7oe!L~kZtGkE zT3>5oXx`myI)AH6(m4{$LHqmu_CcKr{qe@pE&Xu@W?N+YAuR4JAIgWx9Ie7x+D1~f zXn;RK({ogjK{~$abxmjH^X2`V*K7kR7D`W?bS#|NQ4!}s7Z`Q*li*K= zKmz<1pdaNJnNMEk;Ql%#p`K80*fGs_f`-^4LqHz_VrAw0d0<_L5d~vt>s+dSBG+B~wGQ<(IYkJSO&1 zj=QrJk2+5J-hAIn1u*BJA=+eL&V3wIFGu-oCpl1dKMfg{qk2WVKLoq~nWHC1UAnVB z++#nTk2zOULwg`9VLwAqFIvH*XgIxWvJi~15;XLd?-o2hYqsq?VB9DW7bLRYeZQ3KH2?qtX zdimJV&JjY*L7{V4zUi{|XwAeyk$X@6gQL#T`tJwD-pmE&5S_6`&O>~#UV-J=uCZ3x z!;*-wf=5?$#yhcxrExt4kEOfDdp!=zXf$Q3p))a%a9EzBS7>M4H8E0iSb+~Kbg){0(zXCPr6uo!Kxd`2HG6f^FJAx-oa2PGs%{2MSxJg~j}?&icFs)){SJ zHq^YwoYMOAwL+oYr`-gu;=tS+{35=r@A(=+V?|H%heBc>%#PyOLCI-JK`*O@MmgG> zbxQawEJh8HfZxuXRSkBYn)H)j-|Pm(Bg0Gv_nBA)Dip}n**B*xvLsqbVJ5O4pjPP9 z*Ues>wsZVoBQ85pY)0_!pPFYso0w_1brjS?!Dv_kPS1-~>g^OfgYQ$wawiW~i4r*Q zr;(}!?sgfRu!x1(HgSRD_(=EqjDIZn8>8fAYwZ0s=is*31yxN5Y|YDtD;qdyHzpNu zf9+WWF?xyvRjJz$1{8mEk=@<>Fi53#H@0kubCOs2viAk3-^chY_EztnLSQJLCy;}L z-qRht@YH{Do)hpJ(DV%Jmj30CM>@h8$q(O;1H?Yd=8 zO;aCK_8KC--+4mjV?MNN&mOGt{D(TGF#_48n@9MU2^nGe^uK zzmjbo8}vkyU)TRPA$t80qE3NL;W$Ryv^}@@m5xcOfuiOZoC2mlx%2eHkC9RidfgYR za}v0t*dlI7^U3kz#}mwl>@S(?9CA8cy%Be4r%}z^9AP^nDbeP zQoQ8U-bm(PrKyl8D~*%17Hw6F3XDa$zV`3 zEW%;e zMXe(^+dzX-z5_N0eD<@86i7@ISj@>!g{XAr~pg0&U0iVD0S@N8uTgQvVOd&zt#Wnd5tgjZoE`JiWV zTqPJhFFHRv1Rz+>y_2kPlNF3DyNeh_!W*2K?HCQV&EdIA27Bn21LXH|namC5aP{>iw2P zK9@XjGkNHK^2n>?vH0YP>g1{MtJLH8)bG`)KgUyle@g{$;^<^?AS@2-frBRCU^O`S1dio94#}CuDx1cJ zO=I^+`xi|KVV5Idr4*L)cJ~gvSpOwbkVzT zH)PfV6>}SwPO~eg8<{9xp)z zQAj3MHe0VE8#R$FcJdsiB9!BpndL&t5?{=60c0PNSccHd!+6XZ8lHt`@)0r^hn@eI+^)ML6=a#K84^eVZSa@P5i%1MiQI;j5(BOcl2|+?Am<4mlK@HD6%^!aWCdOhdxb zPwWtIru5WR{3C{v7@?9wbcrhE zW{YQ*yO7GBES9yw%GnZOV$UJdotQNJ5@~zHE;>Ef4spO&>S7KR?ZPbcRR%j(fQgt8 zAxP*1CU&jDmVw|cOz@YjKqWv$VxTCGVzJDkr|Zm$b};b(yeqEqJ~2o92KS6AKg* zvNIE_gw+s=+61x7)lc(@sEJ&$Gqu;Pi6X<5Z@VyUfOOqX;v+TYyIclOPMFfaa+Wu( zW3sw10Ai)cVr_m6W{{FjL}z7~5XC)-qeRS%J}eVgJ0)x+zLtqvEcql?gVL@Qd0sE9 zR^bv+8AfvmSi0sq<{Yu^np&M#e#NgzBY+&FwFa|c4;57_0qYjE5;4|75H9;l;jX;L z!jKoFB9RzoS8`RHNu8oly7*m0V?u+~LG~F>c&`RRc`dyZ*|=y@>*8E8ZIBz!ctV3vO^PAV=W-<)UZl&l zn4fFuFT7iSX(ROIA;A=a8NBGA3o}b8aPx+e?GXaPkm%ngt>!Vz!Y0K5_$H7DeEwDB=zo5M<} zMD-SyVJiF)cgUDCye)$Hp}gS+nx&kGnRSN8IP~nw_wAeZ9eVX0C-r@=?fW^^_xoob zfQL+{Kn9tS!LP~CWHPLd44)>m{30WH`dJnF+06RcU-xq)_jA_ub5Hm4{_5xB8Mvr0 zz;8An@OnTnc|fRcKxBGA?AHK_XE6WFKS=NZAaaIAf-yj;|G!A^?=0=#Ns!j0(b_W_ z4E`ro@NW{NWoG}q3jSY`;FpFrnhMfLkOqS^5~S5)e|KUu6{NLcW#u(Rc)~vmvHuJV z{#}S=W);wqu=vEZ*tnF4sJM3pBQy^T%xDY3{Yk=naIOFEF!0$Q41E6Y7-(tt+`{UA z%LDBVjZL%-%(Qj?Qn`)&pJSl>Eftwtn*WkO+5d$EivO=L@NXlek>L8jNU&hk=09pR zWjOzTQ>$^7^Ot65+!8RrI^_JLR(scfx+h-h>7QE7rt$X8*KamdbNRH=uF74Y)oM>V zBtS8;|Fu?Y(R_4&0Ac)2;}cz@Hmz1G#V`gcOiDO57fZI4ChHi_V?&+RS^afB7OQ*# zFRt@p^ykk zRkF2OdWs%bnnRke=h6#zB4PV0?DACyuZj!iN<_*s3kSCE=t5yH3o<6T!`Q82PuM>w7>3H3>t5Tz{ zZ=V8Ed@o;UH}HY0+n({dc+)oaIeoYQPL)G@Wr#KB+vv~>&UetrcamwE?7_T$YBf}= z;5>~4ZU5A2IiFZ%4_D?tp#Rirs_a_l&#DVBo{kdV%~|+(^(Nz`_xeUp7Gv%`&RvYX z!`?uv)dFcG_$c=N*^iGE-#t!nAUsKkcA{gnNpjP!e4OmQq&1f8A=Yj~^F*N)oIktW zN?Nc$-pc1tskN2#2z8;=jA$df)y%lZd8=7TFVIT^8bYq>dDd24wEgtfJN zeCvtOdO`V!-FjiwQr>z|?cv&bF$pZZfp2EF-zaGp$loaKmRjE^BdZH z33S$h+5o*$Ky8FeZ%~_%8X`N*Y{m{dEgUulJFVO=H+I_if<$)P`9C@Ab_iw{>~@M& zZtQlU+C=ucB}X0hdSsRh_Il-yHun0^5Yc_I>RHGAe$6X|`vbbtoBMV7%wv)W`%F7h_F)ARagmD zt(=xO+w(!+tEKA|clS?uSMC?5)i-;;T%~XO06O5#(J>>YKYP$_)+Y`r>8;V}KJoQZ zA9aqFRUc$>`=z|^9Sq$2GHB2z74{bCP6!fz^z$-z=B>D;&a;o?mG{y8bS%`N)AeXU z$@;pIPS2SgRB3%!)d#*fdlo9V^p=}s5kpsJvI_rk1f2)y^x1b0FMBC9gc|z!(eDI^ zgK`vo1dBab$G`Fg28k~5sJbSU;ea=Pn52G3C20| z-SXE$O6(Ht_Yw3u1tY86*P27vO88C;+E4wZf^Y?-J=3#=RF(>=`rwN-H*A&XT>#{OBRH8B z*m=YoIs)(rKh9hb>XKH3pyfia4st=+lmi`vzv!k$@{`QIs;3u~A9KSn_?oC?Pfd=5 z+k1MOd5&nx>n@k2#N6G_9Wi*weTTsW>`=Jo3&&5)_G()~tPQuj%g%N< zSiSNcDdo*5=UrV_R~MG(wc{`2&MnY3r2ScDvs5j`tHI2zTCqXy0~MS;8)!N@fZTrp D2~_cB literal 10747 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 I2%z@g0JJU}j{pDw diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_slider.py b/sdk/python/packages/flet/integration_tests/examples/material/test_slider.py index cc1643547d..3a590b68d0 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_slider.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_slider.py @@ -1,12 +1,10 @@ import pytest +import examples.controls.slider.basic.main as basic +import examples.controls.slider.custom_label.main as custom_label +import examples.controls.slider.handling_events.main as handling_events import flet as ft import flet.testing as ftt -from examples.controls.slider import ( - basic, - custom_label, - handling_events, -) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_snack_bar.py b/sdk/python/packages/flet/integration_tests/examples/material/test_snack_bar.py index bcc0805bdf..7fa88f8bcf 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_snack_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_snack_bar.py @@ -1,8 +1,10 @@ import pytest +import examples.controls.snack_bar.action.main as action +import examples.controls.snack_bar.basic.main as basic +import examples.controls.snack_bar.counter.main as counter import flet as ft import flet.testing as ftt -from examples.controls.snack_bar import action, basic, counter @pytest.mark.asyncio(loop_scope="function") From 992052d10676f847204c1bfb2471c8ababea06f2 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 15:52:13 -0700 Subject: [PATCH 74/96] Convert examples to per-example project layout Restructure several control examples into standalone example projects: move flat example scripts into example/main.py, add pyproject.toml for each example, and remove control-level __init__.py files. Wrap UIs with ft.SafeArea, add __main__ entrypoints, and make small code adjustments (remove some page.update calls, simplify theme toggle logic, adjust container/layout structure). Update docs includes to reference .../main.py paths and update integration tests to import the new module paths. Adds gallery/metadata entries in new pyproject.toml files to support discovery. --- .../create-flet-example-projects/SKILL.md | 7 +- .../examples/controls/stack/__init__.py | 0 .../controls/stack/absolute_positioning.py | 65 ------------------ .../stack/absolute_positioning/main.py | 67 +++++++++++++++++++ .../stack/absolute_positioning/pyproject.toml | 26 +++++++ .../examples/controls/stack/online_avatar.py | 23 ------- .../controls/stack/online_avatar/main.py | 25 +++++++ .../stack/online_avatar/pyproject.toml | 26 +++++++ .../examples/controls/stack/text_on_image.py | 33 --------- .../controls/stack/text_on_image/main.py | 36 ++++++++++ .../stack/text_on_image/pyproject.toml | 26 +++++++ .../controls/submenu_button/__init__.py | 0 .../{basic.py => basic/main.py} | 33 ++++----- .../submenu_button/basic/pyproject.toml | 26 +++++++ .../{standalone.py => standalone/main.py} | 2 +- .../submenu_button/standalone/pyproject.toml | 26 +++++++ .../examples/controls/switch/__init__.py | 0 sdk/python/examples/controls/switch/basic.py | 25 ------- .../examples/controls/switch/basic/main.py | 30 +++++++++ .../controls/switch/basic/pyproject.toml | 26 +++++++ .../main.py} | 13 ++-- .../switch/handling_events/pyproject.toml | 26 +++++++ .../packages/flet/docs/controls/stack.md | 4 +- .../flet/docs/controls/submenubutton.md | 2 +- .../packages/flet/docs/controls/switch.md | 4 +- .../examples/core/test_stack.py | 6 +- .../examples/material/test_submenu_button.py | 2 +- .../examples/material/test_switch.py | 4 +- 28 files changed, 379 insertions(+), 184 deletions(-) delete mode 100644 sdk/python/examples/controls/stack/__init__.py delete mode 100644 sdk/python/examples/controls/stack/absolute_positioning.py create mode 100644 sdk/python/examples/controls/stack/absolute_positioning/main.py create mode 100644 sdk/python/examples/controls/stack/absolute_positioning/pyproject.toml delete mode 100644 sdk/python/examples/controls/stack/online_avatar.py create mode 100644 sdk/python/examples/controls/stack/online_avatar/main.py create mode 100644 sdk/python/examples/controls/stack/online_avatar/pyproject.toml delete mode 100644 sdk/python/examples/controls/stack/text_on_image.py create mode 100644 sdk/python/examples/controls/stack/text_on_image/main.py create mode 100644 sdk/python/examples/controls/stack/text_on_image/pyproject.toml delete mode 100644 sdk/python/examples/controls/submenu_button/__init__.py rename sdk/python/examples/controls/submenu_button/{basic.py => basic/main.py} (89%) create mode 100644 sdk/python/examples/controls/submenu_button/basic/pyproject.toml rename sdk/python/examples/controls/submenu_button/{standalone.py => standalone/main.py} (96%) create mode 100644 sdk/python/examples/controls/submenu_button/standalone/pyproject.toml delete mode 100644 sdk/python/examples/controls/switch/__init__.py delete mode 100644 sdk/python/examples/controls/switch/basic.py create mode 100644 sdk/python/examples/controls/switch/basic/main.py create mode 100644 sdk/python/examples/controls/switch/basic/pyproject.toml rename sdk/python/examples/controls/switch/{handling_events.py => handling_events/main.py} (58%) create mode 100644 sdk/python/examples/controls/switch/handling_events/pyproject.toml diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index 9c1fc0bb5e..d0bac8903a 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -33,6 +33,7 @@ Ensure each runnable example is a standalone project containing: - If `foo/main.py` already exists, keep it and do not recreate/move files. - If folder exists but `main.py` is missing, repair structure only when there is a clear source file. - Do not create `foo/__init__.py`; import example modules directly in tests/docs (for example `import examples.controls.foo.bar.main as bar` or `import examples.controls.foo.bar as bar` when using namespace-package imports). +- When a control folder has been fully converted to project-per-example layout, delete the control-level `examples/controls//__init__.py` too. The converted folders should behave like namespace packages, matching prior migrations such as commit `7e65ad566`. 3. Add `pyproject.toml` for each example project. - Infer from path and code. @@ -97,22 +98,26 @@ Ensure each runnable example is a standalone project containing: 10. Update references. - Docs code includes: change from `.../example.py` to `.../example/main.py`. +- Inspect the relevant docs pages for each touched control/service/example area (for example `sdk/python/packages/flet/docs/controls/.md`) and update any `--8<--` includes or direct file-path references to the new `main.py` path. - Tests/imports: use direct module imports and avoid relying on package-level `__init__.py` re-exports. - For already-converted examples, only update references that are stale; avoid unnecessary churn. +- If removing a control-level `__init__.py`, confirm no remaining imports rely on `from examples.controls. import ...`. 11. Validate. - Run `python -m compileall` on changed `main.py` files. - Run `uv run ruff check` on changed example files and fix violations until it passes (respecting repository `pyproject.toml` under `[tool.ruff]`). - Search for stale paths to old flat files. +- Search docs and package sources for stale references to the migrated flat example paths and fix any hits in scope. - Check `git status` to confirm expected moves and edits. - When integration tests exist for the touched control, run the targeted test file(s). - Confirm all in-scope `main.py` files include both top-level `ft.SafeArea` wrapping and the `if __name__ == "__main__": ft.run(main)` entrypoint. - Confirm in-scope `ft.SafeArea` wrappers use `expand=True` only where needed for correct behavior and sizing; avoid forcing it by default. - - Confirm there are no unnecessary `page.update()` calls in in-scope examples (unless explicitly required by isolated-control or non-auto-update behavior). - Confirm no in-scope examples use `use_material3`. - Confirm each in-scope `pyproject.toml` has a meaningful, example-specific `[project].description` (not generic or templated text). - Confirm metadata features include `"save to file"` when the example code supports file export/save behavior. +- Confirm there is no stale control-level `__init__.py` left behind once a touched control folder has been fully converted. +- Confirm the relevant docs pages were updated to reference `main.py` and that no stale doc includes remain for the touched examples. ## Code style diff --git a/sdk/python/examples/controls/stack/__init__.py b/sdk/python/examples/controls/stack/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/stack/absolute_positioning.py b/sdk/python/examples/controls/stack/absolute_positioning.py deleted file mode 100644 index 7b02c41874..0000000000 --- a/sdk/python/examples/controls/stack/absolute_positioning.py +++ /dev/null @@ -1,65 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - page.add( - ft.Container( - border_radius=8, - padding=5, - width=200, - height=200, - bgcolor=ft.Colors.BLACK, - content=ft.Stack( - controls=[ - ft.Container( - width=20, - height=20, - bgcolor=ft.Colors.RED, - border_radius=5, - ), - ft.Container( - width=20, - height=20, - bgcolor=ft.Colors.YELLOW, - border_radius=5, - right=0, - ), - ft.Container( - width=20, - height=20, - bgcolor=ft.Colors.BLUE, - border_radius=5, - right=0, - bottom=0, - ), - ft.Container( - width=20, - height=20, - bgcolor=ft.Colors.GREEN, - border_radius=5, - left=0, - bottom=0, - ), - ft.Column( - left=85, - top=85, - controls=[ - ft.Container( - width=20, - height=20, - bgcolor=ft.Colors.PURPLE, - border_radius=5, - ) - ], - ), - ] - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/stack/absolute_positioning/main.py b/sdk/python/examples/controls/stack/absolute_positioning/main.py new file mode 100644 index 0000000000..16bf50da08 --- /dev/null +++ b/sdk/python/examples/controls/stack/absolute_positioning/main.py @@ -0,0 +1,67 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Container( + border_radius=8, + padding=5, + width=200, + height=200, + bgcolor=ft.Colors.BLACK, + content=ft.Stack( + controls=[ + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.RED, + border_radius=5, + ), + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.YELLOW, + border_radius=5, + right=0, + ), + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.BLUE, + border_radius=5, + right=0, + bottom=0, + ), + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.GREEN, + border_radius=5, + left=0, + bottom=0, + ), + ft.Column( + left=85, + top=85, + controls=[ + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.PURPLE, + border_radius=5, + ) + ], + ), + ] + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/stack/absolute_positioning/pyproject.toml b/sdk/python/examples/controls/stack/absolute_positioning/pyproject.toml new file mode 100644 index 0000000000..19508589b2 --- /dev/null +++ b/sdk/python/examples/controls/stack/absolute_positioning/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "stack-absolute-positioning" +version = "1.0.0" +description = "Places colored containers at fixed corners and center positions inside a Stack." +requires-python = ">=3.10" +keywords = ["stack", "layout", "positioning", "absolute", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Stack"] + +[tool.flet.metadata] +title = "Absolute positioning" +controls = ["SafeArea", "Container", "Stack", "Column"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["absolute positioning"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/stack/online_avatar.py b/sdk/python/examples/controls/stack/online_avatar.py deleted file mode 100644 index 328d4c9683..0000000000 --- a/sdk/python/examples/controls/stack/online_avatar.py +++ /dev/null @@ -1,23 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Stack( - width=40, - height=40, - controls=[ - ft.CircleAvatar( - foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" - ), - ft.Container( - content=ft.CircleAvatar(bgcolor=ft.Colors.GREEN, radius=5), - alignment=ft.Alignment.BOTTOM_LEFT, - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/stack/online_avatar/main.py b/sdk/python/examples/controls/stack/online_avatar/main.py new file mode 100644 index 0000000000..d78318471a --- /dev/null +++ b/sdk/python/examples/controls/stack/online_avatar/main.py @@ -0,0 +1,25 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Stack( + width=40, + height=40, + controls=[ + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" + ), + ft.Container( + alignment=ft.Alignment.BOTTOM_LEFT, + content=ft.CircleAvatar(bgcolor=ft.Colors.GREEN, radius=5), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/stack/online_avatar/pyproject.toml b/sdk/python/examples/controls/stack/online_avatar/pyproject.toml new file mode 100644 index 0000000000..6eb6c68f12 --- /dev/null +++ b/sdk/python/examples/controls/stack/online_avatar/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "stack-online-avatar" +version = "1.0.0" +description = "Overlays an online-status badge on top of a profile avatar using Stack." +requires-python = ">=3.10" +keywords = ["stack", "avatar", "status", "overlay", "badge"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Stack"] + +[tool.flet.metadata] +title = "Online avatar" +controls = ["SafeArea", "Stack", "CircleAvatar", "Container"] +layout_pattern = "overlay" +complexity = "basic" +features = ["status indicator"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/stack/text_on_image.py b/sdk/python/examples/controls/stack/text_on_image.py deleted file mode 100644 index dfff5b0e43..0000000000 --- a/sdk/python/examples/controls/stack/text_on_image.py +++ /dev/null @@ -1,33 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Stack( - width=300, - height=300, - controls=[ - ft.Image( - src="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", - width=300, - height=300, - fit=ft.BoxFit.CONTAIN, - ), - ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - ft.Text( - value="Image title", - color=ft.Colors.SURFACE_TINT, - size=40, - weight=ft.FontWeight.BOLD, - opacity=0.5, - ) - ], - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/stack/text_on_image/main.py b/sdk/python/examples/controls/stack/text_on_image/main.py new file mode 100644 index 0000000000..d86b58f4d5 --- /dev/null +++ b/sdk/python/examples/controls/stack/text_on_image/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Stack( + width=300, + height=300, + controls=[ + ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==", + width=300, + height=300, + fit=ft.BoxFit.CONTAIN, + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + value="Image title", + color=ft.Colors.SURFACE_TINT, + size=40, + weight=ft.FontWeight.BOLD, + opacity=0.5, + ) + ], + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/stack/text_on_image/pyproject.toml b/sdk/python/examples/controls/stack/text_on_image/pyproject.toml new file mode 100644 index 0000000000..c4860cfeb3 --- /dev/null +++ b/sdk/python/examples/controls/stack/text_on_image/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "stack-text-on-image" +version = "1.0.0" +description = "Layers a centered title over a base64-backed image inside a Stack." +requires-python = ">=3.10" +keywords = ["stack", "image", "text", "overlay", "base64"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Stack"] + +[tool.flet.metadata] +title = "Text on image" +controls = ["SafeArea", "Stack", "Image", "Row", "Text"] +layout_pattern = "overlay" +complexity = "basic" +features = ["text overlay"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/submenu_button/__init__.py b/sdk/python/examples/controls/submenu_button/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/submenu_button/basic.py b/sdk/python/examples/controls/submenu_button/basic/main.py similarity index 89% rename from sdk/python/examples/controls/submenu_button/basic.py rename to sdk/python/examples/controls/submenu_button/basic/main.py index 7c460ce4c1..ab6e627de2 100644 --- a/sdk/python/examples/controls/submenu_button/basic.py +++ b/sdk/python/examples/controls/submenu_button/basic/main.py @@ -9,17 +9,9 @@ def handle_color_click(e: ft.Event[ft.MenuItemButton]): color = e.control.content.value background_container.content.value = f"{color} background color" background_container.bgcolor = color.lower() - page.update() def handle_alignment_click(e: ft.Event[ft.MenuItemButton]): - print( - f"bg_container.alignment: {background_container.alignment}, bg_container.content: {background_container.content}" - ) background_container.alignment = e.control.data - print( - f"e.control.content.value: {e.control.content.value}, e.control.data: {e.control.data}" - ) - page.update() def handle_on_hover(e: ft.Event[ft.MenuItemButton]): print(f"{e.control.content.value}.on_hover") @@ -123,16 +115,25 @@ def handle_on_hover(e: ft.Event[ft.MenuItemButton]): ) page.add( - ft.Row(controls=[menubar]), - background_container := ft.Container( + ft.SafeArea( expand=True, - bgcolor=ft.Colors.SURFACE_TINT, - alignment=ft.Alignment.CENTER, - content=ft.Text( - value="Choose a bgcolor from the menu", - style=ft.TextStyle(size=24, weight=ft.FontWeight.BOLD), + content=ft.Column( + expand=True, + spacing=0, + controls=[ + ft.Row(controls=[menubar]), + background_container := ft.Container( + expand=True, + bgcolor=ft.Colors.SURFACE_TINT, + alignment=ft.Alignment.CENTER, + content=ft.Text( + value="Choose a bgcolor from the menu", + style=ft.TextStyle(size=24, weight=ft.FontWeight.BOLD), + ), + ), + ], ), - ), + ) ) diff --git a/sdk/python/examples/controls/submenu_button/basic/pyproject.toml b/sdk/python/examples/controls/submenu_button/basic/pyproject.toml new file mode 100644 index 0000000000..43a34f8d99 --- /dev/null +++ b/sdk/python/examples/controls/submenu_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "submenu-button-basic" +version = "1.0.0" +description = "Changes background color and text alignment from nested SubmenuButton menu actions." +requires-python = ">=3.10" +keywords = ["submenu button", "menu", "nested", "alignment", "color"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/SubmenuButton"] + +[tool.flet.metadata] +title = "SubmenuButton basic" +controls = ["SafeArea", "Column", "Row", "MenuBar", "SubmenuButton", "MenuItemButton", "Container", "Text", "Icon"] +layout_pattern = "toolbar-content" +complexity = "basic" +features = ["nested menus", "live style updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/submenu_button/standalone.py b/sdk/python/examples/controls/submenu_button/standalone/main.py similarity index 96% rename from sdk/python/examples/controls/submenu_button/standalone.py rename to sdk/python/examples/controls/submenu_button/standalone/main.py index 1b99645e3e..b4810f5a66 100644 --- a/sdk/python/examples/controls/submenu_button/standalone.py +++ b/sdk/python/examples/controls/submenu_button/standalone/main.py @@ -41,7 +41,7 @@ def main(page: ft.Page): ], ) - page.add(ft.Row(controls=[smb])) + page.add(ft.SafeArea(content=ft.Row(controls=[smb]))) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/submenu_button/standalone/pyproject.toml b/sdk/python/examples/controls/submenu_button/standalone/pyproject.toml new file mode 100644 index 0000000000..a48b321cf5 --- /dev/null +++ b/sdk/python/examples/controls/submenu_button/standalone/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "submenu-button-standalone" +version = "1.0.0" +description = "Shows a standalone SubmenuButton with hover-driven text style previews." +requires-python = ">=3.10" +keywords = ["submenu button", "menu", "text style", "hover", "standalone"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/SubmenuButton"] + +[tool.flet.metadata] +title = "Standalone SubmenuButton" +controls = ["SafeArea", "Row", "SubmenuButton", "MenuItemButton", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["hover styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/switch/__init__.py b/sdk/python/examples/controls/switch/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/switch/basic.py b/sdk/python/examples/controls/switch/basic.py deleted file mode 100644 index 3c8eeeef39..0000000000 --- a/sdk/python/examples/controls/switch/basic.py +++ /dev/null @@ -1,25 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_button_click(e: ft.Event[ft.Button]): - message.value = ( - f"Switch values are: {c1.value}, {c2.value}, {c3.value}, {c4.value}." - ) - page.update() - - page.add( - c1 := ft.Switch(label="Unchecked switch", value=False), - c2 := ft.Switch(label="Checked switch", value=True), - c3 := ft.Switch(label="Disabled switch", disabled=True), - c4 := ft.Switch( - label="Switch with rendered label_position='left'", - label_position=ft.LabelPosition.LEFT, - ), - ft.Button(content="Submit", on_click=handle_button_click), - message := ft.Text(), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/switch/basic/main.py b/sdk/python/examples/controls/switch/basic/main.py new file mode 100644 index 0000000000..e559bcdea2 --- /dev/null +++ b/sdk/python/examples/controls/switch/basic/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = ( + f"Switch values are: {c1.value}, {c2.value}, {c3.value}, {c4.value}." + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + c1 := ft.Switch(label="Unchecked switch", value=False), + c2 := ft.Switch(label="Checked switch", value=True), + c3 := ft.Switch(label="Disabled switch", disabled=True), + c4 := ft.Switch( + label="Switch with rendered label_position='left'", + label_position=ft.LabelPosition.LEFT, + ), + ft.Button(content="Submit", on_click=handle_button_click), + message := ft.Text(), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/switch/basic/pyproject.toml b/sdk/python/examples/controls/switch/basic/pyproject.toml new file mode 100644 index 0000000000..2e517dff88 --- /dev/null +++ b/sdk/python/examples/controls/switch/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "switch-basic" +version = "1.0.0" +description = "Compares checked, unchecked, disabled, and left-labeled Switch controls and reports their values." +requires-python = ">=3.10" +keywords = ["switch", "input", "states", "button", "label"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Switch"] + +[tool.flet.metadata] +title = "Switch basic" +controls = ["SafeArea", "Column", "Switch", "Button", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["multiple states", "value summary"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/switch/handling_events.py b/sdk/python/examples/controls/switch/handling_events/main.py similarity index 58% rename from sdk/python/examples/controls/switch/handling_events.py rename to sdk/python/examples/controls/switch/handling_events/main.py index cdd9768f03..2eef4ef3ed 100644 --- a/sdk/python/examples/controls/switch/handling_events.py +++ b/sdk/python/examples/controls/switch/handling_events/main.py @@ -3,20 +3,19 @@ def main(page: ft.Page): def handle_switch_change(e: ft.Event[ft.Switch]): - page.theme_mode = ( - ft.ThemeMode.DARK - if page.theme_mode == ft.ThemeMode.LIGHT - else ft.ThemeMode.LIGHT - ) + page.theme_mode = ft.ThemeMode.DARK if e.control.value else ft.ThemeMode.LIGHT e.control.label = ( "Light ThemeMode" if page.theme_mode == ft.ThemeMode.LIGHT else "Dark ThemeMode" ) - page.update() page.theme_mode = ft.ThemeMode.LIGHT - page.add(ft.Switch(label="Light ThemeMode", on_change=handle_switch_change)) + page.add( + ft.SafeArea( + content=ft.Switch(label="Light ThemeMode", on_change=handle_switch_change) + ) + ) if __name__ == "__main__": diff --git a/sdk/python/examples/controls/switch/handling_events/pyproject.toml b/sdk/python/examples/controls/switch/handling_events/pyproject.toml new file mode 100644 index 0000000000..45ce19a929 --- /dev/null +++ b/sdk/python/examples/controls/switch/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "switch-handling-events" +version = "1.0.0" +description = "Toggles page theme mode and updates the label when a Switch value changes." +requires-python = ">=3.10" +keywords = ["switch", "events", "theme", "toggle", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Switch"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "Switch"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["change events", "theme toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/stack.md b/sdk/python/packages/flet/docs/controls/stack.md index 493127ccc9..83fe819f67 100644 --- a/sdk/python/packages/flet/docs/controls/stack.md +++ b/sdk/python/packages/flet/docs/controls/stack.md @@ -15,7 +15,7 @@ example_images: ../test-images/examples/core/golden/macos/stack ### Avatar with online status ```python ---8<-- "{{ examples }}/online_avatar.py" +--8<-- "{{ examples }}/online_avatar/main.py" ``` {{ image(example_images + "/online_avatar.png", alt="online-avatar", width="80%") }} @@ -24,7 +24,7 @@ example_images: ../test-images/examples/core/golden/macos/stack ### Absolute positioning ```python ---8<-- "{{ examples }}/absolute_positioning.py" +--8<-- "{{ examples }}/absolute_positioning/main.py" ``` {{ image(example_images + "/absolute_positioning.png", alt="absolute-positioning", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/submenubutton.md b/sdk/python/packages/flet/docs/controls/submenubutton.md index 814cd17748..0004891914 100644 --- a/sdk/python/packages/flet/docs/controls/submenubutton.md +++ b/sdk/python/packages/flet/docs/controls/submenubutton.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/submenu_button ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/switch.md b/sdk/python/packages/flet/docs/controls/switch.md index 522ab1cda1..8687ced97b 100644 --- a/sdk/python/packages/flet/docs/controls/switch.md +++ b/sdk/python/packages/flet/docs/controls/switch.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/switch/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/switch/media ### Handling change events ```python ---8<-- "{{ examples }}/handling_events.py" +--8<-- "{{ examples }}/handling_events/main.py" ``` {{ image(example_media + "/handling_events.gif", alt="handling-events", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_stack.py b/sdk/python/packages/flet/integration_tests/examples/core/test_stack.py index 84cfac06ae..54e929ec84 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_stack.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_stack.py @@ -1,11 +1,9 @@ import pytest +import examples.controls.stack.absolute_positioning.main as absolute_positioning +import examples.controls.stack.online_avatar.main as online_avatar import flet as ft import flet.testing as ftt -from examples.controls.stack import ( - absolute_positioning, - online_avatar, -) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_submenu_button.py b/sdk/python/packages/flet/integration_tests/examples/material/test_submenu_button.py index 28c221b966..34f29a3416 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_submenu_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_submenu_button.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.submenu_button.basic.main as basic import flet as ft import flet.testing as ftt -from examples.controls.submenu_button import basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_switch.py b/sdk/python/packages/flet/integration_tests/examples/material/test_switch.py index 2e5fdc3478..f156ff478d 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_switch.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_switch.py @@ -1,10 +1,8 @@ import pytest +import examples.controls.switch.basic.main as basic import flet as ft import flet.testing as ftt -from examples.controls.switch import ( - basic, -) @pytest.mark.asyncio(loop_scope="function") From 24c90ce1b5c0036acac3af5d9a17a80ae75875af Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 16:06:02 -0700 Subject: [PATCH 75/96] Reorganize Tabs examples into per-example packages Move Tabs examples into dedicated example packages (basic, custom_indicator, dynamic_tab_addition, move_to, nested): delete old top-level example .py files and add per-example main.py and pyproject.toml files. Examples now wrap content in SafeArea and include metadata (pyproject) for gallery listing. Dynamic tab example updated to use @ft.control-style component fields for MyContainer. Update docs (packages/flet/docs/controls/tabs/index.md) to point to the new ".../main.py" example paths. --- sdk/python/examples/controls/tabs/__init__.py | 0 sdk/python/examples/controls/tabs/basic.py | 48 ------------ .../examples/controls/tabs/basic/main.py | 51 ++++++++++++ .../controls/tabs/basic/pyproject.toml | 26 +++++++ .../controls/tabs/custom_indicator.py | 42 ---------- .../controls/tabs/custom_indicator/main.py | 43 ++++++++++ .../tabs/custom_indicator/pyproject.toml | 26 +++++++ .../controls/tabs/dynamic_tab_addition.py | 58 -------------- .../tabs/dynamic_tab_addition/main.py | 65 ++++++++++++++++ .../tabs/dynamic_tab_addition/pyproject.toml | 26 +++++++ sdk/python/examples/controls/tabs/move_to.py | 77 ------------------ .../examples/controls/tabs/move_to/main.py | 78 +++++++++++++++++++ .../controls/tabs/move_to/pyproject.toml | 26 +++++++ sdk/python/examples/controls/tabs/nested.py | 55 ------------- .../examples/controls/tabs/nested/main.py | 58 ++++++++++++++ .../controls/tabs/nested/pyproject.toml | 26 +++++++ .../packages/flet/docs/controls/tabs/index.md | 10 +-- 17 files changed, 430 insertions(+), 285 deletions(-) delete mode 100644 sdk/python/examples/controls/tabs/__init__.py delete mode 100644 sdk/python/examples/controls/tabs/basic.py create mode 100644 sdk/python/examples/controls/tabs/basic/main.py create mode 100644 sdk/python/examples/controls/tabs/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/tabs/custom_indicator.py create mode 100644 sdk/python/examples/controls/tabs/custom_indicator/main.py create mode 100644 sdk/python/examples/controls/tabs/custom_indicator/pyproject.toml delete mode 100644 sdk/python/examples/controls/tabs/dynamic_tab_addition.py create mode 100644 sdk/python/examples/controls/tabs/dynamic_tab_addition/main.py create mode 100644 sdk/python/examples/controls/tabs/dynamic_tab_addition/pyproject.toml delete mode 100644 sdk/python/examples/controls/tabs/move_to.py create mode 100644 sdk/python/examples/controls/tabs/move_to/main.py create mode 100644 sdk/python/examples/controls/tabs/move_to/pyproject.toml delete mode 100644 sdk/python/examples/controls/tabs/nested.py create mode 100644 sdk/python/examples/controls/tabs/nested/main.py create mode 100644 sdk/python/examples/controls/tabs/nested/pyproject.toml diff --git a/sdk/python/examples/controls/tabs/__init__.py b/sdk/python/examples/controls/tabs/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/tabs/basic.py b/sdk/python/examples/controls/tabs/basic.py deleted file mode 100644 index 05ad7b2baa..0000000000 --- a/sdk/python/examples/controls/tabs/basic.py +++ /dev/null @@ -1,48 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Tabs( - selected_index=1, - length=3, - expand=True, - content=ft.Column( - expand=True, - controls=[ - ft.TabBar( - tabs=[ - ft.Tab(label="Tab 1", icon=ft.Icons.SETTINGS_PHONE), - ft.Tab(label="Tab 2", icon=ft.Icons.SETTINGS), - ft.Tab( - label=ft.CircleAvatar( - foreground_image_src="https://avatars.githubusercontent.com/u/102273996?s=200&v=4", - ), - ), - ] - ), - ft.TabBarView( - expand=True, - controls=[ - ft.Container( - content=ft.Text("This is Tab 1"), - alignment=ft.Alignment.CENTER, - ), - ft.Container( - content=ft.Text("This is Tab 2"), - alignment=ft.Alignment.CENTER, - ), - ft.Container( - content=ft.Text("This is Tab 3"), - alignment=ft.Alignment.CENTER, - ), - ], - ), - ], - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/tabs/basic/main.py b/sdk/python/examples/controls/tabs/basic/main.py new file mode 100644 index 0000000000..dcca9fd589 --- /dev/null +++ b/sdk/python/examples/controls/tabs/basic/main.py @@ -0,0 +1,51 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Tabs( + selected_index=1, + length=3, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label="Tab 1", icon=ft.Icons.SETTINGS_PHONE), + ft.Tab(label="Tab 2", icon=ft.Icons.SETTINGS), + ft.Tab( + label=ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/102273996?s=200&v=4", + ), + ), + ] + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 1"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 2"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 3"), + ), + ], + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/tabs/basic/pyproject.toml b/sdk/python/examples/controls/tabs/basic/pyproject.toml new file mode 100644 index 0000000000..ce99e923ec --- /dev/null +++ b/sdk/python/examples/controls/tabs/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-basic" +version = "1.0.0" +description = "Displays a basic Tabs layout with icons, an avatar tab label, and matching tab content." +requires-python = ">=3.10" +keywords = ["tabs", "navigation", "icons", "avatar", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Tabs basic" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "Container", "Text", "CircleAvatar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["icon tabs", "avatar tab label"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/tabs/custom_indicator.py b/sdk/python/examples/controls/tabs/custom_indicator.py deleted file mode 100644 index d0459fffad..0000000000 --- a/sdk/python/examples/controls/tabs/custom_indicator.py +++ /dev/null @@ -1,42 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Tabs( - length=2, - expand=True, - content=ft.Column( - expand=True, - controls=[ - ft.TabBar( - tab_alignment=ft.TabAlignment.START, - indicator_animation=ft.TabIndicatorAnimation.ELASTIC, - indicator_size=ft.TabBarIndicatorSize.LABEL, - indicator=ft.UnderlineTabIndicator( - border_side=ft.BorderSide(5, color=ft.Colors.RED), - border_radius=ft.BorderRadius.all(1), - insets=ft.Padding.only(bottom=5), - ), - # indicator_thickness=5, - # indicator_color=ft.Colors.RED, - tabs=[ - ft.Tab(label=ft.Text("Home")), - ft.Tab(label=ft.Text("My Account")), - ], - ), - ft.TabBarView( - expand=True, - controls=[ - ft.Text("Home Tab Content"), - ft.Text("Profile Tab Content"), - ], - ), - ], - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/tabs/custom_indicator/main.py b/sdk/python/examples/controls/tabs/custom_indicator/main.py new file mode 100644 index 0000000000..937e794a74 --- /dev/null +++ b/sdk/python/examples/controls/tabs/custom_indicator/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Tabs( + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tab_alignment=ft.TabAlignment.START, + indicator_animation=ft.TabIndicatorAnimation.ELASTIC, + indicator_size=ft.TabBarIndicatorSize.LABEL, + indicator=ft.UnderlineTabIndicator( + border_side=ft.BorderSide(5, color=ft.Colors.RED), + border_radius=ft.BorderRadius.all(1), + insets=ft.Padding.only(bottom=5), + ), + tabs=[ + ft.Tab(label=ft.Text("Home")), + ft.Tab(label=ft.Text("My Account")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("Home Tab Content"), + ft.Text("Profile Tab Content"), + ], + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/tabs/custom_indicator/pyproject.toml b/sdk/python/examples/controls/tabs/custom_indicator/pyproject.toml new file mode 100644 index 0000000000..881c26f48a --- /dev/null +++ b/sdk/python/examples/controls/tabs/custom_indicator/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-custom-indicator" +version = "1.0.0" +description = "Customizes the tab underline indicator with elastic animation, rounded corners, and insets." +requires-python = ">=3.10" +keywords = ["tabs", "indicator", "underline", "animation", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Custom tab indicator" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "Text", "UnderlineTabIndicator"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom indicator", "elastic indicator animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/tabs/dynamic_tab_addition.py b/sdk/python/examples/controls/tabs/dynamic_tab_addition.py deleted file mode 100644 index b419abab6f..0000000000 --- a/sdk/python/examples/controls/tabs/dynamic_tab_addition.py +++ /dev/null @@ -1,58 +0,0 @@ -import flet as ft - - -class MyContainer(ft.Container): - def __init__(self, text): - super().__init__( - height=100, - bgcolor=ft.Colors.random(), - alignment=ft.Alignment.CENTER, - ) - self.content = ft.Text(text) - - -def main(page: ft.Page): - def handle_new_tab(e: ft.Event[ft.CupertinoFilledButton]): - tab_count = len(tab_bar.tabs) + 1 - tab_bar.tabs.append(ft.Tab(label=ft.Text(f"Tab {tab_count}"))) - tab_view.controls.append(MyContainer(text=f"Tab {tab_count} content")) - tabs.length = len(tab_bar.tabs) - - page.add( - tabs := ft.Tabs( - length=2, - expand=True, - content=ft.Column( - expand=True, - controls=[ - tab_bar := ft.TabBar( - tab_alignment=ft.TabAlignment.CENTER, - tabs=[ - ft.Tab(label=ft.Text("Tab 1")), - ft.Tab(label=ft.Text("Tab 2")), - ], - ), - ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - ft.CupertinoFilledButton( - content="Add New Tab", - icon=ft.Icons.ADD, - on_click=handle_new_tab, - ), - ], - ), - tab_view := ft.TabBarView( - expand=True, - controls=[ - MyContainer(text="Tab 1 content"), - MyContainer(text="Tab 2 content"), - ], - ), - ], - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/tabs/dynamic_tab_addition/main.py b/sdk/python/examples/controls/tabs/dynamic_tab_addition/main.py new file mode 100644 index 0000000000..2377a757fe --- /dev/null +++ b/sdk/python/examples/controls/tabs/dynamic_tab_addition/main.py @@ -0,0 +1,65 @@ +import flet as ft + + +@ft.control +class MyContainer(ft.Container): + text: str = "" + height: int = 100 + alignment: ft.Alignment = ft.Alignment.CENTER + + def init(self): + self.bgcolor = ft.Colors.random() + self.content = ft.Text(self.text) + + +def main(page: ft.Page): + def handle_new_tab(e: ft.Event[ft.CupertinoFilledButton]): + tab_count = len(tab_bar.tabs) + 1 + tab_bar.tabs.append(ft.Tab(label=ft.Text(f"Tab {tab_count}"))) + tab_view.controls.append(MyContainer(text=f"Tab {tab_count} content")) + tabs.length = len(tab_bar.tabs) + + tabs = ft.Tabs( + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + tab_bar := ft.TabBar( + tab_alignment=ft.TabAlignment.CENTER, + tabs=[ + ft.Tab(label=ft.Text("Tab 1")), + ft.Tab(label=ft.Text("Tab 2")), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.CupertinoFilledButton( + content="Add New Tab", + icon=ft.Icons.ADD, + on_click=handle_new_tab, + ), + ], + ), + tab_view := ft.TabBarView( + expand=True, + controls=[ + MyContainer(text="Tab 1 content"), + MyContainer(text="Tab 2 content"), + ], + ), + ], + ), + ) + + page.add( + ft.SafeArea( + expand=True, + content=tabs, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/tabs/dynamic_tab_addition/pyproject.toml b/sdk/python/examples/controls/tabs/dynamic_tab_addition/pyproject.toml new file mode 100644 index 0000000000..6677164a2b --- /dev/null +++ b/sdk/python/examples/controls/tabs/dynamic_tab_addition/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-dynamic-tab-addition" +version = "1.0.0" +description = "Adds new tabs and matching content panels dynamically from a button click." +requires-python = ">=3.10" +keywords = ["tabs", "dynamic", "add tab", "button", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Dynamic tab addition" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "Row", "CupertinoFilledButton", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["dynamic tabs", "button-driven updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/tabs/move_to.py b/sdk/python/examples/controls/tabs/move_to.py deleted file mode 100644 index 9859fed3cf..0000000000 --- a/sdk/python/examples/controls/tabs/move_to.py +++ /dev/null @@ -1,77 +0,0 @@ -import random - -import flet as ft - - -def main(page: ft.Page): - async def handle_move_to_random(e: ft.Event[ft.FloatingActionButton]): - # random index, excluding the current one - i = random.choice([i for i in range(tabs.length) if i != tabs.selected_index]) - - await tabs.move_to( - index=i, - animation_curve=ft.AnimationCurve.FAST_OUT_SLOWIN, - animation_duration=ft.Duration(seconds=3), - ) - - page.floating_action_button = ft.FloatingActionButton( - icon=ft.Icons.MOVE_UP, - content="Move to a random tab", - on_click=handle_move_to_random, - ) - - page.add( - tabs := ft.Tabs( - length=6, - selected_index=5, - expand=True, - content=ft.Column( - expand=True, - controls=[ - ft.TabBar( - tab_alignment=ft.TabAlignment.CENTER, - tabs=[ - ft.Tab(label=ft.Text("Tab 1")), - ft.Tab(label=ft.Text("Tab 2")), - ft.Tab(label=ft.Text("Tab 3")), - ft.Tab(label=ft.Text("Tab 4")), - ft.Tab(label=ft.Text("Tab 5")), - ft.Tab(label=ft.Text("Tab 6")), - ], - ), - ft.TabBarView( - expand=True, - controls=[ - ft.Container( - content=ft.Text("Tab 1 content"), - alignment=ft.Alignment.CENTER, - ), - ft.Container( - content=ft.Text("Tab 2 content"), - alignment=ft.Alignment.CENTER, - ), - ft.Container( - content=ft.Text("Tab 3 content"), - alignment=ft.Alignment.CENTER, - ), - ft.Container( - content=ft.Text("Tab 4 content"), - alignment=ft.Alignment.CENTER, - ), - ft.Container( - content=ft.Text("Tab 5 content"), - alignment=ft.Alignment.CENTER, - ), - ft.Container( - content=ft.Text("Tab 6 content"), - alignment=ft.Alignment.CENTER, - ), - ], - ), - ], - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/tabs/move_to/main.py b/sdk/python/examples/controls/tabs/move_to/main.py new file mode 100644 index 0000000000..c8b961e0e7 --- /dev/null +++ b/sdk/python/examples/controls/tabs/move_to/main.py @@ -0,0 +1,78 @@ +import random + +import flet as ft + + +def main(page: ft.Page): + async def handle_move_to_random(e: ft.Event[ft.FloatingActionButton]): + # random index, excluding the current one + i = random.choice([i for i in range(tabs.length) if i != tabs.selected_index]) + + await tabs.move_to( + index=i, + animation_curve=ft.AnimationCurve.FAST_OUT_SLOWIN, + animation_duration=ft.Duration(seconds=3), + ) + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.MOVE_UP, + content="Move to a random tab", + on_click=handle_move_to_random, + ) + + tabs = ft.Tabs( + length=6, + selected_index=5, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tab_alignment=ft.TabAlignment.CENTER, + tabs=[ + ft.Tab(label=ft.Text("Tab 1")), + ft.Tab(label=ft.Text("Tab 2")), + ft.Tab(label=ft.Text("Tab 3")), + ft.Tab(label=ft.Text("Tab 4")), + ft.Tab(label=ft.Text("Tab 5")), + ft.Tab(label=ft.Text("Tab 6")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 1 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 2 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 3 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 4 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 5 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 6 content"), + ), + ], + ), + ], + ), + ) + + page.add(ft.SafeArea(expand=True, content=tabs)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/tabs/move_to/pyproject.toml b/sdk/python/examples/controls/tabs/move_to/pyproject.toml new file mode 100644 index 0000000000..c975d28d7c --- /dev/null +++ b/sdk/python/examples/controls/tabs/move_to/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-move-to" +version = "1.0.0" +description = "Animates programmatic tab switching to a random tab using Tabs.move_to." +requires-python = ">=3.10" +keywords = ["tabs", "move_to", "animation", "async", "navigation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Programmatic tab switch" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "FloatingActionButton", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["programmatic tab switching", "animated transitions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/tabs/nested.py b/sdk/python/examples/controls/tabs/nested.py deleted file mode 100644 index f17fb5f7b0..0000000000 --- a/sdk/python/examples/controls/tabs/nested.py +++ /dev/null @@ -1,55 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Tabs( - length=2, - selected_index=1, - expand=True, - content=ft.Column( - expand=True, - controls=[ - ft.TabBar( - tabs=[ - ft.Tab(label=ft.Text("Main Tab 1")), - ft.Tab(label=ft.Text("Main Tab 2")), - ], - ), - ft.TabBarView( - expand=True, - controls=[ - ft.Text("Main Tab 1 content"), - ft.Tabs( - length=2, - expand=True, - content=ft.Column( - expand=True, - controls=[ - ft.TabBar( - secondary=True, - tabs=[ - ft.Tab(label=ft.Text("SubTab 1")), - ft.Tab(label=ft.Text("SubTab 2")), - ], - ), - ft.TabBarView( - expand=True, - controls=[ - ft.Text("Nested Tab 1 content"), - ft.Text("Nested Tab 2 content"), - ], - ), - ], - ), - ), - ], - ), - ], - ), - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/tabs/nested/main.py b/sdk/python/examples/controls/tabs/nested/main.py new file mode 100644 index 0000000000..3bf34173eb --- /dev/null +++ b/sdk/python/examples/controls/tabs/nested/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Tabs( + length=2, + selected_index=1, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label=ft.Text("Main Tab 1")), + ft.Tab(label=ft.Text("Main Tab 2")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("Main Tab 1 content"), + ft.Tabs( + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + secondary=True, + tabs=[ + ft.Tab(label=ft.Text("SubTab 1")), + ft.Tab(label=ft.Text("SubTab 2")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("Nested Tab 1 content"), + ft.Text("Nested Tab 2 content"), + ], + ), + ], + ), + ), + ], + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/tabs/nested/pyproject.toml b/sdk/python/examples/controls/tabs/nested/pyproject.toml new file mode 100644 index 0000000000..c0278892dc --- /dev/null +++ b/sdk/python/examples/controls/tabs/nested/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-nested" +version = "1.0.0" +description = "Embeds a secondary Tabs control inside a parent tab to demonstrate nested navigation." +requires-python = ">=3.10" +keywords = ["tabs", "nested", "secondary", "navigation", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Nested tabs" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["nested tabs", "secondary tab bar"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/tabs/index.md b/sdk/python/packages/flet/docs/controls/tabs/index.md index 001046e97d..9ea3c36697 100644 --- a/sdk/python/packages/flet/docs/controls/tabs/index.md +++ b/sdk/python/packages/flet/docs/controls/tabs/index.md @@ -15,7 +15,7 @@ example_images: ../../examples/controls/tabs/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.gif", width="80%") }} @@ -24,25 +24,25 @@ example_images: ../../examples/controls/tabs/media ### Nesting tabs ```python ---8<-- "{{ examples }}/nested.py" +--8<-- "{{ examples }}/nested/main.py" ``` ### Dynamic tab addition ```python ---8<-- "{{ examples }}/dynamic_tab_addition.py" +--8<-- "{{ examples }}/dynamic_tab_addition/main.py" ``` ### Custom indicator ```python ---8<-- "{{ examples }}/custom_indicator.py" +--8<-- "{{ examples }}/custom_indicator/main.py" ``` ### Programmatical Tab switch ```python ---8<-- "{{ examples }}/move_to.py" +--8<-- "{{ examples }}/move_to/main.py" ``` {{ class_members(class_name) }} From 9c0b90d00542b3bfa087ae4d26c22711dfa09306 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 16:25:10 -0700 Subject: [PATCH 76/96] Move text & text_button examples into main.py Reorganize Python UI examples by replacing flat example scripts with per-example packages: deleted legacy example files and added main.py and pyproject.toml in each example folder (controls/text/* and controls/text_button/*). UI layouts are wrapped with SafeArea/Column, and each example now includes package metadata for the Flet gallery. Update docs to reference the new example paths and adjust integration test imports to the new module locations. --- .../examples/controls/text/custom_styles.py | 68 ---------- .../controls/text/custom_styles/main.py | 125 ++++++++++++++++++ .../text/custom_styles/pyproject.toml | 26 ++++ .../examples/controls/text/rich_text_basic.py | 103 --------------- .../controls/text/rich_text_basic/main.py | 123 +++++++++++++++++ .../text/rich_text_basic/pyproject.toml | 26 ++++ .../controls/text/rich_text_border_stroke.py | 41 ------ .../text/rich_text_border_stroke/main.py | 44 ++++++ .../rich_text_border_stroke/pyproject.toml | 26 ++++ .../controls/text/rich_text_gradient.py | 27 ---- .../controls/text/rich_text_gradient/main.py | 30 +++++ .../text/rich_text_gradient/pyproject.toml | 26 ++++ .../controls/text/text_theme_styles.py | 27 ---- .../controls/text/text_theme_styles/main.py | 55 ++++++++ .../text/text_theme_styles/pyproject.toml | 26 ++++ .../controls/text/variable_font_weight.py | 31 ----- .../text/variable_font_weight/main.py | 38 ++++++ .../text/variable_font_weight/pyproject.toml | 26 ++++ .../examples/controls/text_button/__init__.py | 0 .../examples/controls/text_button/basic.py | 14 -- .../controls/text_button/basic/main.py | 20 +++ .../controls/text_button/basic/pyproject.toml | 26 ++++ .../controls/text_button/custom_content.py | 36 ----- .../text_button/custom_content/main.py | 42 ++++++ .../text_button/custom_content/pyproject.toml | 26 ++++ .../controls/text_button/handling_clicks.py | 25 ---- .../text_button/handling_clicks/main.py | 33 +++++ .../handling_clicks/pyproject.toml | 26 ++++ .../examples/controls/text_button/icons.py | 18 --- .../controls/text_button/icons/main.py | 27 ++++ .../controls/text_button/icons/pyproject.toml | 26 ++++ .../packages/flet/docs/controls/text.md | 12 +- .../packages/flet/docs/controls/textbutton.md | 8 +- .../examples/material/test_text_button.py | 5 +- 34 files changed, 811 insertions(+), 401 deletions(-) delete mode 100644 sdk/python/examples/controls/text/custom_styles.py create mode 100644 sdk/python/examples/controls/text/custom_styles/main.py create mode 100644 sdk/python/examples/controls/text/custom_styles/pyproject.toml delete mode 100644 sdk/python/examples/controls/text/rich_text_basic.py create mode 100644 sdk/python/examples/controls/text/rich_text_basic/main.py create mode 100644 sdk/python/examples/controls/text/rich_text_basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/text/rich_text_border_stroke.py create mode 100644 sdk/python/examples/controls/text/rich_text_border_stroke/main.py create mode 100644 sdk/python/examples/controls/text/rich_text_border_stroke/pyproject.toml delete mode 100644 sdk/python/examples/controls/text/rich_text_gradient.py create mode 100644 sdk/python/examples/controls/text/rich_text_gradient/main.py create mode 100644 sdk/python/examples/controls/text/rich_text_gradient/pyproject.toml delete mode 100644 sdk/python/examples/controls/text/text_theme_styles.py create mode 100644 sdk/python/examples/controls/text/text_theme_styles/main.py create mode 100644 sdk/python/examples/controls/text/text_theme_styles/pyproject.toml delete mode 100644 sdk/python/examples/controls/text/variable_font_weight.py create mode 100644 sdk/python/examples/controls/text/variable_font_weight/main.py create mode 100644 sdk/python/examples/controls/text/variable_font_weight/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_button/__init__.py delete mode 100644 sdk/python/examples/controls/text_button/basic.py create mode 100644 sdk/python/examples/controls/text_button/basic/main.py create mode 100644 sdk/python/examples/controls/text_button/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_button/custom_content.py create mode 100644 sdk/python/examples/controls/text_button/custom_content/main.py create mode 100644 sdk/python/examples/controls/text_button/custom_content/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_button/handling_clicks.py create mode 100644 sdk/python/examples/controls/text_button/handling_clicks/main.py create mode 100644 sdk/python/examples/controls/text_button/handling_clicks/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_button/icons.py create mode 100644 sdk/python/examples/controls/text_button/icons/main.py create mode 100644 sdk/python/examples/controls/text_button/icons/pyproject.toml diff --git a/sdk/python/examples/controls/text/custom_styles.py b/sdk/python/examples/controls/text/custom_styles.py deleted file mode 100644 index fa7824d3ec..0000000000 --- a/sdk/python/examples/controls/text/custom_styles.py +++ /dev/null @@ -1,68 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Text custom styles" - page.scroll = ft.ScrollMode.ADAPTIVE - - page.add( - ft.Text("Size 10", size=10), - ft.Text("Size 30, Italic", size=30, color=ft.Colors.PINK_600, italic=True), - ft.Text( - value="Size 40, w100", - size=40, - color=ft.Colors.WHITE, - bgcolor=ft.Colors.BLUE_600, - weight=ft.FontWeight.W_100, - ), - ft.Text( - value="Size 50, Normal", - size=50, - color=ft.Colors.WHITE, - bgcolor=ft.Colors.ORANGE_800, - weight=ft.FontWeight.NORMAL, - ), - ft.Text( - value="Size 60, Bold, Italic", - size=50, - color=ft.Colors.WHITE, - bgcolor=ft.Colors.GREEN_700, - weight=ft.FontWeight.BOLD, - italic=True, - ), - ft.Text( - value="Size 70, w900, selectable", - size=70, - weight=ft.FontWeight.W_900, - selectable=True, - ), - ft.Text( - value="Limit long text to 1 line with ellipsis", - theme_style=ft.TextThemeStyle.HEADLINE_SMALL, - ), - ft.Text( - value="Proin rutrum, purus sit amet elementum volutpat, nunc lacus vulputate orci, cursus ultrices neque dui quis purus. Ut ultricies purus nec nibh bibendum, eget vestibulum metus various. Duis convallis maximus justo, eu rutrum libero maximus id. Donec ullamcorper arcu in sapien molestie, non pellentesque tellus pellentesque. Nulla nec tristique ex. Maecenas euismod nisl enim, a convallis arcu laoreet at. Ut at tortor finibus, rutrum massa sit amet, pulvinar velit. Phasellus diam lorem, viverra vitae leo vitae, consequat suscipit lorem.", - max_lines=1, - overflow=ft.TextOverflow.ELLIPSIS, - ), - ft.Text( - value="Limit long text to 2 lines and fading", - theme_style=ft.TextThemeStyle.HEADLINE_SMALL, - ), - ft.Text( - value="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur quis nibh vitae purus consectetur facilisis sed vitae ipsum. Quisque faucibus sed nulla placerat sagittis. Phasellus condimentum risus vitae nulla vestibulum auctor. Curabitur scelerisque, nibh eget imperdiet consequat, odio ante tempus diam, sed volutpat nisl erat eget turpis. Sed viverra, diam sit amet blandit vulputate, mi tellus dapibus lorem, vitae vehicula diam mauris placerat diam. Morbi sit amet pretium turpis, et consequat ligula. Nulla velit sem, suscipit sit amet dictum non, tincidunt sed nulla. Aenean pellentesque odio porttitor sagittis aliquam. Name various at metus vitae vulputate. Praesent faucibus nibh lorem, eu pretium dolor dictum nec. Phasellus eget dui laoreet, viverra magna vitae, pellentesque diam.", - max_lines=2, - ), - ft.Text( - value="Limit the width and height of long text", - theme_style=ft.TextThemeStyle.HEADLINE_SMALL, - ), - ft.Text( - value="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur quis nibh vitae purus consectetur facilisis sed vitae ipsum. Quisque faucibus sed nulla placerat sagittis. Phasellus condimentum risus vitae nulla vestibulum auctor. Curabitur scelerisque, nibh eget imperdiet consequat, odio ante tempus diam, sed volutpat nisl erat eget turpis. Sed viverra, diam sit amet blandit vulputate, mi tellus dapibus lorem, vitae vehicula diam mauris placerat diam. Morbi sit amet pretium turpis, et consequat ligula. Nulla velit sem, suscipit sit amet dictum non, tincidunt sed nulla. Aenean pellentesque odio porttitor sagittis aliquam. Name various at metus vitae vulputate. Praesent faucibus nibh lorem, eu pretium dolor dictum nec. Phasellus eget dui laoreet, viverra magna vitae, pellentesque diam.", - width=700, - height=100, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text/custom_styles/main.py b/sdk/python/examples/controls/text/custom_styles/main.py new file mode 100644 index 0000000000..ef783de13a --- /dev/null +++ b/sdk/python/examples/controls/text/custom_styles/main.py @@ -0,0 +1,125 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Text custom styles" + page.scroll = ft.ScrollMode.ADAPTIVE + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Size 10", size=10), + ft.Text( + "Size 30, Italic", + size=30, + color=ft.Colors.PINK_600, + italic=True, + ), + ft.Text( + value="Size 40, w100", + size=40, + color=ft.Colors.WHITE, + bgcolor=ft.Colors.BLUE_600, + weight=ft.FontWeight.W_100, + ), + ft.Text( + value="Size 50, Normal", + size=50, + color=ft.Colors.WHITE, + bgcolor=ft.Colors.ORANGE_800, + weight=ft.FontWeight.NORMAL, + ), + ft.Text( + value="Size 60, Bold, Italic", + size=50, + color=ft.Colors.WHITE, + bgcolor=ft.Colors.GREEN_700, + weight=ft.FontWeight.BOLD, + italic=True, + ), + ft.Text( + value="Size 70, w900, selectable", + size=70, + weight=ft.FontWeight.W_900, + selectable=True, + ), + ft.Text( + value="Limit long text to 1 line with ellipsis", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Text( + value=( + "Proin rutrum, purus sit amet elementum volutpat, nunc " + "lacus vulputate orci, cursus ultrices neque dui quis " + "purus. Ut ultricies purus nec nibh bibendum, eget " + "vestibulum metus various. Duis convallis maximus justo, " + "eu rutrum libero maximus id. Donec ullamcorper arcu in " + "sapien molestie, non pellentesque tellus pellentesque. " + "Nulla nec tristique ex. Maecenas euismod nisl enim, a " + "convallis arcu laoreet at. Ut at tortor finibus, rutrum " + "massa sit amet, pulvinar velit. Phasellus diam lorem, " + "viverra vitae leo vitae, consequat suscipit lorem." + ), + max_lines=1, + overflow=ft.TextOverflow.ELLIPSIS, + ), + ft.Text( + value="Limit long text to 2 lines and fading", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Text( + value=( + "Lorem ipsum dolor sit amet, consectetur adipiscing " + "elit. Curabitur quis nibh vitae purus consectetur " + "facilisis sed vitae ipsum. Quisque faucibus sed nulla " + "placerat sagittis. Phasellus condimentum risus vitae " + "nulla vestibulum auctor. Curabitur scelerisque, nibh " + "eget imperdiet consequat, odio ante tempus diam, sed " + "volutpat nisl erat eget turpis. Sed viverra, diam sit " + "amet blandit vulputate, mi tellus dapibus lorem, vitae " + "vehicula diam mauris placerat diam. Morbi sit amet " + "pretium turpis, et consequat ligula. Nulla velit sem, " + "suscipit sit amet dictum non, tincidunt sed nulla. " + "Aenean pellentesque odio porttitor sagittis aliquam. " + "Name various at metus vitae vulputate. Praesent " + "faucibus nibh lorem, eu pretium dolor dictum nec. " + "Phasellus eget dui laoreet, viverra magna vitae, " + "pellentesque diam." + ), + max_lines=2, + ), + ft.Text( + value="Limit the width and height of long text", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Text( + value=( + "Lorem ipsum dolor sit amet, consectetur adipiscing " + "elit. Curabitur quis nibh vitae purus consectetur " + "facilisis sed vitae ipsum. Quisque faucibus sed nulla " + "placerat sagittis. Phasellus condimentum risus vitae " + "nulla vestibulum auctor. Curabitur scelerisque, nibh " + "eget imperdiet consequat, odio ante tempus diam, sed " + "volutpat nisl erat eget turpis. Sed viverra, diam sit " + "amet blandit vulputate, mi tellus dapibus lorem, vitae " + "vehicula diam mauris placerat diam. Morbi sit amet " + "pretium turpis, et consequat ligula. Nulla velit sem, " + "suscipit sit amet dictum non, tincidunt sed nulla. " + "Aenean pellentesque odio porttitor sagittis aliquam. " + "Name various at metus vitae vulputate. Praesent " + "faucibus nibh lorem, eu pretium dolor dictum nec. " + "Phasellus eget dui laoreet, viverra magna vitae, " + "pellentesque diam." + ), + width=700, + height=100, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text/custom_styles/pyproject.toml b/sdk/python/examples/controls/text/custom_styles/pyproject.toml new file mode 100644 index 0000000000..bde8060435 --- /dev/null +++ b/sdk/python/examples/controls/text/custom_styles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-custom-styles" +version = "1.0.0" +description = "Demonstrates Text size, color, weight, selection, and overflow styling variations." +requires-python = ">=3.10" +keywords = ["text", "styles", "typography", "overflow", "selection"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Display/Text"] + +[tool.flet.metadata] +title = "Custom text styles" +controls = ["SafeArea", "Column", "Text"] +layout_pattern = "stacked-content" +complexity = "basic" +features = ["custom text styling", "overflow handling", "selectable text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text/rich_text_basic.py b/sdk/python/examples/controls/text/rich_text_basic.py deleted file mode 100644 index 44e8cb2f6e..0000000000 --- a/sdk/python/examples/controls/text/rich_text_basic.py +++ /dev/null @@ -1,103 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Text("Plain text with default style"), - ft.Text("Selectable plain text with default style", selectable=True), - ft.Text( - value="Some text", - selectable=True, - size=30, - spans=[ - ft.TextSpan( - text="here goes italic", - style=ft.TextStyle(italic=True, size=20, color=ft.Colors.GREEN), - spans=[ - ft.TextSpan( - text="bold and italic", - style=ft.TextStyle(weight=ft.FontWeight.BOLD), - ), - ft.TextSpan( - text="just italic", - spans=[ - ft.TextSpan("smaller italic", ft.TextStyle(size=15)) - ], - ), - ], - ) - ], - ), - ft.Text( - disabled=False, - spans=[ - ft.TextSpan( - text="underlined and clickable", - style=ft.TextStyle(decoration=ft.TextDecoration.UNDERLINE), - on_click=lambda e: print(f"Clicked span: {e.control}"), - on_enter=lambda e: print(f"Entered span: {e.control}"), - on_exit=lambda e: print(f"Exited span: {e.control}"), - ), - ft.TextSpan(text=" "), - ft.TextSpan( - text="underlined red wavy", - style=ft.TextStyle( - decoration=ft.TextDecoration.UNDERLINE, - decoration_color=ft.Colors.RED, - decoration_style=ft.TextDecorationStyle.WAVY, - ), - on_enter=lambda e: print(f"Entered span: {e.control}"), - on_exit=lambda e: print(f"Exited span: {e.control}"), - ), - ft.TextSpan(text=" "), - ft.TextSpan( - text="overlined blue", - style=ft.TextStyle( - decoration=ft.TextDecoration.OVERLINE, decoration_color="blue" - ), - ), - ft.TextSpan(text=" "), - ft.TextSpan( - text="overlined and underlined", - style=ft.TextStyle( - decoration=ft.TextDecoration.OVERLINE - | ft.TextDecoration.UNDERLINE - ), - ), - ft.TextSpan(text=" "), - ft.TextSpan( - text="line through thick", - style=ft.TextStyle( - decoration=ft.TextDecoration.LINE_THROUGH, - decoration_thickness=3, - ), - ), - ], - ), - ) - - def handle_link_highlight(e: ft.Event[ft.TextSpan]): - e.control.style.color = ft.Colors.BLUE - e.control.update() - - def handle_link_unhighlight(e: ft.Event[ft.TextSpan]): - e.control.style.color = None - e.control.update() - - page.add( - ft.Text( - disabled=False, - spans=[ - ft.TextSpan( - text="Go to Google", - style=ft.TextStyle(decoration=ft.TextDecoration.UNDERLINE), - url="https://google.com", - on_enter=handle_link_highlight, - on_exit=handle_link_unhighlight, - ) - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text/rich_text_basic/main.py b/sdk/python/examples/controls/text/rich_text_basic/main.py new file mode 100644 index 0000000000..d60c089721 --- /dev/null +++ b/sdk/python/examples/controls/text/rich_text_basic/main.py @@ -0,0 +1,123 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Plain text with default style"), + ft.Text( + "Selectable plain text with default style", + selectable=True, + ), + ft.Text( + value="Some text", + selectable=True, + size=30, + spans=[ + ft.TextSpan( + text="here goes italic", + style=ft.TextStyle( + italic=True, + size=20, + color=ft.Colors.GREEN, + ), + spans=[ + ft.TextSpan( + text="bold and italic", + style=ft.TextStyle(weight=ft.FontWeight.BOLD), + ), + ft.TextSpan( + text="just italic", + spans=[ + ft.TextSpan( + "smaller italic", + ft.TextStyle(size=15), + ) + ], + ), + ], + ) + ], + ), + ft.Text( + disabled=False, + spans=[ + ft.TextSpan( + text="underlined and clickable", + style=ft.TextStyle( + decoration=ft.TextDecoration.UNDERLINE + ), + on_click=lambda e: print(f"Clicked span: {e.control}"), + on_enter=lambda e: print(f"Entered span: {e.control}"), + on_exit=lambda e: print(f"Exited span: {e.control}"), + ), + ft.TextSpan(text=" "), + ft.TextSpan( + text="underlined red wavy", + style=ft.TextStyle( + decoration=ft.TextDecoration.UNDERLINE, + decoration_color=ft.Colors.RED, + decoration_style=ft.TextDecorationStyle.WAVY, + ), + on_enter=lambda e: print(f"Entered span: {e.control}"), + on_exit=lambda e: print(f"Exited span: {e.control}"), + ), + ft.TextSpan(text=" "), + ft.TextSpan( + text="overlined blue", + style=ft.TextStyle( + decoration=ft.TextDecoration.OVERLINE, + decoration_color="blue", + ), + ), + ft.TextSpan(text=" "), + ft.TextSpan( + text="overlined and underlined", + style=ft.TextStyle( + decoration=ft.TextDecoration.OVERLINE + | ft.TextDecoration.UNDERLINE + ), + ), + ft.TextSpan(text=" "), + ft.TextSpan( + text="line through thick", + style=ft.TextStyle( + decoration=ft.TextDecoration.LINE_THROUGH, + decoration_thickness=3, + ), + ), + ], + ), + ], + ), + ), + ) + + def handle_link_highlight(e: ft.Event[ft.TextSpan]): + e.control.style.color = ft.Colors.BLUE + e.control.update() + + def handle_link_unhighlight(e: ft.Event[ft.TextSpan]): + e.control.style.color = None + e.control.update() + + page.add( + ft.Text( + disabled=False, + spans=[ + ft.TextSpan( + text="Go to Google", + style=ft.TextStyle(decoration=ft.TextDecoration.UNDERLINE), + url="https://google.com", + on_enter=handle_link_highlight, + on_exit=handle_link_unhighlight, + ) + ], + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text/rich_text_basic/pyproject.toml b/sdk/python/examples/controls/text/rich_text_basic/pyproject.toml new file mode 100644 index 0000000000..a1de30b4db --- /dev/null +++ b/sdk/python/examples/controls/text/rich_text_basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-rich-text-basic" +version = "1.0.0" +description = "Combines nested TextSpan styles, interactive spans, and an external link in rich text." +requires-python = ">=3.10" +keywords = ["text", "rich text", "textspan", "link", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Display/Text"] + +[tool.flet.metadata] +title = "Basic rich text" +controls = ["SafeArea", "Column", "Text", "TextSpan"] +layout_pattern = "stacked-content" +complexity = "basic" +features = ["nested text spans", "clickable spans", "external links"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text/rich_text_border_stroke.py b/sdk/python/examples/controls/text/rich_text_border_stroke.py deleted file mode 100644 index 4a702e657c..0000000000 --- a/sdk/python/examples/controls/text/rich_text_border_stroke.py +++ /dev/null @@ -1,41 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Stack( - controls=[ - ft.Text( - spans=[ - ft.TextSpan( - text="Greetings, planet!", - style=ft.TextStyle( - size=40, - weight=ft.FontWeight.BOLD, - foreground=ft.Paint( - color=ft.Colors.BLUE_700, - stroke_width=6, - style=ft.PaintingStyle.STROKE, - ), - ), - ), - ], - ), - ft.Text( - spans=[ - ft.TextSpan( - text="Greetings, planet!", - style=ft.TextStyle( - size=40, - weight=ft.FontWeight.BOLD, - color=ft.Colors.GREY_300, - ), - ), - ], - ), - ] - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text/rich_text_border_stroke/main.py b/sdk/python/examples/controls/text/rich_text_border_stroke/main.py new file mode 100644 index 0000000000..8ccbded7c4 --- /dev/null +++ b/sdk/python/examples/controls/text/rich_text_border_stroke/main.py @@ -0,0 +1,44 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Stack( + controls=[ + ft.Text( + spans=[ + ft.TextSpan( + text="Greetings, planet!", + style=ft.TextStyle( + size=40, + weight=ft.FontWeight.BOLD, + foreground=ft.Paint( + color=ft.Colors.BLUE_700, + stroke_width=6, + style=ft.PaintingStyle.STROKE, + ), + ), + ), + ], + ), + ft.Text( + spans=[ + ft.TextSpan( + text="Greetings, planet!", + style=ft.TextStyle( + size=40, + weight=ft.FontWeight.BOLD, + color=ft.Colors.GREY_300, + ), + ), + ], + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text/rich_text_border_stroke/pyproject.toml b/sdk/python/examples/controls/text/rich_text_border_stroke/pyproject.toml new file mode 100644 index 0000000000..486e979df2 --- /dev/null +++ b/sdk/python/examples/controls/text/rich_text_border_stroke/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-rich-text-border-stroke" +version = "1.0.0" +description = "Layers stroked and filled rich text in a Stack to create an outlined title effect." +requires-python = ">=3.10" +keywords = ["text", "rich text", "stroke", "outline", "stack"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Display/Text"] + +[tool.flet.metadata] +title = "Rich text border stroke" +controls = ["SafeArea", "Stack", "Text", "TextSpan"] +layout_pattern = "overlay" +complexity = "basic" +features = ["stroked text effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text/rich_text_gradient.py b/sdk/python/examples/controls/text/rich_text_gradient.py deleted file mode 100644 index 9941aaaf46..0000000000 --- a/sdk/python/examples/controls/text/rich_text_gradient.py +++ /dev/null @@ -1,27 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Text( - spans=[ - ft.TextSpan( - text="Greetings, planet!", - style=ft.TextStyle( - size=40, - weight=ft.FontWeight.BOLD, - foreground=ft.Paint( - gradient=ft.PaintLinearGradient( - begin=(0, 20), - end=(150, 20), - colors=[ft.Colors.RED, ft.Colors.YELLOW], - ) - ), - ), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text/rich_text_gradient/main.py b/sdk/python/examples/controls/text/rich_text_gradient/main.py new file mode 100644 index 0000000000..613acd0559 --- /dev/null +++ b/sdk/python/examples/controls/text/rich_text_gradient/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Text( + spans=[ + ft.TextSpan( + text="Greetings, planet!", + style=ft.TextStyle( + size=40, + weight=ft.FontWeight.BOLD, + foreground=ft.Paint( + gradient=ft.PaintLinearGradient( + begin=(0, 20), + end=(150, 20), + colors=[ft.Colors.RED, ft.Colors.YELLOW], + ) + ), + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text/rich_text_gradient/pyproject.toml b/sdk/python/examples/controls/text/rich_text_gradient/pyproject.toml new file mode 100644 index 0000000000..371a207ccb --- /dev/null +++ b/sdk/python/examples/controls/text/rich_text_gradient/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-rich-text-gradient" +version = "1.0.0" +description = "Applies a linear gradient paint to rich text for a multicolor title." +requires-python = ">=3.10" +keywords = ["text", "rich text", "gradient", "paint", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Display/Text"] + +[tool.flet.metadata] +title = "Rich text gradient" +controls = ["SafeArea", "Text", "TextSpan"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["gradient text effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text/text_theme_styles.py b/sdk/python/examples/controls/text/text_theme_styles.py deleted file mode 100644 index cd156bd24c..0000000000 --- a/sdk/python/examples/controls/text/text_theme_styles.py +++ /dev/null @@ -1,27 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Text theme styles" - page.scroll = ft.ScrollMode.ADAPTIVE - - page.add( - ft.Text("Display Large", theme_style=ft.TextThemeStyle.DISPLAY_LARGE), - ft.Text("Display Medium", theme_style=ft.TextThemeStyle.DISPLAY_MEDIUM), - ft.Text("Display Small", theme_style=ft.TextThemeStyle.DISPLAY_SMALL), - ft.Text("Headline Large", theme_style=ft.TextThemeStyle.HEADLINE_LARGE), - ft.Text("Headline Medium", theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM), - ft.Text("Headline Small", theme_style=ft.TextThemeStyle.HEADLINE_SMALL), - ft.Text("Title Large", theme_style=ft.TextThemeStyle.TITLE_LARGE), - ft.Text("Title Medium", theme_style=ft.TextThemeStyle.TITLE_MEDIUM), - ft.Text("Title Small", theme_style=ft.TextThemeStyle.TITLE_SMALL), - ft.Text("Label Large", theme_style=ft.TextThemeStyle.LABEL_LARGE), - ft.Text("Label Medium", theme_style=ft.TextThemeStyle.LABEL_MEDIUM), - ft.Text("Label Small", theme_style=ft.TextThemeStyle.LABEL_SMALL), - ft.Text("Body Large", theme_style=ft.TextThemeStyle.BODY_LARGE), - ft.Text("Body Medium", theme_style=ft.TextThemeStyle.BODY_MEDIUM), - ft.Text("Body Small", theme_style=ft.TextThemeStyle.BODY_SMALL), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text/text_theme_styles/main.py b/sdk/python/examples/controls/text/text_theme_styles/main.py new file mode 100644 index 0000000000..7d6fc1f00a --- /dev/null +++ b/sdk/python/examples/controls/text/text_theme_styles/main.py @@ -0,0 +1,55 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Text theme styles" + page.scroll = ft.ScrollMode.ADAPTIVE + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Display Large", + theme_style=ft.TextThemeStyle.DISPLAY_LARGE, + ), + ft.Text( + "Display Medium", + theme_style=ft.TextThemeStyle.DISPLAY_MEDIUM, + ), + ft.Text( + "Display Small", + theme_style=ft.TextThemeStyle.DISPLAY_SMALL, + ), + ft.Text( + "Headline Large", + theme_style=ft.TextThemeStyle.HEADLINE_LARGE, + ), + ft.Text( + "Headline Medium", + theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM, + ), + ft.Text( + "Headline Small", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Text("Title Large", theme_style=ft.TextThemeStyle.TITLE_LARGE), + ft.Text("Title Medium", theme_style=ft.TextThemeStyle.TITLE_MEDIUM), + ft.Text("Title Small", theme_style=ft.TextThemeStyle.TITLE_SMALL), + ft.Text("Label Large", theme_style=ft.TextThemeStyle.LABEL_LARGE), + ft.Text( + "Label Medium", + theme_style=ft.TextThemeStyle.LABEL_MEDIUM, + ), + ft.Text("Label Small", theme_style=ft.TextThemeStyle.LABEL_SMALL), + ft.Text("Body Large", theme_style=ft.TextThemeStyle.BODY_LARGE), + ft.Text("Body Medium", theme_style=ft.TextThemeStyle.BODY_MEDIUM), + ft.Text("Body Small", theme_style=ft.TextThemeStyle.BODY_SMALL), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text/text_theme_styles/pyproject.toml b/sdk/python/examples/controls/text/text_theme_styles/pyproject.toml new file mode 100644 index 0000000000..584681cb20 --- /dev/null +++ b/sdk/python/examples/controls/text/text_theme_styles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-theme-styles" +version = "1.0.0" +description = "Shows the built-in TextThemeStyle variants from display styles through body and labels." +requires-python = ">=3.10" +keywords = ["text", "theme", "typography", "styles", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Display/Text"] + +[tool.flet.metadata] +title = "Theme text styles" +controls = ["SafeArea", "Column", "Text"] +layout_pattern = "stacked-content" +complexity = "basic" +features = ["theme typography"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text/variable_font_weight.py b/sdk/python/examples/controls/text/variable_font_weight.py deleted file mode 100644 index 91b1debdba..0000000000 --- a/sdk/python/examples/controls/text/variable_font_weight.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.fonts = { - "RobotoSlab": "https://github.com/google/fonts/raw/main/apache/robotoslab/RobotoSlab%5Bwght%5D.ttf" - } - - def handle_slider_change(e): - text.weight = f"w{int(e.control.value)}" # noqa - text.update() - - page.add( - text := ft.Text( - "This is rendered with Roboto Slab", - size=30, - font_family="RobotoSlab", - weight=ft.FontWeight.W_100, - ), - ft.Slider( - min=100, - max=900, - divisions=8, - label="Weight = {value}", - width=500, - on_change=handle_slider_change, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text/variable_font_weight/main.py b/sdk/python/examples/controls/text/variable_font_weight/main.py new file mode 100644 index 0000000000..9e8f2aa871 --- /dev/null +++ b/sdk/python/examples/controls/text/variable_font_weight/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.fonts = { + "RobotoSlab": "https://github.com/google/fonts/raw/main/apache/robotoslab/RobotoSlab%5Bwght%5D.ttf" + } + + def handle_slider_change(e): + text.weight = f"w{int(e.control.value)}" # noqa + text.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + text := ft.Text( + "This is rendered with Roboto Slab", + size=30, + font_family="RobotoSlab", + weight=ft.FontWeight.W_100, + ), + ft.Slider( + min=100, + max=900, + divisions=8, + label="Weight = {value}", + width=500, + on_change=handle_slider_change, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text/variable_font_weight/pyproject.toml b/sdk/python/examples/controls/text/variable_font_weight/pyproject.toml new file mode 100644 index 0000000000..a2eb6ab740 --- /dev/null +++ b/sdk/python/examples/controls/text/variable_font_weight/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-variable-font-weight" +version = "1.0.0" +description = "Adjusts a variable font weight interactively with a slider." +requires-python = ">=3.10" +keywords = ["text", "font", "variable", "weight", "slider"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Display/Text"] + +[tool.flet.metadata] +title = "Variable font weight" +controls = ["SafeArea", "Column", "Text", "Slider"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["interactive font weight control"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_button/__init__.py b/sdk/python/examples/controls/text_button/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/text_button/basic.py b/sdk/python/examples/controls/text_button/basic.py deleted file mode 100644 index d140f1af8a..0000000000 --- a/sdk/python/examples/controls/text_button/basic.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Basic text buttons" - - page.add( - ft.TextButton(content="Text button"), - ft.TextButton(content="Disabled button", disabled=True), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/text_button/basic/main.py b/sdk/python/examples/controls/text_button/basic/main.py new file mode 100644 index 0000000000..b9f8c11117 --- /dev/null +++ b/sdk/python/examples/controls/text_button/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Basic text buttons" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextButton(content="Text button"), + ft.TextButton(content="Disabled button", disabled=True), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_button/basic/pyproject.toml b/sdk/python/examples/controls/text_button/basic/pyproject.toml new file mode 100644 index 0000000000..aa5b7a2bb7 --- /dev/null +++ b/sdk/python/examples/controls/text_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-button-basic" +version = "1.0.0" +description = "Shows enabled and disabled TextButton controls with the default appearance." +requires-python = ">=3.10" +keywords = ["text button", "button", "disabled", "basic", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/TextButton"] + +[tool.flet.metadata] +title = "TextButton basic" +controls = ["SafeArea", "Column", "TextButton"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["enabled and disabled states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_button/custom_content.py b/sdk/python/examples/controls/text_button/custom_content.py deleted file mode 100644 index 7b402714fb..0000000000 --- a/sdk/python/examples/controls/text_button/custom_content.py +++ /dev/null @@ -1,36 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "TextButtons with custom content" - - page.add( - ft.TextButton( - width=150, - content=ft.Row( - alignment=ft.MainAxisAlignment.SPACE_AROUND, - controls=[ - ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), - ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), - ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), - ], - ), - ), - ft.TextButton( - content=ft.Container( - padding=ft.Padding.all(10), - content=ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - spacing=5, - controls=[ - ft.Text(value="Compound button", size=20), - ft.Text(value="This is secondary text"), - ], - ), - ), - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/text_button/custom_content/main.py b/sdk/python/examples/controls/text_button/custom_content/main.py new file mode 100644 index 0000000000..82642c013e --- /dev/null +++ b/sdk/python/examples/controls/text_button/custom_content/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "TextButtons with custom content" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextButton( + width=150, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), + ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), + ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), + ], + ), + ), + ft.TextButton( + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + spacing=5, + controls=[ + ft.Text(value="Compound button", size=20), + ft.Text(value="This is secondary text"), + ], + ), + ), + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_button/custom_content/pyproject.toml b/sdk/python/examples/controls/text_button/custom_content/pyproject.toml new file mode 100644 index 0000000000..57fdaafae0 --- /dev/null +++ b/sdk/python/examples/controls/text_button/custom_content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-button-custom-content" +version = "1.0.0" +description = "Builds TextButton controls with rows of icons and compound multi-line content." +requires-python = ">=3.10" +keywords = ["text button", "custom content", "icons", "compound", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/TextButton"] + +[tool.flet.metadata] +title = "TextButton custom content" +controls = ["SafeArea", "Column", "TextButton", "Row", "Container", "Column", "Icon", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["custom button content", "compound button layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_button/handling_clicks.py b/sdk/python/examples/controls/text_button/handling_clicks.py deleted file mode 100644 index 9cc25baff3..0000000000 --- a/sdk/python/examples/controls/text_button/handling_clicks.py +++ /dev/null @@ -1,25 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "TextButton with 'click' event" - - def button_clicked(e): - button.data += 1 - message_text.value = f"Button clicked {button.data} time(s)" - page.update() - - message_text = ft.Text() - page.add( - button := ft.TextButton( - key="TextButton", - content="Button with 'click' event", - data=0, - on_click=button_clicked, - ), - message := ft.Container(content=message_text, padding=ft.Padding(left=12)), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/text_button/handling_clicks/main.py b/sdk/python/examples/controls/text_button/handling_clicks/main.py new file mode 100644 index 0000000000..1e8cb47b9d --- /dev/null +++ b/sdk/python/examples/controls/text_button/handling_clicks/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "TextButton with 'click' event" + + def button_clicked(e): + button.data += 1 + message_text.value = f"Button clicked {button.data} time(s)" + + message_text = ft.Text() + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + button := ft.TextButton( + key="TextButton", + content="Button with 'click' event", + data=0, + on_click=button_clicked, + ), + ft.Container( + padding=ft.Padding(left=12), + content=message_text, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/text_button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..88527e5907 --- /dev/null +++ b/sdk/python/examples/controls/text_button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-button-handling-clicks" +version = "1.0.0" +description = "Updates a counter message each time a TextButton click event fires." +requires-python = ">=3.10" +keywords = ["text button", "events", "click", "counter", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/TextButton"] + +[tool.flet.metadata] +title = "TextButton handling clicks" +controls = ["SafeArea", "Column", "TextButton", "Container", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["click handling", "live counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_button/icons.py b/sdk/python/examples/controls/text_button/icons.py deleted file mode 100644 index 3205f15353..0000000000 --- a/sdk/python/examples/controls/text_button/icons.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "TextButtons with icons" - - page.add( - ft.TextButton(content="Button with icon", icon=ft.Icons.WAVES_OUTLINED), - ft.TextButton( - content="Button with colorful icon", - icon=ft.Icons.PARK_ROUNDED, - icon_color=ft.Colors.GREEN_400, - ), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/text_button/icons/main.py b/sdk/python/examples/controls/text_button/icons/main.py new file mode 100644 index 0000000000..9e1e445ab0 --- /dev/null +++ b/sdk/python/examples/controls/text_button/icons/main.py @@ -0,0 +1,27 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "TextButtons with icons" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextButton( + content="Button with icon", + icon=ft.Icons.WAVES_OUTLINED, + ), + ft.TextButton( + content="Button with colorful icon", + icon=ft.Icons.PARK_ROUNDED, + icon_color=ft.Colors.GREEN_400, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_button/icons/pyproject.toml b/sdk/python/examples/controls/text_button/icons/pyproject.toml new file mode 100644 index 0000000000..df13c044b9 --- /dev/null +++ b/sdk/python/examples/controls/text_button/icons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-button-icons" +version = "1.0.0" +description = "Adds standard and custom-colored icons to TextButton controls." +requires-python = ">=3.10" +keywords = ["text button", "icons", "button", "material", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/TextButton"] + +[tool.flet.metadata] +title = "TextButton icons" +controls = ["SafeArea", "Column", "TextButton"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["icon buttons", "custom icon colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/text.md b/sdk/python/packages/flet/docs/controls/text.md index 91c20f9308..33ae5c73bd 100644 --- a/sdk/python/packages/flet/docs/controls/text.md +++ b/sdk/python/packages/flet/docs/controls/text.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/text/media ### Custom text styles ```python ---8<-- "{{ examples }}/custom_styles.py" +--8<-- "{{ examples }}/custom_styles/main.py" ``` {{ image(example_media + "/custom_styles.gif", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/text/media ### Pre-defined theme text styles ```python ---8<-- "{{ examples }}/text_theme_styles.py" +--8<-- "{{ examples }}/text_theme_styles/main.py" ``` {{ image(example_media + "/text_theme_styles.png", width="80%") }} @@ -32,7 +32,7 @@ example_media: ../examples/controls/text/media ### Font with variable weight ```python ---8<-- "{{ examples }}/variable_font_weight.py" +--8<-- "{{ examples }}/variable_font_weight/main.py" ``` {{ image(example_media + "/variable_font_weight.gif", width="80%") }} @@ -41,7 +41,7 @@ example_media: ../examples/controls/text/media ### Basic rich text example ```python ---8<-- "{{ examples }}/rich_text_basic.py" +--8<-- "{{ examples }}/rich_text_basic/main.py" ``` {{ image(example_media + "/rich_text_basic.png", width="80%") }} @@ -50,7 +50,7 @@ example_media: ../examples/controls/text/media ### Rich text with borders and stroke ```python ---8<-- "{{ examples }}/rich_text_border_stroke.py" +--8<-- "{{ examples }}/rich_text_border_stroke/main.py" ``` {{ image(example_media + "/rich_text_border_stroke.png", width="80%") }} @@ -59,7 +59,7 @@ example_media: ../examples/controls/text/media ### Rich text with gradient ```python ---8<-- "{{ examples }}/rich_text_gradient.py" +--8<-- "{{ examples }}/rich_text_gradient/main.py" ``` {{ image(example_media + "/rich_text_gradient.png", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/textbutton.md b/sdk/python/packages/flet/docs/controls/textbutton.md index d82d0ff6ac..7a23b848b3 100644 --- a/sdk/python/packages/flet/docs/controls/textbutton.md +++ b/sdk/python/packages/flet/docs/controls/textbutton.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/text_button ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} @@ -22,7 +22,7 @@ example_images: ../test-images/examples/material/golden/macos/text_button ### Icons ```python ---8<-- "{{ examples }}/icons.py" +--8<-- "{{ examples }}/icons/main.py" ``` {{ image(example_images + "/icons.png", alt="icons", width="80%") }} @@ -31,7 +31,7 @@ example_images: ../test-images/examples/material/golden/macos/text_button ### Handling clicks ```python ---8<-- "{{ examples }}/handling_clicks.py" +--8<-- "{{ examples }}/handling_clicks/main.py" ``` {{ image(example_images + "/handling_clicks.png", alt="handling-clicks", width="80%") }} @@ -40,7 +40,7 @@ example_images: ../test-images/examples/material/golden/macos/text_button ### Custom content ```python ---8<-- "{{ examples }}/custom_content.py" +--8<-- "{{ examples }}/custom_content/main.py" ``` {{ image(example_images + "/custom_content.png", alt="custom-content", width="80%") }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_text_button.py b/sdk/python/packages/flet/integration_tests/examples/material/test_text_button.py index b4afbff3d0..1910f31912 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_text_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_text_button.py @@ -1,8 +1,11 @@ import pytest +import examples.controls.text_button.basic.main as basic +import examples.controls.text_button.custom_content.main as custom_content +import examples.controls.text_button.handling_clicks.main as handling_clicks +import examples.controls.text_button.icons.main as icons import flet as ft import flet.testing as ftt -from examples.controls.text_button import basic, custom_content, handling_clicks, icons @pytest.mark.asyncio(loop_scope="function") From 04518287b834eb0716c5e178224db9e33e7f36ea Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 16:34:48 -0700 Subject: [PATCH 77/96] Restructure TextField examples into subdirs Move TextField example scripts into per-example directories (each now provides main.py) and add pyproject.toml metadata for each example. Legacy flat example files were removed, UI containers were standardized (SafeArea/Column where appropriate), and documentation links in textfield.md were updated to point to the new example paths. --- .../examples/controls/text_field/basic.py | 23 ------- .../controls/text_field/basic/main.py | 43 +++++++++++++ .../controls/text_field/basic/pyproject.toml | 26 ++++++++ .../text_field/handling_change_events.py | 18 ------ .../text_field/handling_change_events/main.py | 24 ++++++++ .../handling_change_events/pyproject.toml | 26 ++++++++ .../text_field/label_hint_helper_counter.py | 55 ----------------- .../label_hint_helper_counter/main.py | 61 +++++++++++++++++++ .../label_hint_helper_counter/pyproject.toml | 26 ++++++++ .../examples/controls/text_field/multiline.py | 25 -------- .../controls/text_field/multiline/main.py | 32 ++++++++++ .../text_field/multiline/pyproject.toml | 26 ++++++++ .../examples/controls/text_field/password.py | 14 ----- .../controls/text_field/password/main.py | 17 ++++++ .../text_field/password/pyproject.toml | 26 ++++++++ .../controls/text_field/prefix_and_suffix.py | 39 ------------ .../text_field/prefix_and_suffix/main.py | 51 ++++++++++++++++ .../prefix_and_suffix/pyproject.toml | 26 ++++++++ .../controls/text_field/selection_change.py | 52 ---------------- .../text_field/selection_change/main.py | 56 +++++++++++++++++ .../selection_change/pyproject.toml | 26 ++++++++ .../examples/controls/text_field/styled.py | 27 -------- .../controls/text_field/styled/main.py | 32 ++++++++++ .../controls/text_field/styled/pyproject.toml | 26 ++++++++ .../text_field/underlined_and_borderless.py | 31 ---------- .../underlined_and_borderless/main.py | 38 ++++++++++++ .../underlined_and_borderless/pyproject.toml | 26 ++++++++ .../packages/flet/docs/controls/textfield.md | 18 +++--- 28 files changed, 597 insertions(+), 293 deletions(-) delete mode 100644 sdk/python/examples/controls/text_field/basic.py create mode 100644 sdk/python/examples/controls/text_field/basic/main.py create mode 100644 sdk/python/examples/controls/text_field/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_field/handling_change_events.py create mode 100644 sdk/python/examples/controls/text_field/handling_change_events/main.py create mode 100644 sdk/python/examples/controls/text_field/handling_change_events/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_field/label_hint_helper_counter.py create mode 100644 sdk/python/examples/controls/text_field/label_hint_helper_counter/main.py create mode 100644 sdk/python/examples/controls/text_field/label_hint_helper_counter/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_field/multiline.py create mode 100644 sdk/python/examples/controls/text_field/multiline/main.py create mode 100644 sdk/python/examples/controls/text_field/multiline/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_field/password.py create mode 100644 sdk/python/examples/controls/text_field/password/main.py create mode 100644 sdk/python/examples/controls/text_field/password/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_field/prefix_and_suffix.py create mode 100644 sdk/python/examples/controls/text_field/prefix_and_suffix/main.py create mode 100644 sdk/python/examples/controls/text_field/prefix_and_suffix/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_field/selection_change.py create mode 100644 sdk/python/examples/controls/text_field/selection_change/main.py create mode 100644 sdk/python/examples/controls/text_field/selection_change/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_field/styled.py create mode 100644 sdk/python/examples/controls/text_field/styled/main.py create mode 100644 sdk/python/examples/controls/text_field/styled/pyproject.toml delete mode 100644 sdk/python/examples/controls/text_field/underlined_and_borderless.py create mode 100644 sdk/python/examples/controls/text_field/underlined_and_borderless/main.py create mode 100644 sdk/python/examples/controls/text_field/underlined_and_borderless/pyproject.toml diff --git a/sdk/python/examples/controls/text_field/basic.py b/sdk/python/examples/controls/text_field/basic.py deleted file mode 100644 index e592be84af..0000000000 --- a/sdk/python/examples/controls/text_field/basic.py +++ /dev/null @@ -1,23 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_button_click(e: ft.Event[ft.Button]): - message.value = f"Textboxes values are: '{tb1.value}', '{tb2.value}', " - f"'{tb3.value}', '{tb4.value}', '{tb5.value}'." - page.update() - - page.add( - tb1 := ft.TextField(label="Standard"), - tb2 := ft.TextField(label="Disabled", disabled=True, value="First name"), - tb3 := ft.TextField(label="Read-only", read_only=True, value="Last name"), - tb4 := ft.TextField( - label="With placeholder", hint_text="Please enter text here" - ), - tb5 := ft.TextField(label="With an icon", icon=ft.Icons.EMOJI_EMOTIONS), - ft.Button(content="Submit", on_click=handle_button_click), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text_field/basic/main.py b/sdk/python/examples/controls/text_field/basic/main.py new file mode 100644 index 0000000000..6cece3e499 --- /dev/null +++ b/sdk/python/examples/controls/text_field/basic/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = ( + f"Textboxes values are: '{tb1.value}', '{tb2.value}', " + f"'{tb3.value}', '{tb4.value}', '{tb5.value}'." + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + tb1 := ft.TextField(label="Standard"), + tb2 := ft.TextField( + label="Disabled", + disabled=True, + value="First name", + ), + tb3 := ft.TextField( + label="Read-only", + read_only=True, + value="Last name", + ), + tb4 := ft.TextField( + label="With placeholder", + hint_text="Please enter text here", + ), + tb5 := ft.TextField( + label="With an icon", + icon=ft.Icons.EMOJI_EMOTIONS, + ), + ft.Button(content="Submit", on_click=handle_button_click), + message := ft.Text(), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/basic/pyproject.toml b/sdk/python/examples/controls/text_field/basic/pyproject.toml new file mode 100644 index 0000000000..b4d729ec59 --- /dev/null +++ b/sdk/python/examples/controls/text_field/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-basic" +version = "1.0.0" +description = "Compares standard, disabled, read-only, placeholder, and icon TextField states." +requires-python = ">=3.10" +keywords = ["text field", "input", "disabled", "read-only", "basic"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "TextField basic" +controls = ["SafeArea", "Column", "TextField", "Button", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["multiple field states", "value summary"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_field/handling_change_events.py b/sdk/python/examples/controls/text_field/handling_change_events.py deleted file mode 100644 index 1dbf5585ef..0000000000 --- a/sdk/python/examples/controls/text_field/handling_change_events.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_field_change(e: ft.Event[ft.TextField]): - message.value = e.control.value - page.update() - - page.add( - ft.TextField( - label="Textbox with 'change' event:", - on_change=handle_field_change, - ), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text_field/handling_change_events/main.py b/sdk/python/examples/controls/text_field/handling_change_events/main.py new file mode 100644 index 0000000000..dc72dc0cfd --- /dev/null +++ b/sdk/python/examples/controls/text_field/handling_change_events/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_field_change(e: ft.Event[ft.TextField]): + message.value = e.control.value + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + label="Textbox with 'change' event:", + on_change=handle_field_change, + ), + message := ft.Text(), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/handling_change_events/pyproject.toml b/sdk/python/examples/controls/text_field/handling_change_events/pyproject.toml new file mode 100644 index 0000000000..87de8505cd --- /dev/null +++ b/sdk/python/examples/controls/text_field/handling_change_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-handling-change-events" +version = "1.0.0" +description = "Echoes TextField input live as the value changes." +requires-python = ">=3.10" +keywords = ["text field", "events", "change", "input", "live"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Handling change events" +controls = ["SafeArea", "Column", "TextField", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["change events", "live updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_field/label_hint_helper_counter.py b/sdk/python/examples/controls/text_field/label_hint_helper_counter.py deleted file mode 100644 index 66f426a819..0000000000 --- a/sdk/python/examples/controls/text_field/label_hint_helper_counter.py +++ /dev/null @@ -1,55 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - - def handle_field_change(e: ft.Event[ft.TextField]): - message.value = e.control.value - page.update() - - page.add( - ft.TextField( - on_change=handle_field_change, - text_style=ft.TextStyle( - size=15, - italic=True, - color=ft.Colors.DEEP_ORANGE_600, - bgcolor=ft.Colors.LIME_ACCENT_200, - ), - label="Label", - label_style=ft.TextStyle( - size=17, - weight=ft.FontWeight.BOLD, - italic=True, - color=ft.Colors.BLUE, - bgcolor=ft.Colors.RED_700, - ), - hint_text="Hint", - hint_style=ft.TextStyle( - size=15, - weight=ft.FontWeight.BOLD, - italic=True, - color=ft.Colors.PINK_ACCENT, - bgcolor=ft.Colors.BROWN_400, - ), - helper="Helper", - helper_style=ft.TextStyle( - size=14, - weight=ft.FontWeight.BOLD, - color=ft.Colors.DEEP_PURPLE, - bgcolor=ft.Colors.BLUE_50, - ), - counter="Counter", - counter_style=ft.TextStyle( - size=14, - italic=True, - color=ft.Colors.YELLOW, - bgcolor=ft.Colors.GREEN_500, - ), - ), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text_field/label_hint_helper_counter/main.py b/sdk/python/examples/controls/text_field/label_hint_helper_counter/main.py new file mode 100644 index 0000000000..6760ab9bec --- /dev/null +++ b/sdk/python/examples/controls/text_field/label_hint_helper_counter/main.py @@ -0,0 +1,61 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_field_change(e: ft.Event[ft.TextField]): + message.value = e.control.value + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + on_change=handle_field_change, + text_style=ft.TextStyle( + size=15, + italic=True, + color=ft.Colors.DEEP_ORANGE_600, + bgcolor=ft.Colors.LIME_ACCENT_200, + ), + label="Label", + label_style=ft.TextStyle( + size=17, + weight=ft.FontWeight.BOLD, + italic=True, + color=ft.Colors.BLUE, + bgcolor=ft.Colors.RED_700, + ), + hint_text="Hint", + hint_style=ft.TextStyle( + size=15, + weight=ft.FontWeight.BOLD, + italic=True, + color=ft.Colors.PINK_ACCENT, + bgcolor=ft.Colors.BROWN_400, + ), + helper="Helper", + helper_style=ft.TextStyle( + size=14, + weight=ft.FontWeight.BOLD, + color=ft.Colors.DEEP_PURPLE, + bgcolor=ft.Colors.BLUE_50, + ), + counter="Counter", + counter_style=ft.TextStyle( + size=14, + italic=True, + color=ft.Colors.YELLOW, + bgcolor=ft.Colors.GREEN_500, + ), + ), + message := ft.Text(), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/label_hint_helper_counter/pyproject.toml b/sdk/python/examples/controls/text_field/label_hint_helper_counter/pyproject.toml new file mode 100644 index 0000000000..79f08fb3a5 --- /dev/null +++ b/sdk/python/examples/controls/text_field/label_hint_helper_counter/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-label-hint-helper-counter" +version = "1.0.0" +description = "Styles TextField label, hint, helper, and counter text independently." +requires-python = ">=3.10" +keywords = ["text field", "label", "hint", "helper", "counter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Custom label, hint, helper, and counter texts and styles" +controls = ["SafeArea", "Column", "TextField", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["custom label styling", "custom hint styling", "custom helper and counter styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_field/multiline.py b/sdk/python/examples/controls/text_field/multiline.py deleted file mode 100644 index 8b980a11aa..0000000000 --- a/sdk/python/examples/controls/text_field/multiline.py +++ /dev/null @@ -1,25 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.TextField( - label="Standard", - multiline=True, - ), - ft.TextField( - label="Disabled", - multiline=True, - disabled=True, - value="line1\nline2\nline3\nline4\nline5", - ), - ft.TextField( - label="Auto adjusted height with max lines", - multiline=True, - min_lines=1, - max_lines=3, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text_field/multiline/main.py b/sdk/python/examples/controls/text_field/multiline/main.py new file mode 100644 index 0000000000..1f51a32f10 --- /dev/null +++ b/sdk/python/examples/controls/text_field/multiline/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + label="Standard", + multiline=True, + ), + ft.TextField( + label="Disabled", + multiline=True, + disabled=True, + value="line1\nline2\nline3\nline4\nline5", + ), + ft.TextField( + label="Auto adjusted height with max lines", + multiline=True, + min_lines=1, + max_lines=3, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/multiline/pyproject.toml b/sdk/python/examples/controls/text_field/multiline/pyproject.toml new file mode 100644 index 0000000000..32d2ae4e32 --- /dev/null +++ b/sdk/python/examples/controls/text_field/multiline/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-multiline" +version = "1.0.0" +description = "Compares multiline TextField configurations including disabled and auto-sized fields." +requires-python = ">=3.10" +keywords = ["text field", "multiline", "input", "disabled", "autosize"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Multiline fields" +controls = ["SafeArea", "Column", "TextField"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["multiline input", "auto-sized height"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_field/password.py b/sdk/python/examples/controls/text_field/password.py deleted file mode 100644 index a15b063f94..0000000000 --- a/sdk/python/examples/controls/text_field/password.py +++ /dev/null @@ -1,14 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.TextField( - label="Password with reveal button", - password=True, - can_reveal_password=True, - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text_field/password/main.py b/sdk/python/examples/controls/text_field/password/main.py new file mode 100644 index 0000000000..91c423d901 --- /dev/null +++ b/sdk/python/examples/controls/text_field/password/main.py @@ -0,0 +1,17 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.TextField( + label="Password with reveal button", + password=True, + can_reveal_password=True, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/password/pyproject.toml b/sdk/python/examples/controls/text_field/password/pyproject.toml new file mode 100644 index 0000000000..e26b76d4e5 --- /dev/null +++ b/sdk/python/examples/controls/text_field/password/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-password" +version = "1.0.0" +description = "Shows a password TextField with a built-in reveal button." +requires-python = ">=3.10" +keywords = ["text field", "password", "secure input", "reveal", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Password with reveal button" +controls = ["SafeArea", "TextField"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["password reveal"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_field/prefix_and_suffix.py b/sdk/python/examples/controls/text_field/prefix_and_suffix.py deleted file mode 100644 index 0007346b47..0000000000 --- a/sdk/python/examples/controls/text_field/prefix_and_suffix.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def handle_button_click(e: ft.Event[ft.Button]): - message.value = ( - "Textboxes values are: " - f"'{prefix_field.value}', " - f"'{suffix_field.value}', " - f"'{prefix_suffix_field.value}', " - f"'{color_field.value}'." - ) - page.update() - - page.add( - prefix_field := ft.TextField(label="With prefix", prefix="https://"), - suffix_field := ft.TextField(label="With suffix", suffix=".com"), - prefix_suffix_field := ft.TextField( - label="With prefix and suffix", - prefix="https://", - suffix=".com", - enable_interactive_selection=True, - ), - color_field := ft.TextField( - label="My favorite color", - icon=ft.Icons.FORMAT_SIZE, - hint_text="Type your favorite color", - helper="You can type only one color", - counter="{value_length}/{max_length} chars used", - prefix_icon=ft.Icons.COLOR_LENS, - suffix="...is your color", - max_length=20, - ), - ft.Button(content="Submit", on_click=handle_button_click), - message := ft.Text(), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text_field/prefix_and_suffix/main.py b/sdk/python/examples/controls/text_field/prefix_and_suffix/main.py new file mode 100644 index 0000000000..503eb87009 --- /dev/null +++ b/sdk/python/examples/controls/text_field/prefix_and_suffix/main.py @@ -0,0 +1,51 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = ( + "Textboxes values are: " + f"'{prefix_field.value}', " + f"'{suffix_field.value}', " + f"'{prefix_suffix_field.value}', " + f"'{color_field.value}'." + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + prefix_field := ft.TextField( + label="With prefix", + prefix="https://", + ), + suffix_field := ft.TextField( + label="With suffix", + suffix=".com", + ), + prefix_suffix_field := ft.TextField( + label="With prefix and suffix", + prefix="https://", + suffix=".com", + enable_interactive_selection=True, + ), + color_field := ft.TextField( + label="My favorite color", + icon=ft.Icons.FORMAT_SIZE, + hint_text="Type your favorite color", + helper="You can type only one color", + counter="{value_length}/{max_length} chars used", + prefix_icon=ft.Icons.COLOR_LENS, + suffix="...is your color", + max_length=20, + ), + ft.Button(content="Submit", on_click=handle_button_click), + message := ft.Text(), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/prefix_and_suffix/pyproject.toml b/sdk/python/examples/controls/text_field/prefix_and_suffix/pyproject.toml new file mode 100644 index 0000000000..baef30c0c8 --- /dev/null +++ b/sdk/python/examples/controls/text_field/prefix_and_suffix/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-prefix-and-suffix" +version = "1.0.0" +description = "Adds prefixes, suffixes, counters, and helper text to TextField inputs." +requires-python = ">=3.10" +keywords = ["text field", "prefix", "suffix", "counter", "helper"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Setting prefixes and suffixes" +controls = ["SafeArea", "Column", "TextField", "Button", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["prefix and suffix text", "helper text", "counters"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_field/selection_change.py b/sdk/python/examples/controls/text_field/selection_change.py deleted file mode 100644 index 43d6fa5abe..0000000000 --- a/sdk/python/examples/controls/text_field/selection_change.py +++ /dev/null @@ -1,52 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Text selection" - - def handle_selection_change(e: ft.TextSelectionChangeEvent[ft.TextField]): - selection.value = ( - f"Selection: '{e.selected_text}'" if e.selected_text else "No selection." - ) - selection_details.value = f"start={e.selection.start}, end={e.selection.end}" - caret.value = f"Caret position: {e.selection.end}" - - async def select_characters(e: ft.Event[ft.Button]): - await field.focus() - field.selection = ft.TextSelection( - base_offset=0, extent_offset=len(field.value) - ) - - async def move_caret(e: ft.Event[ft.Button]): - await field.focus() - field.selection = ft.TextSelection(base_offset=0, extent_offset=0) - - page.add( - ft.Column( - spacing=10, - controls=[ - field := ft.TextField( - value="Lorem ipsum dolor sit amet, consectetur adipiscing elit.", - multiline=True, - min_lines=3, - autofocus=True, - on_selection_change=handle_selection_change, - ), - selection := ft.Text("Select some text from the field."), - selection_details := ft.Text(), - caret := ft.Text("Caret position: -"), - ft.Button( - content="Select all text", - on_click=select_characters, - ), - ft.Button( - content="Move caret to start", - on_click=move_caret, - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/text_field/selection_change/main.py b/sdk/python/examples/controls/text_field/selection_change/main.py new file mode 100644 index 0000000000..8589f7ae77 --- /dev/null +++ b/sdk/python/examples/controls/text_field/selection_change/main.py @@ -0,0 +1,56 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Text selection" + + def handle_selection_change(e: ft.TextSelectionChangeEvent[ft.TextField]): + selection.value = ( + f"Selection: '{e.selected_text}'" if e.selected_text else "No selection." + ) + selection_details.value = f"start={e.selection.start}, end={e.selection.end}" + caret.value = f"Caret position: {e.selection.end}" + + async def select_characters(e: ft.Event[ft.Button]): + await field.focus() + field.selection = ft.TextSelection( + base_offset=0, extent_offset=len(field.value) + ) + + async def move_caret(e: ft.Event[ft.Button]): + await field.focus() + field.selection = ft.TextSelection(base_offset=0, extent_offset=0) + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=10, + controls=[ + field := ft.TextField( + value=( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + ), + multiline=True, + min_lines=3, + autofocus=True, + on_selection_change=handle_selection_change, + ), + selection := ft.Text("Select some text from the field."), + selection_details := ft.Text(), + caret := ft.Text("Caret position: -"), + ft.Button( + content="Select all text", + on_click=select_characters, + ), + ft.Button( + content="Move caret to start", + on_click=move_caret, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/selection_change/pyproject.toml b/sdk/python/examples/controls/text_field/selection_change/pyproject.toml new file mode 100644 index 0000000000..710da215d8 --- /dev/null +++ b/sdk/python/examples/controls/text_field/selection_change/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-selection-change" +version = "1.0.0" +description = "Tracks TextField selection ranges and moves the caret with buttons." +requires-python = ">=3.10" +keywords = ["text field", "selection", "caret", "async", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Handling selection changes" +controls = ["SafeArea", "Column", "TextField", "Text", "Button"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["selection events", "caret control"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_field/styled.py b/sdk/python/examples/controls/text_field/styled.py deleted file mode 100644 index fe2aca1f4c..0000000000 --- a/sdk/python/examples/controls/text_field/styled.py +++ /dev/null @@ -1,27 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - page.padding = 50 - - page.add( - tf := ft.TextField( - text_size=30, - cursor_color=ft.Colors.RED, - selection_color=ft.Colors.YELLOW, - color=ft.Colors.PINK, - bgcolor=ft.Colors.BLACK_26, - filled=True, - focused_color=ft.Colors.GREEN, - focused_bgcolor=ft.Colors.CYAN_200, - border_radius=30, - border_color=ft.Colors.GREEN_800, - focused_border_color=ft.Colors.GREEN_ACCENT_400, - max_length=20, - capitalization=ft.TextCapitalization.CHARACTERS, - ) - ) - await tf.focus() - - -ft.run(main) diff --git a/sdk/python/examples/controls/text_field/styled/main.py b/sdk/python/examples/controls/text_field/styled/main.py new file mode 100644 index 0000000000..ba34ffdf60 --- /dev/null +++ b/sdk/python/examples/controls/text_field/styled/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +async def main(page: ft.Page): + page.padding = 50 + + tf = ft.TextField( + text_size=30, + cursor_color=ft.Colors.RED, + selection_color=ft.Colors.YELLOW, + color=ft.Colors.PINK, + bgcolor=ft.Colors.BLACK_26, + filled=True, + focused_color=ft.Colors.GREEN, + focused_bgcolor=ft.Colors.CYAN_200, + border_radius=30, + border_color=ft.Colors.GREEN_800, + focused_border_color=ft.Colors.GREEN_ACCENT_400, + max_length=20, + capitalization=ft.TextCapitalization.CHARACTERS, + ) + + page.add( + ft.SafeArea( + content=tf, + ) + ) + await tf.focus() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/styled/pyproject.toml b/sdk/python/examples/controls/text_field/styled/pyproject.toml new file mode 100644 index 0000000000..652ce7e042 --- /dev/null +++ b/sdk/python/examples/controls/text_field/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-styled" +version = "1.0.0" +description = "Customizes TextField colors, cursor, borders, capitalization, and focus behavior." +requires-python = ">=3.10" +keywords = ["text field", "styling", "focus", "async", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Styled TextField" +controls = ["SafeArea", "TextField"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom field styling", "programmatic focus"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/text_field/underlined_and_borderless.py b/sdk/python/examples/controls/text_field/underlined_and_borderless.py deleted file mode 100644 index 24c0d67e44..0000000000 --- a/sdk/python/examples/controls/text_field/underlined_and_borderless.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.TextField( - label="Underlined", - border=ft.InputBorder.UNDERLINE, - hint_text="Enter text here", - ), - ft.TextField( - label="Underlined filled", - border=ft.InputBorder.UNDERLINE, - filled=True, - hint_text="Enter text here", - ), - ft.TextField( - label="Borderless", - border=ft.InputBorder.NONE, - hint_text="Enter text here", - ), - ft.TextField( - label="Borderless filled", - border=ft.InputBorder.NONE, - filled=True, - hint_text="Enter text here", - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/text_field/underlined_and_borderless/main.py b/sdk/python/examples/controls/text_field/underlined_and_borderless/main.py new file mode 100644 index 0000000000..9d792c93af --- /dev/null +++ b/sdk/python/examples/controls/text_field/underlined_and_borderless/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + label="Underlined", + border=ft.InputBorder.UNDERLINE, + hint_text="Enter text here", + ), + ft.TextField( + label="Underlined filled", + border=ft.InputBorder.UNDERLINE, + filled=True, + hint_text="Enter text here", + ), + ft.TextField( + label="Borderless", + border=ft.InputBorder.NONE, + hint_text="Enter text here", + ), + ft.TextField( + label="Borderless filled", + border=ft.InputBorder.NONE, + filled=True, + hint_text="Enter text here", + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/text_field/underlined_and_borderless/pyproject.toml b/sdk/python/examples/controls/text_field/underlined_and_borderless/pyproject.toml new file mode 100644 index 0000000000..11e7d234c4 --- /dev/null +++ b/sdk/python/examples/controls/text_field/underlined_and_borderless/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-underlined-and-borderless" +version = "1.0.0" +description = "Shows underlined and borderless TextField styles with filled and unfilled variants." +requires-python = ">=3.10" +keywords = ["text field", "border", "underlined", "borderless", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Underlined and borderless TextFields" +controls = ["SafeArea", "Column", "TextField"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["underlined border", "borderless style"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/textfield.md b/sdk/python/packages/flet/docs/controls/textfield.md index 20529fb418..ab264d0c5c 100644 --- a/sdk/python/packages/flet/docs/controls/textfield.md +++ b/sdk/python/packages/flet/docs/controls/textfield.md @@ -14,7 +14,7 @@ example_media: ../examples/controls/text_field/media ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_media + "/basic.gif", alt="basic", width="80%") }} @@ -23,7 +23,7 @@ example_media: ../examples/controls/text_field/media ### Handling change events ```python ---8<-- "{{ examples }}/handling_change_events.py" +--8<-- "{{ examples }}/handling_change_events/main.py" ``` {{ image(example_media + "/handling_change_events.gif", alt="handling-change-events", width="80%") }} @@ -31,13 +31,13 @@ example_media: ../examples/controls/text_field/media ### Handling selection changes ```python ---8<-- "{{ examples }}/selection_change.py" +--8<-- "{{ examples }}/selection_change/main.py" ``` ### Password with reveal button ```python ---8<-- "{{ examples }}/password.py" +--8<-- "{{ examples }}/password/main.py" ``` {{ image(example_media + "/password.gif", alt="password", width="80%") }} @@ -46,7 +46,7 @@ example_media: ../examples/controls/text_field/media ### Multiline fields ```python ---8<-- "{{ examples }}/multiline.py" +--8<-- "{{ examples }}/multiline/main.py" ``` {{ image(example_media + "/multiline.gif", alt="multiline", width="80%") }} @@ -55,7 +55,7 @@ example_media: ../examples/controls/text_field/media ### Underlined and borderless TextFields ```python ---8<-- "{{ examples }}/underlined_and_borderless.py" +--8<-- "{{ examples }}/underlined_and_borderless/main.py" ``` {{ image(example_media + "/underlined_and_borderless.gif", alt="underlined-and-borderless", width="80%") }} @@ -64,7 +64,7 @@ example_media: ../examples/controls/text_field/media ### Setting prefixes and suffixes ```python ---8<-- "{{ examples }}/prefix_and_suffix.py" +--8<-- "{{ examples }}/prefix_and_suffix/main.py" ``` {{ image(example_media + "/prefix_and_suffix.gif", alt="prefix-and-suffix", width="80%") }} @@ -73,13 +73,13 @@ example_media: ../examples/controls/text_field/media ### Styled TextField ```python ---8<-- "{{ examples }}/styled.py" +--8<-- "{{ examples }}/styled/main.py" ``` ### Custom label, hint, helper, and counter texts and styles ```python ---8<-- "{{ examples }}/label_hint_helper_counter.py" +--8<-- "{{ examples }}/label_hint_helper_counter/main.py" ``` {{ class_members(class_name) }} From 57694832a159ecefa791ed67baba24941060c97a Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 16:44:03 -0700 Subject: [PATCH 78/96] Reorganize examples into main.py and add pyprojects Move example scripts into per-example main.py entrypoints and add pyproject.toml metadata for gallery/tests. Wrap example UIs with SafeArea and refactor layouts (TimePicker: basic/hour_formats/custom_locale, TransparentPointer basic). Remove old flat example files and update docs and tests to reference new paths. --- .../examples/controls/time_picker/__init__.py | 0 .../time_picker/{basic.py => basic/main.py} | 17 ++-- .../controls/time_picker/basic/pyproject.toml | 26 ++++++ .../controls/time_picker/custom_locale.py | 18 ----- .../time_picker/custom_locale/main.py | 21 +++++ .../time_picker/custom_locale/pyproject.toml | 26 ++++++ .../controls/time_picker/hour_formats.py | 70 ---------------- .../controls/time_picker/hour_formats/main.py | 80 +++++++++++++++++++ .../time_picker/hour_formats/pyproject.toml | 26 ++++++ .../controls/transparent_pointer/basic.py | 29 ------- .../transparent_pointer/basic/main.py | 36 +++++++++ .../transparent_pointer/basic/pyproject.toml | 26 ++++++ .../packages/flet/docs/controls/timepicker.md | 4 +- .../flet/docs/controls/transparentpointer.md | 2 +- .../examples/material/test_time_picker.py | 3 +- 15 files changed, 258 insertions(+), 126 deletions(-) delete mode 100644 sdk/python/examples/controls/time_picker/__init__.py rename sdk/python/examples/controls/time_picker/{basic.py => basic/main.py} (69%) create mode 100644 sdk/python/examples/controls/time_picker/basic/pyproject.toml delete mode 100644 sdk/python/examples/controls/time_picker/custom_locale.py create mode 100644 sdk/python/examples/controls/time_picker/custom_locale/main.py create mode 100644 sdk/python/examples/controls/time_picker/custom_locale/pyproject.toml delete mode 100644 sdk/python/examples/controls/time_picker/hour_formats.py create mode 100644 sdk/python/examples/controls/time_picker/hour_formats/main.py create mode 100644 sdk/python/examples/controls/time_picker/hour_formats/pyproject.toml delete mode 100644 sdk/python/examples/controls/transparent_pointer/basic.py create mode 100644 sdk/python/examples/controls/transparent_pointer/basic/main.py create mode 100644 sdk/python/examples/controls/transparent_pointer/basic/pyproject.toml diff --git a/sdk/python/examples/controls/time_picker/__init__.py b/sdk/python/examples/controls/time_picker/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/time_picker/basic.py b/sdk/python/examples/controls/time_picker/basic/main.py similarity index 69% rename from sdk/python/examples/controls/time_picker/basic.py rename to sdk/python/examples/controls/time_picker/basic/main.py index b330848165..852027192a 100644 --- a/sdk/python/examples/controls/time_picker/basic.py +++ b/sdk/python/examples/controls/time_picker/basic/main.py @@ -28,12 +28,19 @@ def handle_entry_mode_change(e: ft.TimePickerEntryModeChangeEvent): ) page.add( - ft.Button( - content="Pick time", - icon=ft.Icons.TIME_TO_LEAVE, - on_click=lambda: page.show_dialog(time_picker), + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Button( + content="Pick time", + icon=ft.Icons.TIME_TO_LEAVE, + on_click=lambda: page.show_dialog(time_picker), + ), + selection := ft.Text(weight=ft.FontWeight.BOLD), + ], + ), ), - selection := ft.Text(weight=ft.FontWeight.BOLD), ) diff --git a/sdk/python/examples/controls/time_picker/basic/pyproject.toml b/sdk/python/examples/controls/time_picker/basic/pyproject.toml new file mode 100644 index 0000000000..e0215ded66 --- /dev/null +++ b/sdk/python/examples/controls/time_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "time-picker-basic" +version = "1.0.0" +description = "Opens a TimePicker dialog and reports selection, dismissal, and entry mode changes." +requires-python = ">=3.10" +keywords = ["time picker", "dialog", "events", "selection", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/TimePicker"] + +[tool.flet.metadata] +title = "TimePicker basic" +controls = ["SafeArea", "Column", "Button", "Text", "TimePicker", "SnackBar"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["dialog opening", "change callbacks", "dismiss callbacks"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/time_picker/custom_locale.py b/sdk/python/examples/controls/time_picker/custom_locale.py deleted file mode 100644 index 956065d26b..0000000000 --- a/sdk/python/examples/controls/time_picker/custom_locale.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - page.add( - ft.Button( - content="Pick time (zh_Hans locale)", - icon=ft.Icons.CALENDAR_MONTH, - on_click=lambda e: page.show_dialog( - ft.TimePicker(locale=ft.Locale("zh", "Hans")) - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/time_picker/custom_locale/main.py b/sdk/python/examples/controls/time_picker/custom_locale/main.py new file mode 100644 index 0000000000..75d58281e5 --- /dev/null +++ b/sdk/python/examples/controls/time_picker/custom_locale/main.py @@ -0,0 +1,21 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Button( + content="Pick time (zh_Hans locale)", + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda e: page.show_dialog( + ft.TimePicker(locale=ft.Locale("zh", "Hans")) + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/time_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/time_picker/custom_locale/pyproject.toml new file mode 100644 index 0000000000..ed1d04a6dd --- /dev/null +++ b/sdk/python/examples/controls/time_picker/custom_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "time-picker-custom-locale" +version = "1.0.0" +description = "Opens a TimePicker dialog using a custom zh_Hans locale." +requires-python = ">=3.10" +keywords = ["time picker", "locale", "dialog", "internationalization", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/TimePicker"] + +[tool.flet.metadata] +title = "Custom locale" +controls = ["SafeArea", "Button", "TimePicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom locale"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/time_picker/hour_formats.py b/sdk/python/examples/controls/time_picker/hour_formats.py deleted file mode 100644 index 8013f3ca0f..0000000000 --- a/sdk/python/examples/controls/time_picker/hour_formats.py +++ /dev/null @@ -1,70 +0,0 @@ -from datetime import time - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def get_system_hour_format(): - """Returns the current system's hour format.""" - return "24h" if page.media.always_use_24_hour_format else "12h" - - def format_time(value: time) -> str: - """Returns a formatted time string based on TimePicker and system settings.""" - use_24h = time_picker.hour_format == ft.TimePickerHourFormat.H24 or ( - time_picker.hour_format == ft.TimePickerHourFormat.SYSTEM - and page.media.always_use_24_hour_format - ) - return value.strftime("%H:%M" if use_24h else "%I:%M %p") - - def handle_change(e: ft.Event[ft.TimePicker]): - selection.value = f"Selection: {format_time(time_picker.value)}" - - time_picker = ft.TimePicker( - value=time(hour=19, minute=30), - help_text="Choose your meeting time", - on_change=handle_change, - ) - - def open_picker(e: ft.Event[ft.Button]): - choice = format_dropdown.value - hour_format_map = { - "system": ft.TimePickerHourFormat.SYSTEM, - "12h": ft.TimePickerHourFormat.H12, - "24h": ft.TimePickerHourFormat.H24, - } - time_picker.hour_format = hour_format_map[choice] - page.show_dialog(time_picker) - - page.add( - ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - format_dropdown := ft.Dropdown( - label="Hour format", - value="system", - width=260, - key="dd", - options=[ - ft.DropdownOption( - key="system", - text=f"System default ({get_system_hour_format()})", - ), - ft.DropdownOption(key="12h", text="12-hour clock"), - ft.DropdownOption(key="24h", text="24-hour clock"), - ], - ), - ft.Button( - "Open TimePicker", - icon=ft.Icons.SCHEDULE, - on_click=open_picker, - ), - ], - ), - selection := ft.Text(weight=ft.FontWeight.BOLD), - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/time_picker/hour_formats/main.py b/sdk/python/examples/controls/time_picker/hour_formats/main.py new file mode 100644 index 0000000000..ae0ef4d7b4 --- /dev/null +++ b/sdk/python/examples/controls/time_picker/hour_formats/main.py @@ -0,0 +1,80 @@ +from datetime import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def get_system_hour_format(): + """Returns the current system's hour format.""" + return "24h" if page.media.always_use_24_hour_format else "12h" + + def format_time(value: time) -> str: + """Returns a formatted time string based on TimePicker and system settings.""" + use_24h = time_picker.hour_format == ft.TimePickerHourFormat.H24 or ( + time_picker.hour_format == ft.TimePickerHourFormat.SYSTEM + and page.media.always_use_24_hour_format + ) + return value.strftime("%H:%M" if use_24h else "%I:%M %p") + + def handle_change(e: ft.Event[ft.TimePicker]): + selection.value = f"Selection: {format_time(time_picker.value)}" + + time_picker = ft.TimePicker( + value=time(hour=19, minute=30), + help_text="Choose your meeting time", + on_change=handle_change, + ) + + def open_picker(e: ft.Event[ft.Button]): + choice = format_dropdown.value + hour_format_map = { + "system": ft.TimePickerHourFormat.SYSTEM, + "12h": ft.TimePickerHourFormat.H12, + "24h": ft.TimePickerHourFormat.H24, + } + time_picker.hour_format = hour_format_map[choice] + page.show_dialog(time_picker) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + format_dropdown := ft.Dropdown( + label="Hour format", + value="system", + width=260, + key="dd", + options=[ + ft.DropdownOption( + key="system", + text=( + f"System default " + f"({get_system_hour_format()})" + ), + ), + ft.DropdownOption(key="12h", text="12-hour clock"), + ft.DropdownOption(key="24h", text="24-hour clock"), + ], + ), + ft.Button( + "Open TimePicker", + icon=ft.Icons.SCHEDULE, + on_click=open_picker, + ), + ], + ), + selection := ft.Text(weight=ft.FontWeight.BOLD), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/time_picker/hour_formats/pyproject.toml b/sdk/python/examples/controls/time_picker/hour_formats/pyproject.toml new file mode 100644 index 0000000000..979eb6eaf5 --- /dev/null +++ b/sdk/python/examples/controls/time_picker/hour_formats/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "time-picker-hour-formats" +version = "1.0.0" +description = "Switches a TimePicker between system, 12-hour, and 24-hour display formats." +requires-python = ">=3.10" +keywords = ["time picker", "hour format", "dropdown", "12h", "24h"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/TimePicker"] + +[tool.flet.metadata] +title = "Hour formats" +controls = ["SafeArea", "Column", "Row", "Dropdown", "Button", "Text", "TimePicker"] +layout_pattern = "toolbar-content" +complexity = "basic" +features = ["hour format switching", "system format detection"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/transparent_pointer/basic.py b/sdk/python/examples/controls/transparent_pointer/basic.py deleted file mode 100644 index cce31e3e27..0000000000 --- a/sdk/python/examples/controls/transparent_pointer/basic.py +++ /dev/null @@ -1,29 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def button_clicked(e): - print("transparent pointer button clicked") - - page.add( - ft.Stack( - expand=True, - controls=[ - ft.GestureDetector( - on_tap=lambda _: print("TAP!"), - multi_tap_touches=3, - on_multi_tap=lambda e: print("MULTI TAP:", e.global_position), - on_multi_long_press=lambda _: print("Multi tap long press"), - ), - ft.TransparentPointer( - content=ft.Container( - content=ft.Button("Test button", on_click=button_clicked), - padding=50, - ) - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/transparent_pointer/basic/main.py b/sdk/python/examples/controls/transparent_pointer/basic/main.py new file mode 100644 index 0000000000..e5781d0ca3 --- /dev/null +++ b/sdk/python/examples/controls/transparent_pointer/basic/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +def main(page: ft.Page): + def button_clicked(e): + print("transparent pointer button clicked") + + page.add( + ft.SafeArea( + expand=True, + content=ft.Stack( + expand=True, + controls=[ + ft.GestureDetector( + on_tap=lambda _: print("TAP!"), + multi_tap_touches=3, + on_multi_tap=lambda e: print("MULTI TAP:", e.global_position), + on_multi_long_press=lambda _: print("Multi tap long press"), + ), + ft.TransparentPointer( + content=ft.Container( + padding=50, + content=ft.Button( + "Test button", + on_click=button_clicked, + ), + ) + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/transparent_pointer/basic/pyproject.toml b/sdk/python/examples/controls/transparent_pointer/basic/pyproject.toml new file mode 100644 index 0000000000..58f14d2f79 --- /dev/null +++ b/sdk/python/examples/controls/transparent_pointer/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "transparent-pointer-basic" +version = "1.0.0" +description = "Lets pointer events pass through an overlaid button using TransparentPointer." +requires-python = ">=3.10" +keywords = ["transparent pointer", "gesture", "overlay", "stack", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TransparentPointer"] + +[tool.flet.metadata] +title = "TransparentPointer basic" +controls = ["SafeArea", "Stack", "GestureDetector", "TransparentPointer", "Container", "Button"] +layout_pattern = "overlay" +complexity = "basic" +features = ["pointer pass-through", "gesture handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/timepicker.md b/sdk/python/packages/flet/docs/controls/timepicker.md index e1b1c28887..a98b658294 100644 --- a/sdk/python/packages/flet/docs/controls/timepicker.md +++ b/sdk/python/packages/flet/docs/controls/timepicker.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/material/golden/macos/time_picker ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", width="80%") }} @@ -21,7 +21,7 @@ example_images: ../test-images/examples/material/golden/macos/time_picker ### Hour Formats ```python ---8<-- "{{ examples }}/hour_formats.py" +--8<-- "{{ examples }}/hour_formats/main.py" ``` {{ image(example_images + "/hour_formats.gif", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/transparentpointer.md b/sdk/python/packages/flet/docs/controls/transparentpointer.md index 373ead9eff..cdd30bbaf6 100644 --- a/sdk/python/packages/flet/docs/controls/transparentpointer.md +++ b/sdk/python/packages/flet/docs/controls/transparentpointer.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/transparent_pointer ## Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/integration_tests/examples/material/test_time_picker.py b/sdk/python/packages/flet/integration_tests/examples/material/test_time_picker.py index a548275958..71309ec364 100644 --- a/sdk/python/packages/flet/integration_tests/examples/material/test_time_picker.py +++ b/sdk/python/packages/flet/integration_tests/examples/material/test_time_picker.py @@ -2,9 +2,10 @@ import pytest +import examples.controls.time_picker.basic.main as basic +import examples.controls.time_picker.hour_formats.main as hour_formats import flet as ft import flet.testing as ftt -from examples.controls.time_picker import basic, hour_formats # Note: CI macOS runner uses a 12-hour (AM / PM) time format by default. From cc17fd59b5b265d583b6b1bd01f3dbc4b221ca23 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 25 Mar 2026 16:54:56 -0700 Subject: [PATCH 79/96] Move example scripts into main.py and add pyprojects Restructure several Python example packages by moving standalone example scripts into example-specific main.py entrypoints (vertical_divider, webview, window_drag_area, video) and deleting the old top-level example files. Add pyproject.toml metadata for each new example package to support the Flet gallery. Wrap example UIs in SafeArea where appropriate and add a __main__ guard to the video example. Update documentation snippets to reference the new example paths and adjust integration test imports to the new module locations. --- .../controls/vertical_divider/__init__.py | 0 .../controls/vertical_divider/basic.py | 40 ------------------ .../controls/vertical_divider/basic/main.py | 42 +++++++++++++++++++ .../vertical_divider/basic/pyproject.toml | 26 ++++++++++++ .../video/{example_1.py => example_1/main.py} | 3 +- .../controls/video/example_1/pyproject.toml | 26 ++++++++++++ .../examples/controls/webview/example_1.py | 18 -------- .../controls/webview/example_1/main.py | 21 ++++++++++ .../controls/webview/example_1/pyproject.toml | 26 ++++++++++++ .../controls/window_drag_area/__init__.py | 0 .../window_drag_area/no_frame_window.py | 32 -------------- .../window_drag_area/no_frame_window/main.py | 34 +++++++++++++++ .../no_frame_window/pyproject.toml | 26 ++++++++++++ .../flet/docs/controls/verticaldivider.md | 2 +- .../flet/docs/controls/windowdragarea.md | 2 +- sdk/python/packages/flet/docs/video/index.md | 2 +- .../packages/flet/docs/webview/index.md | 2 +- .../examples/core/test_vertical_divider.py | 2 +- .../examples/core/test_window_drag_area.py | 2 +- 19 files changed, 209 insertions(+), 97 deletions(-) delete mode 100644 sdk/python/examples/controls/vertical_divider/__init__.py delete mode 100644 sdk/python/examples/controls/vertical_divider/basic.py create mode 100644 sdk/python/examples/controls/vertical_divider/basic/main.py create mode 100644 sdk/python/examples/controls/vertical_divider/basic/pyproject.toml rename sdk/python/examples/controls/video/{example_1.py => example_1/main.py} (99%) create mode 100644 sdk/python/examples/controls/video/example_1/pyproject.toml delete mode 100644 sdk/python/examples/controls/webview/example_1.py create mode 100644 sdk/python/examples/controls/webview/example_1/main.py create mode 100644 sdk/python/examples/controls/webview/example_1/pyproject.toml delete mode 100644 sdk/python/examples/controls/window_drag_area/__init__.py delete mode 100644 sdk/python/examples/controls/window_drag_area/no_frame_window.py create mode 100644 sdk/python/examples/controls/window_drag_area/no_frame_window/main.py create mode 100644 sdk/python/examples/controls/window_drag_area/no_frame_window/pyproject.toml diff --git a/sdk/python/examples/controls/vertical_divider/__init__.py b/sdk/python/examples/controls/vertical_divider/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/vertical_divider/basic.py b/sdk/python/examples/controls/vertical_divider/basic.py deleted file mode 100644 index ec017dda0a..0000000000 --- a/sdk/python/examples/controls/vertical_divider/basic.py +++ /dev/null @@ -1,40 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Row( - width=180, - height=100, - spacing=0, - controls=[ - ft.Container( - bgcolor=ft.Colors.ORANGE_300, - alignment=ft.Alignment.CENTER, - expand=True, - ), - ft.VerticalDivider(), - ft.Container( - bgcolor=ft.Colors.BROWN_400, - alignment=ft.Alignment.CENTER, - expand=True, - ), - ft.VerticalDivider(width=1, color=ft.Colors.WHITE), - ft.Container( - bgcolor=ft.Colors.BLUE_300, - alignment=ft.Alignment.CENTER, - expand=True, - ), - ft.VerticalDivider(width=9, thickness=3), - ft.Container( - bgcolor=ft.Colors.GREEN_300, - alignment=ft.Alignment.CENTER, - expand=True, - ), - ], - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/vertical_divider/basic/main.py b/sdk/python/examples/controls/vertical_divider/basic/main.py new file mode 100644 index 0000000000..5bbe82841f --- /dev/null +++ b/sdk/python/examples/controls/vertical_divider/basic/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + width=180, + height=100, + spacing=0, + controls=[ + ft.Container( + bgcolor=ft.Colors.ORANGE_300, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.VerticalDivider(), + ft.Container( + bgcolor=ft.Colors.BROWN_400, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.VerticalDivider(width=1, color=ft.Colors.WHITE), + ft.Container( + bgcolor=ft.Colors.BLUE_300, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.VerticalDivider(width=9, thickness=3), + ft.Container( + bgcolor=ft.Colors.GREEN_300, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/vertical_divider/basic/pyproject.toml b/sdk/python/examples/controls/vertical_divider/basic/pyproject.toml new file mode 100644 index 0000000000..776000ff46 --- /dev/null +++ b/sdk/python/examples/controls/vertical_divider/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "vertical-divider-basic" +version = "1.0.0" +description = "Separates colored containers in a row using VerticalDivider variants." +requires-python = ">=3.10" +keywords = ["vertical divider", "layout", "row", "spacing", "divider"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/VerticalDivider"] + +[tool.flet.metadata] +title = "VerticalDivider basic" +controls = ["SafeArea", "Row", "VerticalDivider", "Container"] +layout_pattern = "single-row" +complexity = "basic" +features = ["divider width and thickness variants"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/video/example_1.py b/sdk/python/examples/controls/video/example_1/main.py similarity index 99% rename from sdk/python/examples/controls/video/example_1.py rename to sdk/python/examples/controls/video/example_1/main.py index 49b67cd638..16e0cada1e 100644 --- a/sdk/python/examples/controls/video/example_1.py +++ b/sdk/python/examples/controls/video/example_1/main.py @@ -137,4 +137,5 @@ async def handle_fullscreen(e: ft.Event[ft.Button]): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/video/example_1/pyproject.toml b/sdk/python/examples/controls/video/example_1/pyproject.toml new file mode 100644 index 0000000000..df62d0f886 --- /dev/null +++ b/sdk/python/examples/controls/video/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-example-1" +version = "1.0.0" +description = "Controls video playback, playlist management, volume, and fullscreen in a Flet video player." +requires-python = ">=3.10" +keywords = ["video", "media", "playlist", "fullscreen", "player", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Video example 1" +controls = ["SafeArea", "Column", "Row", "Button", "Slider", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["playlist controls", "volume control", "playback rate control", "fullscreen"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/webview/example_1.py b/sdk/python/examples/controls/webview/example_1.py deleted file mode 100644 index 32495aa5ed..0000000000 --- a/sdk/python/examples/controls/webview/example_1.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet_webview as fwv - -import flet as ft - - -def main(page: ft.Page): - page.add( - fwv.WebView( - url="https://flet.dev", - on_page_started=lambda _: print("Page started"), - on_page_ended=lambda _: print("Page ended"), - on_web_resource_error=lambda e: print("WebView error:", e.data), - expand=True, - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/webview/example_1/main.py b/sdk/python/examples/controls/webview/example_1/main.py new file mode 100644 index 0000000000..7bc13ebda5 --- /dev/null +++ b/sdk/python/examples/controls/webview/example_1/main.py @@ -0,0 +1,21 @@ +import flet as ft +import flet_webview as fwv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=fwv.WebView( + url="https://flet.dev", + on_page_started=lambda _: print("Page started"), + on_page_ended=lambda _: print("Page ended"), + on_web_resource_error=lambda e: print("WebView error:", e.data), + expand=True, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/webview/example_1/pyproject.toml b/sdk/python/examples/controls/webview/example_1/pyproject.toml new file mode 100644 index 0000000000..5bf2c696b1 --- /dev/null +++ b/sdk/python/examples/controls/webview/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "webview-example-1" +version = "1.0.0" +description = "Displays a web page in a WebView and logs page lifecycle events." +requires-python = ">=3.10" +keywords = ["webview", "browser", "web", "events", "embedded"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-webview"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Display/WebView"] + +[tool.flet.metadata] +title = "WebView example 1" +controls = ["SafeArea", "WebView"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["page lifecycle events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/window_drag_area/__init__.py b/sdk/python/examples/controls/window_drag_area/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/controls/window_drag_area/no_frame_window.py b/sdk/python/examples/controls/window_drag_area/no_frame_window.py deleted file mode 100644 index d40ee59670..0000000000 --- a/sdk/python/examples/controls/window_drag_area/no_frame_window.py +++ /dev/null @@ -1,32 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.window.title_bar_hidden = True - page.window.title_bar_buttons_hidden = True - - async def handle_window_close(e: ft.Event[ft.IconButton]): - await page.window.close() - - page.add( - ft.Row( - controls=[ - ft.WindowDragArea( - expand=True, - content=ft.Container( - bgcolor=ft.Colors.AMBER_300, - padding=10, - content=ft.Text( - "Drag this area to move, maximize and " - "restore application window." - ), - ), - ), - ft.IconButton(ft.Icons.CLOSE, on_click=handle_window_close), - ] - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/controls/window_drag_area/no_frame_window/main.py b/sdk/python/examples/controls/window_drag_area/no_frame_window/main.py new file mode 100644 index 0000000000..3e403a4f3c --- /dev/null +++ b/sdk/python/examples/controls/window_drag_area/no_frame_window/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + page.window.title_bar_hidden = True + page.window.title_bar_buttons_hidden = True + + async def handle_window_close(e: ft.Event[ft.IconButton]): + await page.window.close() + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.WindowDragArea( + expand=True, + content=ft.Container( + bgcolor=ft.Colors.AMBER_300, + padding=10, + content=ft.Text( + "Drag this area to move, maximize and " + "restore application window." + ), + ), + ), + ft.IconButton(ft.Icons.CLOSE, on_click=handle_window_close), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/window_drag_area/no_frame_window/pyproject.toml b/sdk/python/examples/controls/window_drag_area/no_frame_window/pyproject.toml new file mode 100644 index 0000000000..631e8805ee --- /dev/null +++ b/sdk/python/examples/controls/window_drag_area/no_frame_window/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "window-drag-area-no-frame-window" +version = "1.0.0" +description = "Creates a frameless window with a custom draggable title area and close button." +requires-python = ">=3.10" +keywords = ["window drag area", "desktop", "window", "frameless", "drag"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/WindowDragArea"] + +[tool.flet.metadata] +title = "No frame window" +controls = ["SafeArea", "Row", "WindowDragArea", "Container", "Text", "IconButton"] +layout_pattern = "toolbar-content" +complexity = "basic" +features = ["frameless window", "custom window dragging"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/controls/verticaldivider.md b/sdk/python/packages/flet/docs/controls/verticaldivider.md index fc5a776b7a..123d7c9fe3 100644 --- a/sdk/python/packages/flet/docs/controls/verticaldivider.md +++ b/sdk/python/packages/flet/docs/controls/verticaldivider.md @@ -13,7 +13,7 @@ example_images: ../test-images/examples/core/golden/macos/vertical_divider ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ image(example_images + "/basic.png", alt="basic", width="80%") }} diff --git a/sdk/python/packages/flet/docs/controls/windowdragarea.md b/sdk/python/packages/flet/docs/controls/windowdragarea.md index 2ced1c493d..be36025467 100644 --- a/sdk/python/packages/flet/docs/controls/windowdragarea.md +++ b/sdk/python/packages/flet/docs/controls/windowdragarea.md @@ -11,7 +11,7 @@ example_images: ../test-images/examples/core/golden/macos/window_drag_area ### No frame window ```python ---8<-- "{{ examples }}/no_frame_window.py" +--8<-- "{{ examples }}/no_frame_window/main.py" ``` {{ image(example_images + "/no_frame_window.png", alt="no-frame-window", width="80%") }} diff --git a/sdk/python/packages/flet/docs/video/index.md b/sdk/python/packages/flet/docs/video/index.md index 2dd66544a5..4ad4932e19 100644 --- a/sdk/python/packages/flet/docs/video/index.md +++ b/sdk/python/packages/flet/docs/video/index.md @@ -93,7 +93,7 @@ sudo ln -s /usr/lib/x86_64-linux-gnu/libmpv.so /usr/lib/libmpv.so.1 ### Basic example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Description diff --git a/sdk/python/packages/flet/docs/webview/index.md b/sdk/python/packages/flet/docs/webview/index.md index 509d07eef3..7d14b3ff1a 100644 --- a/sdk/python/packages/flet/docs/webview/index.md +++ b/sdk/python/packages/flet/docs/webview/index.md @@ -37,7 +37,7 @@ pip install flet-webview # (1)! ## Example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Troubleshooting diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_vertical_divider.py b/sdk/python/packages/flet/integration_tests/examples/core/test_vertical_divider.py index 86b2bf3005..3df5c67d47 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_vertical_divider.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_vertical_divider.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.vertical_divider.basic.main as basic import flet as ft import flet.testing as ftt -from examples.controls.vertical_divider import basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/core/test_window_drag_area.py b/sdk/python/packages/flet/integration_tests/examples/core/test_window_drag_area.py index e12f1ade5a..4195ce672f 100644 --- a/sdk/python/packages/flet/integration_tests/examples/core/test_window_drag_area.py +++ b/sdk/python/packages/flet/integration_tests/examples/core/test_window_drag_area.py @@ -1,8 +1,8 @@ import pytest +import examples.controls.window_drag_area.no_frame_window.main as no_frame_window import flet as ft import flet.testing as ftt -from examples.controls.window_drag_area import no_frame_window @pytest.mark.asyncio(loop_scope="function") From e9bd493422df4c36ada5d2c4a47a64950a16608c Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 26 Mar 2026 12:06:20 -0700 Subject: [PATCH 80/96] Move container alignment example and add metadata Remove the old standalone container.py and add a new example at sdk/python/examples/controls/types/alignment/container/main.py (wrap-enabled Row inside SafeArea/Column). Add pyproject.toml for the example with project and Flet gallery metadata. Update the docs to reference the new examples/container/main.py path. --- .../controls/types/alignment/container.py | 39 --------------- .../types/alignment/container/main.py | 47 +++++++++++++++++++ .../types/alignment/container/pyproject.toml | 26 ++++++++++ .../packages/flet/docs/types/alignment.md | 2 +- 4 files changed, 74 insertions(+), 40 deletions(-) delete mode 100644 sdk/python/examples/controls/types/alignment/container.py create mode 100644 sdk/python/examples/controls/types/alignment/container/main.py create mode 100644 sdk/python/examples/controls/types/alignment/container/pyproject.toml diff --git a/sdk/python/examples/controls/types/alignment/container.py b/sdk/python/examples/controls/types/alignment/container.py deleted file mode 100644 index b6f0f1ca35..0000000000 --- a/sdk/python/examples/controls/types/alignment/container.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Containers with different alignments" - - page.add( - ft.Row( - controls=[ - ft.Container( - content=ft.Button("Center"), - bgcolor=ft.Colors.AMBER, - padding=15, - alignment=ft.Alignment.CENTER, - width=150, - height=150, - ), - ft.Container( - content=ft.Button("Top left"), - bgcolor=ft.Colors.AMBER, - padding=15, - alignment=ft.Alignment.TOP_LEFT, - width=150, - height=150, - ), - ft.Container( - content=ft.Button("-0.5, -0.5"), - bgcolor=ft.Colors.AMBER, - padding=15, - alignment=ft.Alignment(-0.5, -0.5), - width=150, - height=150, - ), - ] - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/alignment/container/main.py b/sdk/python/examples/controls/types/alignment/container/main.py new file mode 100644 index 0000000000..95a29be797 --- /dev/null +++ b/sdk/python/examples/controls/types/alignment/container/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Containers with different alignments" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Container( + bgcolor=ft.Colors.AMBER, + padding=15, + alignment=ft.Alignment.CENTER, + width=150, + height=150, + content=ft.Button("Center"), + ), + ft.Container( + bgcolor=ft.Colors.AMBER, + padding=15, + alignment=ft.Alignment.TOP_LEFT, + width=150, + height=150, + content=ft.Button("Top left"), + ), + ft.Container( + bgcolor=ft.Colors.AMBER, + padding=15, + alignment=ft.Alignment(-0.5, -0.5), + width=150, + height=150, + content=ft.Button("-0.5, -0.5"), + ), + ], + wrap=True, + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/alignment/container/pyproject.toml b/sdk/python/examples/controls/types/alignment/container/pyproject.toml new file mode 100644 index 0000000000..cb8c384639 --- /dev/null +++ b/sdk/python/examples/controls/types/alignment/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-alignment-container" +version = "1.0.0" +description = "Shows how container content placement changes with preset and custom alignment values." +requires-python = ">=3.10" +keywords = ["alignment", "types", "container", "layout", "positioning"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Container alignment" +controls = ["SafeArea", "Column", "Row", "Container", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["preset alignment", "custom alignment coordinates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/types/alignment.md b/sdk/python/packages/flet/docs/types/alignment.md index d82381a830..2f23dc08d6 100644 --- a/sdk/python/packages/flet/docs/types/alignment.md +++ b/sdk/python/packages/flet/docs/types/alignment.md @@ -10,7 +10,7 @@ example_media: ../examples/controls/types/alignment/media ### Example 1 ```python ---8<-- "{{ examples }}/container.py" +--8<-- "{{ examples }}/container/main.py" ``` {{ image(example_media + "/container.png", width="80%") }} From 7db7dba473022f796f003440b56120ec7cff5cc9 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Thu, 26 Mar 2026 13:04:57 -0700 Subject: [PATCH 81/96] Restructure Python examples and add metadata Move example entrypoints into showcase/main.py (rename showcase.py -> showcase/main.py), wrap example UIs with SafeArea/Column, and replace direct ft.run calls with an if __name__ == "__main__" guard. Add per-example pyproject.toml files with gallery/metadata for many showcases, relocate several container/showcase scripts into new main.py paths, and remove legacy/duplicate files. Also update multiple docs under sdk/python/packages/flet/docs/types to reflect these changes. --- .../{showcase.py => showcase/main.py} | 33 +-- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 60 +++-- .../animation_curve/showcase/pyproject.toml | 26 +++ .../types/app_lifecycle_state/showcase.py | 55 ----- .../app_lifecycle_state/showcase/main.py | 65 ++++++ .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 38 ++-- .../assertiveness/showcase/pyproject.toml | 26 +++ .../axis/{showcase.py => showcase/main.py} | 27 ++- .../types/axis/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../types/blend_mode/showcase/pyproject.toml | 26 +++ .../examples/controls/types/blur/container.py | 61 ----- .../controls/types/blur/container/main.py | 68 ++++++ .../types/blur/container/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 33 +-- .../types/blur_style/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../blur_tile_mode/showcase/pyproject.toml | 26 +++ .../controls/types/border/container.py | 40 ---- .../controls/types/border/container/main.py | 49 ++++ .../types/border/container/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../border_style/showcase/pyproject.toml | 26 +++ .../box_fit/{showcase.py => showcase/main.py} | 29 ++- .../types/box_fit/showcase/pyproject.toml | 26 +++ .../controls/types/box_shadow/container.py | 42 ---- .../types/box_shadow/container/main.py | 49 ++++ .../types/box_shadow/container/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../types/box_shape/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../card_variant/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../clip_behavior/showcase/pyproject.toml | 26 +++ .../main.py} | 11 +- .../disable_auto_update/pyproject.toml | 26 +++ .../controls/types/context/get_page.py | 11 - .../controls/types/context/get_page/main.py | 18 ++ .../types/context/get_page/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 31 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 33 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 33 +-- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 31 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../date_picker_mode/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 30 ++- .../dismiss_direction/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../filter_quality/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../types/font_weight/showcase/pyproject.toml | 26 +++ .../controls/types/gradient/container.py | 95 -------- .../controls/types/gradient/container/main.py | 106 +++++++++ .../types/gradient/container/pyproject.toml | 26 +++ .../gradient/linear_gradient/container.py | 33 --- .../linear_gradient/container/main.py | 40 ++++ .../linear_gradient/container/pyproject.toml | 26 +++ .../gradient/radial_gradient/container.py | 21 -- .../radial_gradient/container/main.py | 28 +++ .../radial_gradient/container/pyproject.toml | 26 +++ .../gradient/sweep_gradient/container.py | 30 --- .../gradient/sweep_gradient/container/main.py | 37 +++ .../sweep_gradient/container/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 30 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../image_repeat/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../label_position/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../types/launch_mode/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../list_tile_style/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 33 ++- .../showcase/pyproject.toml | 26 +++ .../controls/types/margin/container.py | 48 ---- .../controls/types/margin/container/main.py | 55 +++++ .../types/margin/container/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 33 +-- .../mouse_cursor/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../types/orientation/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../showcase/pyproject.toml | 26 +++ .../controls/types/padding/container.py | 43 ---- .../controls/types/padding/container/main.py | 50 +++++ .../types/padding/container/pyproject.toml | 26 +++ .../types/paint_gradient/canvas_paint.py | 71 ------ .../types/paint_gradient/canvas_paint/main.py | 78 +++++++ .../canvas_paint/pyproject.toml | 26 +++ .../paint_linear_gradient/canvas_paint.py | 31 --- .../canvas_paint/main.py | 38 ++++ .../canvas_paint/pyproject.toml | 26 +++ .../paint_radial_gradient/canvas_paint.py | 29 --- .../canvas_paint/main.py | 36 +++ .../canvas_paint/pyproject.toml | 26 +++ .../paint_sweep_gradient/canvas_paint.py | 43 ---- .../paint_sweep_gradient/canvas_paint/main.py | 50 +++++ .../canvas_paint/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../painting_style/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../types/point_mode/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../showcase/pyproject.toml | 26 +++ .../controls/types/scroll_bar/showcase.py | 190 ---------------- .../types/scroll_bar/showcase/main.py | 211 ++++++++++++++++++ .../types/scroll_bar/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 38 ++-- .../showcase/pyproject.toml | 26 +++ .../types/scroll_direction/showcase.py | 48 ---- .../types/scroll_direction/showcase/main.py | 57 +++++ .../scroll_direction/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 31 ++- .../types/scroll_mode/showcase/pyproject.toml | 26 +++ .../controls/types/scroll_type/showcase.py | 50 ----- .../types/scroll_type/showcase/main.py | 62 +++++ .../types/scroll_type/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../types/stroke_cap/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../types/stroke_join/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../tab_alignment/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 36 +-- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../types/text_align/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 31 ++- .../text_overflow/showcase/pyproject.toml | 26 +++ .../controls/types/theme_mode/showcase.py | 63 ------ .../types/theme_mode/showcase/main.py | 72 ++++++ .../types/theme_mode/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../tile_affinity/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 27 ++- .../showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 32 ++- .../showcase/pyproject.toml | 26 +++ .../controls/types/tooltip/with_decoration.py | 39 ---- .../types/tooltip/with_decoration/main.py | 49 ++++ .../tooltip/with_decoration/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 31 ++- .../types/url_target/showcase/pyproject.toml | 26 +++ .../{showcase.py => showcase/main.py} | 29 ++- .../visual_density/showcase/pyproject.toml | 26 +++ .../types/window_event_type/showcase.py | 55 ----- .../types/window_event_type/showcase/main.py | 65 ++++++ .../window_event_type/showcase/pyproject.toml | 26 +++ .../docs/types/animatedswitchertransition.md | 2 +- .../flet/docs/types/animationcurve.md | 2 +- .../flet/docs/types/applifecyclestate.md | 2 +- .../packages/flet/docs/types/assertiveness.md | 2 +- sdk/python/packages/flet/docs/types/axis.md | 2 +- .../packages/flet/docs/types/blendmode.md | 2 +- sdk/python/packages/flet/docs/types/blur.md | 2 +- .../packages/flet/docs/types/blurstyle.md | 2 +- .../packages/flet/docs/types/blurtilemode.md | 2 +- sdk/python/packages/flet/docs/types/border.md | 2 +- .../flet/docs/types/bordersidestrokealign.md | 2 +- .../packages/flet/docs/types/borderstyle.md | 2 +- sdk/python/packages/flet/docs/types/boxfit.md | 2 +- .../packages/flet/docs/types/boxshadow.md | 2 +- .../packages/flet/docs/types/boxshape.md | 2 +- .../packages/flet/docs/types/cardvariant.md | 2 +- .../packages/flet/docs/types/clipbehavior.md | 2 +- .../flet/docs/types/contextmenutrigger.md | 2 +- .../flet/docs/types/crossaxisalignment.md | 2 +- .../flet/docs/types/cupertinobuttonsize.md | 2 +- .../types/cupertinodatepickerdateorder.md | 2 +- .../docs/types/cupertinodatepickermode.md | 2 +- .../docs/types/cupertinotimerpickermode.md | 2 +- .../flet/docs/types/datepickerentrymode.md | 2 +- .../flet/docs/types/datepickermode.md | 2 +- .../flet/docs/types/dismissdirection.md | 2 +- .../packages/flet/docs/types/filterquality.md | 2 +- .../types/floatingactionbuttonlocation.md | 2 +- .../packages/flet/docs/types/fontweight.md | 2 +- .../flet/docs/types/gradient/index.md | 2 +- .../flet/docs/types/gradienttilemode.md | 2 +- .../packages/flet/docs/types/imagerepeat.md | 2 +- .../packages/flet/docs/types/labelposition.md | 2 +- .../packages/flet/docs/types/launchmode.md | 2 +- .../flet/docs/types/lineargradient.md | 2 +- .../packages/flet/docs/types/listtilestyle.md | 2 +- .../flet/docs/types/listtiletitlealignment.md | 2 +- .../flet/docs/types/mainaxisalignment.md | 2 +- sdk/python/packages/flet/docs/types/margin.md | 2 +- .../packages/flet/docs/types/mousecursor.md | 2 +- .../docs/types/navigationbarlabelbehavior.md | 2 +- .../docs/types/navigationraillabeltype.md | 2 +- .../packages/flet/docs/types/orientation.md | 2 +- .../flet/docs/types/overlayvisibilitymode.md | 2 +- .../packages/flet/docs/types/padding.md | 2 +- .../flet/docs/types/paintgradient/index.md | 2 +- .../packages/flet/docs/types/paintingstyle.md | 2 +- .../flet/docs/types/paintlineargradient.md | 2 +- .../flet/docs/types/paintradialgradient.md | 2 +- .../flet/docs/types/paintsweepgradient.md | 2 +- .../packages/flet/docs/types/pointmode.md | 2 +- .../flet/docs/types/popupmenuposition.md | 2 +- .../flet/docs/types/radialgradient.md | 2 +- .../packages/flet/docs/types/scrollbar.md | 2 +- .../flet/docs/types/scrollbarorientation.md | 2 +- .../flet/docs/types/scrolldirection.md | 2 +- .../packages/flet/docs/types/scrollmode.md | 2 +- .../packages/flet/docs/types/scrolltype.md | 2 +- .../flet/docs/types/sliderinteraction.md | 2 +- .../flet/docs/types/snackbarbehavior.md | 2 +- .../packages/flet/docs/types/strokecap.md | 2 +- .../packages/flet/docs/types/strokejoin.md | 2 +- .../packages/flet/docs/types/sweepgradient.md | 2 +- .../packages/flet/docs/types/tabalignment.md | 2 +- .../flet/docs/types/tabbarindicatorsize.md | 2 +- .../flet/docs/types/tabindicatoranimation.md | 2 +- .../packages/flet/docs/types/textalign.md | 2 +- .../flet/docs/types/textcapitalization.md | 2 +- .../flet/docs/types/textdecorationstyle.md | 2 +- .../packages/flet/docs/types/textoverflow.md | 2 +- .../packages/flet/docs/types/thememode.md | 2 +- .../packages/flet/docs/types/tileaffinity.md | 2 +- .../flet/docs/types/timepickerentrymode.md | 2 +- .../flet/docs/types/timepickerhourformat.md | 2 +- .../packages/flet/docs/types/tooltip.md | 2 +- .../packages/flet/docs/types/urltarget.md | 2 +- .../packages/flet/docs/types/visualdensity.md | 2 +- .../flet/docs/types/windoweventtype.md | 2 +- 259 files changed, 4602 insertions(+), 1810 deletions(-) rename sdk/python/examples/controls/types/animated_switcher_transition/{showcase.py => showcase/main.py} (68%) create mode 100644 sdk/python/examples/controls/types/animated_switcher_transition/showcase/pyproject.toml rename sdk/python/examples/controls/types/animation_curve/{showcase.py => showcase/main.py} (76%) create mode 100644 sdk/python/examples/controls/types/animation_curve/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/app_lifecycle_state/showcase.py create mode 100644 sdk/python/examples/controls/types/app_lifecycle_state/showcase/main.py create mode 100644 sdk/python/examples/controls/types/app_lifecycle_state/showcase/pyproject.toml rename sdk/python/examples/controls/types/assertiveness/{showcase.py => showcase/main.py} (66%) create mode 100644 sdk/python/examples/controls/types/assertiveness/showcase/pyproject.toml rename sdk/python/examples/controls/types/axis/{showcase.py => showcase/main.py} (64%) create mode 100644 sdk/python/examples/controls/types/axis/showcase/pyproject.toml rename sdk/python/examples/controls/types/blend_mode/{showcase.py => showcase/main.py} (58%) create mode 100644 sdk/python/examples/controls/types/blend_mode/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/blur/container.py create mode 100644 sdk/python/examples/controls/types/blur/container/main.py create mode 100644 sdk/python/examples/controls/types/blur/container/pyproject.toml rename sdk/python/examples/controls/types/blur_style/{showcase.py => showcase/main.py} (59%) create mode 100644 sdk/python/examples/controls/types/blur_style/showcase/pyproject.toml rename sdk/python/examples/controls/types/blur_tile_mode/{showcase.py => showcase/main.py} (75%) create mode 100644 sdk/python/examples/controls/types/blur_tile_mode/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/border/container.py create mode 100644 sdk/python/examples/controls/types/border/container/main.py create mode 100644 sdk/python/examples/controls/types/border/container/pyproject.toml rename sdk/python/examples/controls/types/border_side_stroke_align/{showcase.py => showcase/main.py} (67%) create mode 100644 sdk/python/examples/controls/types/border_side_stroke_align/showcase/pyproject.toml rename sdk/python/examples/controls/types/border_style/{showcase.py => showcase/main.py} (62%) create mode 100644 sdk/python/examples/controls/types/border_style/showcase/pyproject.toml rename sdk/python/examples/controls/types/box_fit/{showcase.py => showcase/main.py} (63%) create mode 100644 sdk/python/examples/controls/types/box_fit/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/box_shadow/container.py create mode 100644 sdk/python/examples/controls/types/box_shadow/container/main.py create mode 100644 sdk/python/examples/controls/types/box_shadow/container/pyproject.toml rename sdk/python/examples/controls/types/box_shape/{showcase.py => showcase/main.py} (73%) create mode 100644 sdk/python/examples/controls/types/box_shape/showcase/pyproject.toml rename sdk/python/examples/controls/types/card_variant/{showcase.py => showcase/main.py} (65%) create mode 100644 sdk/python/examples/controls/types/card_variant/showcase/pyproject.toml rename sdk/python/examples/controls/types/clip_behavior/{showcase.py => showcase/main.py} (74%) create mode 100644 sdk/python/examples/controls/types/clip_behavior/showcase/pyproject.toml rename sdk/python/examples/controls/types/context/{disable_auto_update.py => disable_auto_update/main.py} (62%) create mode 100644 sdk/python/examples/controls/types/context/disable_auto_update/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/context/get_page.py create mode 100644 sdk/python/examples/controls/types/context/get_page/main.py create mode 100644 sdk/python/examples/controls/types/context/get_page/pyproject.toml rename sdk/python/examples/controls/types/context_menu_trigger/{showcase.py => showcase/main.py} (74%) create mode 100644 sdk/python/examples/controls/types/context_menu_trigger/showcase/pyproject.toml rename sdk/python/examples/controls/types/cross_axis_alignment/{showcase.py => showcase/main.py} (76%) create mode 100644 sdk/python/examples/controls/types/cross_axis_alignment/showcase/pyproject.toml rename sdk/python/examples/controls/types/cupertino_button_size/{showcase.py => showcase/main.py} (59%) create mode 100644 sdk/python/examples/controls/types/cupertino_button_size/showcase/pyproject.toml rename sdk/python/examples/controls/types/cupertino_date_picker_date_order/{showcase.py => showcase/main.py} (66%) create mode 100644 sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase/pyproject.toml rename sdk/python/examples/controls/types/cupertino_date_picker_mode/{showcase.py => showcase/main.py} (64%) create mode 100644 sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/cupertino_timer_picker_mode/{showcase.py => showcase/main.py} (54%) create mode 100644 sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/date_picker_entry_mode/{showcase.py => showcase/main.py} (66%) create mode 100644 sdk/python/examples/controls/types/date_picker_entry_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/date_picker_mode/{showcase.py => showcase/main.py} (67%) create mode 100644 sdk/python/examples/controls/types/date_picker_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/dismiss_direction/{showcase.py => showcase/main.py} (77%) create mode 100644 sdk/python/examples/controls/types/dismiss_direction/showcase/pyproject.toml rename sdk/python/examples/controls/types/filter_quality/{showcase.py => showcase/main.py} (62%) create mode 100644 sdk/python/examples/controls/types/filter_quality/showcase/pyproject.toml rename sdk/python/examples/controls/types/floating_action_button_location/{showcase.py => showcase/main.py} (71%) create mode 100644 sdk/python/examples/controls/types/floating_action_button_location/showcase/pyproject.toml rename sdk/python/examples/controls/types/font_weight/{showcase.py => showcase/main.py} (54%) create mode 100644 sdk/python/examples/controls/types/font_weight/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/gradient/container.py create mode 100644 sdk/python/examples/controls/types/gradient/container/main.py create mode 100644 sdk/python/examples/controls/types/gradient/container/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/gradient/linear_gradient/container.py create mode 100644 sdk/python/examples/controls/types/gradient/linear_gradient/container/main.py create mode 100644 sdk/python/examples/controls/types/gradient/linear_gradient/container/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/gradient/radial_gradient/container.py create mode 100644 sdk/python/examples/controls/types/gradient/radial_gradient/container/main.py create mode 100644 sdk/python/examples/controls/types/gradient/radial_gradient/container/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/gradient/sweep_gradient/container.py create mode 100644 sdk/python/examples/controls/types/gradient/sweep_gradient/container/main.py create mode 100644 sdk/python/examples/controls/types/gradient/sweep_gradient/container/pyproject.toml rename sdk/python/examples/controls/types/gradient_tile_mode/{showcase.py => showcase/main.py} (59%) create mode 100644 sdk/python/examples/controls/types/gradient_tile_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/image_repeat/{showcase.py => showcase/main.py} (62%) create mode 100644 sdk/python/examples/controls/types/image_repeat/showcase/pyproject.toml rename sdk/python/examples/controls/types/label_position/{showcase.py => showcase/main.py} (66%) create mode 100644 sdk/python/examples/controls/types/label_position/showcase/pyproject.toml rename sdk/python/examples/controls/types/launch_mode/{showcase.py => showcase/main.py} (68%) create mode 100644 sdk/python/examples/controls/types/launch_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/list_tile_style/{showcase.py => showcase/main.py} (65%) create mode 100644 sdk/python/examples/controls/types/list_tile_style/showcase/pyproject.toml rename sdk/python/examples/controls/types/list_tile_title_alignment/{showcase.py => showcase/main.py} (64%) create mode 100644 sdk/python/examples/controls/types/list_tile_title_alignment/showcase/pyproject.toml rename sdk/python/examples/controls/types/main_axis_alignment/{showcase.py => showcase/main.py} (64%) create mode 100644 sdk/python/examples/controls/types/main_axis_alignment/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/margin/container.py create mode 100644 sdk/python/examples/controls/types/margin/container/main.py create mode 100644 sdk/python/examples/controls/types/margin/container/pyproject.toml rename sdk/python/examples/controls/types/mouse_cursor/{showcase.py => showcase/main.py} (54%) create mode 100644 sdk/python/examples/controls/types/mouse_cursor/showcase/pyproject.toml rename sdk/python/examples/controls/types/navigation_bar_label_behavior/{showcase.py => showcase/main.py} (59%) create mode 100644 sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase/pyproject.toml rename sdk/python/examples/controls/types/navigation_rail_label_type/{showcase.py => showcase/main.py} (64%) create mode 100644 sdk/python/examples/controls/types/navigation_rail_label_type/showcase/pyproject.toml rename sdk/python/examples/controls/types/orientation/{showcase.py => showcase/main.py} (61%) create mode 100644 sdk/python/examples/controls/types/orientation/showcase/pyproject.toml rename sdk/python/examples/controls/types/overlay_visibility_mode/{showcase.py => showcase/main.py} (66%) create mode 100644 sdk/python/examples/controls/types/overlay_visibility_mode/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/padding/container.py create mode 100644 sdk/python/examples/controls/types/padding/container/main.py create mode 100644 sdk/python/examples/controls/types/padding/container/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/paint_gradient/canvas_paint.py create mode 100644 sdk/python/examples/controls/types/paint_gradient/canvas_paint/main.py create mode 100644 sdk/python/examples/controls/types/paint_gradient/canvas_paint/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint.py create mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/main.py create mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint.py create mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/main.py create mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint.py create mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/main.py create mode 100644 sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/pyproject.toml rename sdk/python/examples/controls/types/painting_style/{showcase.py => showcase/main.py} (65%) create mode 100644 sdk/python/examples/controls/types/painting_style/showcase/pyproject.toml rename sdk/python/examples/controls/types/point_mode/{showcase.py => showcase/main.py} (64%) create mode 100644 sdk/python/examples/controls/types/point_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/popup_menu_position/{showcase.py => showcase/main.py} (63%) create mode 100644 sdk/python/examples/controls/types/popup_menu_position/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/scroll_bar/showcase.py create mode 100644 sdk/python/examples/controls/types/scroll_bar/showcase/main.py create mode 100644 sdk/python/examples/controls/types/scroll_bar/showcase/pyproject.toml rename sdk/python/examples/controls/types/scroll_bar_orientation/{showcase.py => showcase/main.py} (72%) create mode 100644 sdk/python/examples/controls/types/scroll_bar_orientation/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/scroll_direction/showcase.py create mode 100644 sdk/python/examples/controls/types/scroll_direction/showcase/main.py create mode 100644 sdk/python/examples/controls/types/scroll_direction/showcase/pyproject.toml rename sdk/python/examples/controls/types/scroll_mode/{showcase.py => showcase/main.py} (61%) create mode 100644 sdk/python/examples/controls/types/scroll_mode/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/scroll_type/showcase.py create mode 100644 sdk/python/examples/controls/types/scroll_type/showcase/main.py create mode 100644 sdk/python/examples/controls/types/scroll_type/showcase/pyproject.toml rename sdk/python/examples/controls/types/slider_interaction/{showcase.py => showcase/main.py} (70%) create mode 100644 sdk/python/examples/controls/types/slider_interaction/showcase/pyproject.toml rename sdk/python/examples/controls/types/snack_bar_behavior/{showcase.py => showcase/main.py} (64%) create mode 100644 sdk/python/examples/controls/types/snack_bar_behavior/showcase/pyproject.toml rename sdk/python/examples/controls/types/stroke_cap/{showcase.py => showcase/main.py} (72%) create mode 100644 sdk/python/examples/controls/types/stroke_cap/showcase/pyproject.toml rename sdk/python/examples/controls/types/stroke_join/{showcase.py => showcase/main.py} (68%) create mode 100644 sdk/python/examples/controls/types/stroke_join/showcase/pyproject.toml rename sdk/python/examples/controls/types/tab_alignment/{showcase.py => showcase/main.py} (69%) create mode 100644 sdk/python/examples/controls/types/tab_alignment/showcase/pyproject.toml rename sdk/python/examples/controls/types/tab_bar_indicator_size/{showcase.py => showcase/main.py} (68%) create mode 100644 sdk/python/examples/controls/types/tab_bar_indicator_size/showcase/pyproject.toml rename sdk/python/examples/controls/types/tab_indicator_animation/{showcase.py => showcase/main.py} (70%) create mode 100644 sdk/python/examples/controls/types/tab_indicator_animation/showcase/pyproject.toml rename sdk/python/examples/controls/types/text_align/{showcase.py => showcase/main.py} (59%) create mode 100644 sdk/python/examples/controls/types/text_align/showcase/pyproject.toml rename sdk/python/examples/controls/types/text_capitalization/{showcase.py => showcase/main.py} (54%) create mode 100644 sdk/python/examples/controls/types/text_capitalization/showcase/pyproject.toml rename sdk/python/examples/controls/types/text_decoration_style/{showcase.py => showcase/main.py} (67%) create mode 100644 sdk/python/examples/controls/types/text_decoration_style/showcase/pyproject.toml rename sdk/python/examples/controls/types/text_overflow/{showcase.py => showcase/main.py} (61%) create mode 100644 sdk/python/examples/controls/types/text_overflow/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/theme_mode/showcase.py create mode 100644 sdk/python/examples/controls/types/theme_mode/showcase/main.py create mode 100644 sdk/python/examples/controls/types/theme_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/tile_affinity/{showcase.py => showcase/main.py} (58%) create mode 100644 sdk/python/examples/controls/types/tile_affinity/showcase/pyproject.toml rename sdk/python/examples/controls/types/time_picker_entry_mode/{showcase.py => showcase/main.py} (64%) create mode 100644 sdk/python/examples/controls/types/time_picker_entry_mode/showcase/pyproject.toml rename sdk/python/examples/controls/types/time_picker_hour_format/{showcase.py => showcase/main.py} (62%) create mode 100644 sdk/python/examples/controls/types/time_picker_hour_format/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/tooltip/with_decoration.py create mode 100644 sdk/python/examples/controls/types/tooltip/with_decoration/main.py create mode 100644 sdk/python/examples/controls/types/tooltip/with_decoration/pyproject.toml rename sdk/python/examples/controls/types/url_target/{showcase.py => showcase/main.py} (63%) create mode 100644 sdk/python/examples/controls/types/url_target/showcase/pyproject.toml rename sdk/python/examples/controls/types/visual_density/{showcase.py => showcase/main.py} (66%) create mode 100644 sdk/python/examples/controls/types/visual_density/showcase/pyproject.toml delete mode 100644 sdk/python/examples/controls/types/window_event_type/showcase.py create mode 100644 sdk/python/examples/controls/types/window_event_type/showcase/main.py create mode 100644 sdk/python/examples/controls/types/window_event_type/showcase/pyproject.toml diff --git a/sdk/python/examples/controls/types/animated_switcher_transition/showcase.py b/sdk/python/examples/controls/types/animated_switcher_transition/showcase/main.py similarity index 68% rename from sdk/python/examples/controls/types/animated_switcher_transition/showcase.py rename to sdk/python/examples/controls/types/animated_switcher_transition/showcase/main.py index 2a29132850..9802998e0d 100644 --- a/sdk/python/examples/controls/types/animated_switcher_transition/showcase.py +++ b/sdk/python/examples/controls/types/animated_switcher_transition/showcase/main.py @@ -56,19 +56,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="AnimatedSwitcherTransition Showcase") page.add( - ft.Text("Swap content to compare switcher transition effects."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(transition) - for transition in ft.AnimatedSwitcherTransition - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Swap content to compare switcher transition effects."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(transition) + for transition in ft.AnimatedSwitcherTransition + ], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/animated_switcher_transition/showcase/pyproject.toml b/sdk/python/examples/controls/types/animated_switcher_transition/showcase/pyproject.toml new file mode 100644 index 0000000000..e7cba6411e --- /dev/null +++ b/sdk/python/examples/controls/types/animated_switcher_transition/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-animated-switcher-transition-showcase" +version = "1.0.0" +description = "Compares Animated Switcher Transition values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["animated switcher transition", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Animated Switcher Transition showcase" +controls = ["SafeArea", "Column", "Container", "AnimatedSwitcher", "Text", "Button", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/animation_curve/showcase.py b/sdk/python/examples/controls/types/animation_curve/showcase/main.py similarity index 76% rename from sdk/python/examples/controls/types/animation_curve/showcase.py rename to sdk/python/examples/controls/types/animation_curve/showcase/main.py index a7373b4ac0..3cdbfac2f1 100644 --- a/sdk/python/examples/controls/types/animation_curve/showcase.py +++ b/sdk/python/examples/controls/types/animation_curve/showcase/main.py @@ -131,28 +131,44 @@ async def wave_all(): page.appbar = ft.AppBar(title="AnimationCurve Showcase") page.add( - ft.Text( - "Curve Lab: compare timing profiles across motion, progress, and spin." - ), - ft.Row( - wrap=True, - spacing=8, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - ft.Button("Play all", icon=ft.Icons.PLAY_ARROW, on_click=play_all), - ft.Button("Reverse all", icon=ft.Icons.REPLAY, on_click=reverse_all), - ft.Button("Wave", on_click=lambda e: page.run_task(wave_all)), - ], - ), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(curve) for curve in ft.AnimationCurve], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Curve Lab: compare timing profiles across motion, " + "progress, and spin." + ), + ft.Row( + wrap=True, + spacing=8, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Button( + "Play all", icon=ft.Icons.PLAY_ARROW, on_click=play_all + ), + ft.Button( + "Reverse all", + icon=ft.Icons.REPLAY, + on_click=reverse_all, + ), + ft.Button( + "Wave", on_click=lambda e: page.run_task(wave_all) + ), + ], + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(curve) for curve in ft.AnimationCurve], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/animation_curve/showcase/pyproject.toml b/sdk/python/examples/controls/types/animation_curve/showcase/pyproject.toml new file mode 100644 index 0000000000..7a876fda14 --- /dev/null +++ b/sdk/python/examples/controls/types/animation_curve/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-animation-curve-showcase" +version = "1.0.0" +description = "Compares Animation Curve values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["animation curve", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Animation Curve showcase" +controls = ["SafeArea", "Column", "Page", "AnimationCurve", "Container", "Icon", "Text", "Stack"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/app_lifecycle_state/showcase.py b/sdk/python/examples/controls/types/app_lifecycle_state/showcase.py deleted file mode 100644 index d105fba482..0000000000 --- a/sdk/python/examples/controls/types/app_lifecycle_state/showcase.py +++ /dev/null @@ -1,55 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - log = ft.Column( - spacing=4, - scroll=ft.ScrollMode.AUTO, - height=220, - ) - - def add_log(message: str): - log.controls.insert(0, ft.Text(message, size=12)) - if len(log.controls) > 20: - log.controls.pop() - log.update() - - def on_lifecycle(e: ft.AppLifecycleStateChangeEvent): - add_log(f"Received: {e.state.name}") - - page.on_app_lifecycle_state_change = on_lifecycle - - page.appbar = ft.AppBar(title="AppLifecycleState Showcase") - page.add( - ft.Text("Switch app focus/visibility to see lifecycle state changes."), - ft.Text( - "Ex: minimize/restore app, switch tabs, or background/foreground app.", - size=11, - ), - ft.Row( - wrap=True, - spacing=8, - controls=[ - ft.Container( - padding=ft.Padding.symmetric(horizontal=8, vertical=4), - border=ft.Border.all(1, ft.Colors.OUTLINE), - border_radius=12, - content=ft.Text(state.name, size=11), - ) - for state in ft.AppLifecycleState - ], - ), - ft.Container( - width=720, - padding=12, - border=ft.Border.all(1, ft.Colors.RED), - border_radius=10, - bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, - content=log, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/app_lifecycle_state/showcase/main.py b/sdk/python/examples/controls/types/app_lifecycle_state/showcase/main.py new file mode 100644 index 0000000000..6600f230ce --- /dev/null +++ b/sdk/python/examples/controls/types/app_lifecycle_state/showcase/main.py @@ -0,0 +1,65 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + log = ft.Column( + spacing=4, + scroll=ft.ScrollMode.AUTO, + height=220, + ) + + def add_log(message: str): + log.controls.insert(0, ft.Text(message, size=12)) + if len(log.controls) > 20: + log.controls.pop() + log.update() + + def on_lifecycle(e: ft.AppLifecycleStateChangeEvent): + add_log(f"Received: {e.state.name}") + + page.on_app_lifecycle_state_change = on_lifecycle + + page.appbar = ft.AppBar(title="AppLifecycleState Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Switch app focus/visibility to see lifecycle state changes." + ), + ft.Text( + "Ex: minimize/restore app, switch tabs, or " + "background/foreground app.", + size=11, + ), + ft.Row( + wrap=True, + spacing=8, + controls=[ + ft.Container( + padding=ft.Padding.symmetric(horizontal=8, vertical=4), + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=12, + content=ft.Text(state.name, size=11), + ) + for state in ft.AppLifecycleState + ], + ), + ft.Container( + width=720, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=log, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/app_lifecycle_state/showcase/pyproject.toml b/sdk/python/examples/controls/types/app_lifecycle_state/showcase/pyproject.toml new file mode 100644 index 0000000000..8c0cf98a29 --- /dev/null +++ b/sdk/python/examples/controls/types/app_lifecycle_state/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-app-lifecycle-state-showcase" +version = "1.0.0" +description = "Compares App Lifecycle State values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["app lifecycle state", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "App Lifecycle State showcase" +controls = ["SafeArea", "Column", "Page", "Text", "AppBar", "Row", "Container"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/assertiveness/showcase.py b/sdk/python/examples/controls/types/assertiveness/showcase/main.py similarity index 66% rename from sdk/python/examples/controls/types/assertiveness/showcase.py rename to sdk/python/examples/controls/types/assertiveness/showcase/main.py index 92c921e96e..d1aeaa04aa 100644 --- a/sdk/python/examples/controls/types/assertiveness/showcase.py +++ b/sdk/python/examples/controls/types/assertiveness/showcase/main.py @@ -46,21 +46,29 @@ async def announce(): page.appbar = ft.AppBar(title="Assertiveness Showcase") page.add( - ft.Text( - "Compare announcement assertiveness levels. " - "Enable a screen reader to hear the difference." - ), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(assertiveness) for assertiveness in ft.Assertiveness - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare announcement assertiveness levels. " + "Enable a screen reader to hear the difference." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(assertiveness) + for assertiveness in ft.Assertiveness + ], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/assertiveness/showcase/pyproject.toml b/sdk/python/examples/controls/types/assertiveness/showcase/pyproject.toml new file mode 100644 index 0000000000..a49eaf7e2d --- /dev/null +++ b/sdk/python/examples/controls/types/assertiveness/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-assertiveness-showcase" +version = "1.0.0" +description = "Compares Assertiveness values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["assertiveness", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Assertiveness showcase" +controls = ["SafeArea", "Column", "Page", "SemanticsService", "Container", "Text", "Button", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/axis/showcase.py b/sdk/python/examples/controls/types/axis/showcase/main.py similarity index 64% rename from sdk/python/examples/controls/types/axis/showcase.py rename to sdk/python/examples/controls/types/axis/showcase/main.py index fda6502f09..16f7cb0cd2 100644 --- a/sdk/python/examples/controls/types/axis/showcase.py +++ b/sdk/python/examples/controls/types/axis/showcase/main.py @@ -32,16 +32,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="Axis Showcase") page.add( - ft.Text("Compare horizontal vs vertical segment layout."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(axis) for axis in ft.Axis], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare horizontal vs vertical segment layout."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(axis) for axis in ft.Axis], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/axis/showcase/pyproject.toml b/sdk/python/examples/controls/types/axis/showcase/pyproject.toml new file mode 100644 index 0000000000..edaeeff750 --- /dev/null +++ b/sdk/python/examples/controls/types/axis/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-axis-showcase" +version = "1.0.0" +description = "Compares Axis values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["axis", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Axis showcase" +controls = ["SafeArea", "Column", "Container", "Text", "SegmentedButton", "Segment", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/blend_mode/showcase.py b/sdk/python/examples/controls/types/blend_mode/showcase/main.py similarity index 58% rename from sdk/python/examples/controls/types/blend_mode/showcase.py rename to sdk/python/examples/controls/types/blend_mode/showcase/main.py index 1b7a33f838..233bb45fd0 100644 --- a/sdk/python/examples/controls/types/blend_mode/showcase.py +++ b/sdk/python/examples/controls/types/blend_mode/showcase/main.py @@ -31,16 +31,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="BlendMode Showcase") page.add( - ft.Text("Compare color blending results for each BlendMode value."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(blend_mode) for blend_mode in ft.BlendMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare color blending results for each BlendMode value."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(blend_mode) for blend_mode in ft.BlendMode + ], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/blend_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/blend_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..21446b3b29 --- /dev/null +++ b/sdk/python/examples/controls/types/blend_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-blend-mode-showcase" +version = "1.0.0" +description = "Compares Blend Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["blend mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Blend Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Image", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/blur/container.py b/sdk/python/examples/controls/types/blur/container.py deleted file mode 100644 index b2ea37d6a3..0000000000 --- a/sdk/python/examples/controls/types/blur/container.py +++ /dev/null @@ -1,61 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - i = 1 - - img_container = ft.Container( - image=ft.DecorationImage(src="https://picsum.photos/300/300"), - width=300, - height=300, - ) - - def handle_button_click(e: ft.Event[ft.Button]): - nonlocal i - img_container.image = ft.DecorationImage( - src=f"https://picsum.photos/300/300?random={i}" - ) - i += 1 - page.update() - - page.add( - ft.Stack( - controls=[ - img_container, - ft.Container( - width=100, - height=100, - blur=10, - bgcolor="#22CCCC00", - ), - ft.Container( - width=100, - height=100, - left=20, - top=120, - blur=(0, 10), - ), - ft.Container( - top=50, - right=10, - blur=ft.Blur(10, 0, ft.BlurTileMode.MIRROR), - width=100, - height=100, - bgcolor="#44CCCCCC", - border_radius=10, - border=ft.Border.all(2, ft.Colors.BLACK), - ), - ft.Button( - content="Change Background", - bottom=5, - right=5, - # style=ft.ButtonStyle(text_style=ft.TextStyle(size=8)), - on_click=handle_button_click, - ), - ] - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/blur/container/main.py b/sdk/python/examples/controls/types/blur/container/main.py new file mode 100644 index 0000000000..dbb97a746f --- /dev/null +++ b/sdk/python/examples/controls/types/blur/container/main.py @@ -0,0 +1,68 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + i = 1 + + img_container = ft.Container( + image=ft.DecorationImage(src="https://picsum.photos/300/300"), + width=300, + height=300, + ) + + def handle_button_click(e: ft.Event[ft.Button]): + nonlocal i + img_container.image = ft.DecorationImage( + src=f"https://picsum.photos/300/300?random={i}" + ) + i += 1 + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Stack( + controls=[ + img_container, + ft.Container( + width=100, + height=100, + blur=10, + bgcolor="#22CCCC00", + ), + ft.Container( + width=100, + height=100, + left=20, + top=120, + blur=(0, 10), + ), + ft.Container( + top=50, + right=10, + blur=ft.Blur(10, 0, ft.BlurTileMode.MIRROR), + width=100, + height=100, + bgcolor="#44CCCCCC", + border_radius=10, + border=ft.Border.all(2, ft.Colors.BLACK), + ), + ft.Button( + content="Change Background", + bottom=5, + right=5, + # style=ft.ButtonStyle(text_style=ft.TextStyle(size=8)), + on_click=handle_button_click, + ), + ] + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/blur/container/pyproject.toml b/sdk/python/examples/controls/types/blur/container/pyproject.toml new file mode 100644 index 0000000000..6b2b3aa4b7 --- /dev/null +++ b/sdk/python/examples/controls/types/blur/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-blur-container" +version = "1.0.0" +description = "Demonstrates how Blur values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["blur", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Blur" +controls = ["SafeArea", "Column", "Page", "Container", "Button", "Stack", "ButtonStyle"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["blur preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/blur_style/showcase.py b/sdk/python/examples/controls/types/blur_style/showcase/main.py similarity index 59% rename from sdk/python/examples/controls/types/blur_style/showcase.py rename to sdk/python/examples/controls/types/blur_style/showcase/main.py index 15e61f8820..70efd25917 100644 --- a/sdk/python/examples/controls/types/blur_style/showcase.py +++ b/sdk/python/examples/controls/types/blur_style/showcase/main.py @@ -39,19 +39,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="BlurStyle Showcase") page.add( - ft.Text( - "Compare shadow blur rendering styles. " - "The blue box uses red shadow with selected blur style." - ), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(style) for style in ft.BlurStyle], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare shadow blur rendering styles. " + "The blue box uses red shadow with selected blur style." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(style) for style in ft.BlurStyle], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/blur_style/showcase/pyproject.toml b/sdk/python/examples/controls/types/blur_style/showcase/pyproject.toml new file mode 100644 index 0000000000..5a22be6753 --- /dev/null +++ b/sdk/python/examples/controls/types/blur_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-blur-style-showcase" +version = "1.0.0" +description = "Compares Blur Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["blur style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Blur Style showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/blur_tile_mode/showcase.py b/sdk/python/examples/controls/types/blur_tile_mode/showcase/main.py similarity index 75% rename from sdk/python/examples/controls/types/blur_tile_mode/showcase.py rename to sdk/python/examples/controls/types/blur_tile_mode/showcase/main.py index e92665761f..1cbce512d1 100644 --- a/sdk/python/examples/controls/types/blur_tile_mode/showcase.py +++ b/sdk/python/examples/controls/types/blur_tile_mode/showcase/main.py @@ -67,16 +67,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="BlurTileMode Showcase") page.add( - ft.Text("Compare blur edge sampling outside source bounds."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(mode) for mode in ft.BlurTileMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare blur edge sampling outside source bounds."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(mode) for mode in ft.BlurTileMode], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/blur_tile_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/blur_tile_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..56c78a1c12 --- /dev/null +++ b/sdk/python/examples/controls/types/blur_tile_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-blur-tile-mode-showcase" +version = "1.0.0" +description = "Compares Blur Tile Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["blur tile mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Blur Tile Mode showcase" +controls = ["SafeArea", "Column", "Row", "Container", "Stack", "Text", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/border/container.py b/sdk/python/examples/controls/types/border/container.py deleted file mode 100644 index a8cc860faa..0000000000 --- a/sdk/python/examples/controls/types/border/container.py +++ /dev/null @@ -1,40 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Containers with different borders" - - page.add( - ft.Row( - controls=[ - ft.Container( - bgcolor=ft.Colors.AMBER, - padding=15, - border=ft.Border.all(10, ft.Colors.PINK_600), - border_radius=ft.border_radius.all(30), - width=150, - height=150, - ), - ft.Container( - bgcolor=ft.Colors.DEEP_PURPLE, - padding=15, - border=ft.Border.all(3, ft.Colors.LIGHT_GREEN_ACCENT), - border_radius=ft.border_radius.only(top_left=10, bottom_right=10), - width=150, - height=150, - ), - ft.Container( - bgcolor=ft.Colors.BLUE_GREY_900, - padding=15, - border=ft.Border.symmetric( - vertical=ft.BorderSide(8, ft.Colors.YELLOW_800) - ), - width=150, - height=150, - ), - ] - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/border/container/main.py b/sdk/python/examples/controls/types/border/container/main.py new file mode 100644 index 0000000000..364dbd21eb --- /dev/null +++ b/sdk/python/examples/controls/types/border/container/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Containers with different borders" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Container( + bgcolor=ft.Colors.AMBER, + padding=15, + border=ft.Border.all(10, ft.Colors.PINK_600), + border_radius=ft.border_radius.all(30), + width=150, + height=150, + ), + ft.Container( + bgcolor=ft.Colors.DEEP_PURPLE, + padding=15, + border=ft.Border.all(3, ft.Colors.LIGHT_GREEN_ACCENT), + border_radius=ft.border_radius.only( + top_left=10, bottom_right=10 + ), + width=150, + height=150, + ), + ft.Container( + bgcolor=ft.Colors.BLUE_GREY_900, + padding=15, + border=ft.Border.symmetric( + vertical=ft.BorderSide(8, ft.Colors.YELLOW_800) + ), + width=150, + height=150, + ), + ] + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/border/container/pyproject.toml b/sdk/python/examples/controls/types/border/container/pyproject.toml new file mode 100644 index 0000000000..c0ec73a8f7 --- /dev/null +++ b/sdk/python/examples/controls/types/border/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-border-container" +version = "1.0.0" +description = "Demonstrates how Border values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["border", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Border" +controls = ["SafeArea", "Column", "Page", "Row", "Container"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["border preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/border_side_stroke_align/showcase.py b/sdk/python/examples/controls/types/border_side_stroke_align/showcase/main.py similarity index 67% rename from sdk/python/examples/controls/types/border_side_stroke_align/showcase.py rename to sdk/python/examples/controls/types/border_side_stroke_align/showcase/main.py index a233c24569..8c832d3b77 100644 --- a/sdk/python/examples/controls/types/border_side_stroke_align/showcase.py +++ b/sdk/python/examples/controls/types/border_side_stroke_align/showcase/main.py @@ -53,16 +53,28 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="BorderSideStrokeAlign Showcase") page.add( - ft.Text("Compare how thick borders are painted relative to the shape path."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(align) for align in ft.BorderSideStrokeAlign], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how thick borders are painted relative to " + "the shape path." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(align) for align in ft.BorderSideStrokeAlign + ], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/border_side_stroke_align/showcase/pyproject.toml b/sdk/python/examples/controls/types/border_side_stroke_align/showcase/pyproject.toml new file mode 100644 index 0000000000..3fd5b5b17b --- /dev/null +++ b/sdk/python/examples/controls/types/border_side_stroke_align/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-border-side-stroke-align-showcase" +version = "1.0.0" +description = "Compares Border Side Stroke Align values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["border side stroke align", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Border Side Stroke Align showcase" +controls = ["SafeArea", "Column", "BorderSideStrokeAlign", "Container", "Stack", "Text", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/border_style/showcase.py b/sdk/python/examples/controls/types/border_style/showcase/main.py similarity index 62% rename from sdk/python/examples/controls/types/border_style/showcase.py rename to sdk/python/examples/controls/types/border_style/showcase/main.py index 7f2f27f73c..65e973d67f 100644 --- a/sdk/python/examples/controls/types/border_style/showcase.py +++ b/sdk/python/examples/controls/types/border_style/showcase/main.py @@ -34,16 +34,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="BorderStyle Showcase") page.add( - ft.Text("Compare rendered border sides for each BorderStyle value."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(style) for style in ft.BorderStyle], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare rendered border sides for each BorderStyle value." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(style) for style in ft.BorderStyle], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/border_style/showcase/pyproject.toml b/sdk/python/examples/controls/types/border_style/showcase/pyproject.toml new file mode 100644 index 0000000000..b455c82b18 --- /dev/null +++ b/sdk/python/examples/controls/types/border_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-border-style-showcase" +version = "1.0.0" +description = "Compares Border Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["border style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Border Style showcase" +controls = ["SafeArea", "Column", "BorderStyle", "Container", "Text", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/box_fit/showcase.py b/sdk/python/examples/controls/types/box_fit/showcase/main.py similarity index 63% rename from sdk/python/examples/controls/types/box_fit/showcase.py rename to sdk/python/examples/controls/types/box_fit/showcase/main.py index 7bc772f7c6..f471940b63 100644 --- a/sdk/python/examples/controls/types/box_fit/showcase.py +++ b/sdk/python/examples/controls/types/box_fit/showcase/main.py @@ -36,16 +36,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="BoxFit Showcase") page.add( - ft.Text("Compare how the same image is inscribed into a fixed frame."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(fit) for fit in ft.BoxFit], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how the same image is inscribed into a fixed frame." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(fit) for fit in ft.BoxFit], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/box_fit/showcase/pyproject.toml b/sdk/python/examples/controls/types/box_fit/showcase/pyproject.toml new file mode 100644 index 0000000000..46a276254f --- /dev/null +++ b/sdk/python/examples/controls/types/box_fit/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-box-fit-showcase" +version = "1.0.0" +description = "Compares Box Fit values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["box fit", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Box Fit showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Image", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/box_shadow/container.py b/sdk/python/examples/controls/types/box_shadow/container.py deleted file mode 100644 index eb44b9fc18..0000000000 --- a/sdk/python/examples/controls/types/box_shadow/container.py +++ /dev/null @@ -1,42 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Container( - bgcolor=ft.Colors.YELLOW, - width=100, - height=100, - border_radius=50, - shadow=[ - ft.BoxShadow( - spread_radius=1, - blur_radius=15, - color=ft.Colors.WHITE, - offset=ft.Offset(-5, -5), - ), - ft.BoxShadow( - spread_radius=1, - blur_radius=15, - color=ft.Colors.GREY_600, - offset=ft.Offset(5, 5), - ), - ], - ), - ft.Container( - # bgcolor=ft.Colors.WHITE, - border_radius=10, - width=100, - height=100, - shadow=ft.BoxShadow( - spread_radius=1, - blur_radius=15, - color=ft.Colors.BLUE_GREY_300, - offset=ft.Offset(0, 0), - blur_style=ft.BlurStyle.OUTER, - ), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/box_shadow/container/main.py b/sdk/python/examples/controls/types/box_shadow/container/main.py new file mode 100644 index 0000000000..5f96f16579 --- /dev/null +++ b/sdk/python/examples/controls/types/box_shadow/container/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + bgcolor=ft.Colors.YELLOW, + width=100, + height=100, + border_radius=50, + shadow=[ + ft.BoxShadow( + spread_radius=1, + blur_radius=15, + color=ft.Colors.WHITE, + offset=ft.Offset(-5, -5), + ), + ft.BoxShadow( + spread_radius=1, + blur_radius=15, + color=ft.Colors.GREY_600, + offset=ft.Offset(5, 5), + ), + ], + ), + ft.Container( + # bgcolor=ft.Colors.WHITE, + border_radius=10, + width=100, + height=100, + shadow=ft.BoxShadow( + spread_radius=1, + blur_radius=15, + color=ft.Colors.BLUE_GREY_300, + offset=ft.Offset(0, 0), + blur_style=ft.BlurStyle.OUTER, + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/box_shadow/container/pyproject.toml b/sdk/python/examples/controls/types/box_shadow/container/pyproject.toml new file mode 100644 index 0000000000..99f780214d --- /dev/null +++ b/sdk/python/examples/controls/types/box_shadow/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-box-shadow-container" +version = "1.0.0" +description = "Demonstrates how Box Shadow values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["box shadow", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Box Shadow" +controls = ["SafeArea", "Column", "Page", "Container"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["box shadow preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/box_shape/showcase.py b/sdk/python/examples/controls/types/box_shape/showcase/main.py similarity index 73% rename from sdk/python/examples/controls/types/box_shape/showcase.py rename to sdk/python/examples/controls/types/box_shape/showcase/main.py index 3ba603d176..07a86207c3 100644 --- a/sdk/python/examples/controls/types/box_shape/showcase.py +++ b/sdk/python/examples/controls/types/box_shape/showcase/main.py @@ -48,16 +48,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="BoxShape Showcase") page.add( - ft.Text("Compare rectangular and circular box decoration shapes."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(shape) for shape in ft.BoxShape], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare rectangular and circular box decoration shapes."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(shape) for shape in ft.BoxShape], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/box_shape/showcase/pyproject.toml b/sdk/python/examples/controls/types/box_shape/showcase/pyproject.toml new file mode 100644 index 0000000000..e90da7bae5 --- /dev/null +++ b/sdk/python/examples/controls/types/box_shape/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-box-shape-showcase" +version = "1.0.0" +description = "Compares Box Shape values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["box shape", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Box Shape showcase" +controls = ["SafeArea", "Column", "Container", "Text", "BorderRadius", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/card_variant/showcase.py b/sdk/python/examples/controls/types/card_variant/showcase/main.py similarity index 65% rename from sdk/python/examples/controls/types/card_variant/showcase.py rename to sdk/python/examples/controls/types/card_variant/showcase/main.py index 2da8c2c270..9f167c1328 100644 --- a/sdk/python/examples/controls/types/card_variant/showcase.py +++ b/sdk/python/examples/controls/types/card_variant/showcase/main.py @@ -41,16 +41,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="CardVariant Showcase") page.add( - ft.Text("Compare Material card visual variants."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(variant) for variant in ft.CardVariant], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare Material card visual variants."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(variant) for variant in ft.CardVariant], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/card_variant/showcase/pyproject.toml b/sdk/python/examples/controls/types/card_variant/showcase/pyproject.toml new file mode 100644 index 0000000000..de76ead71d --- /dev/null +++ b/sdk/python/examples/controls/types/card_variant/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-card-variant-showcase" +version = "1.0.0" +description = "Compares Card Variant values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["card variant", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Card Variant showcase" +controls = ["SafeArea", "Column", "Container", "Card", "Text", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/clip_behavior/showcase.py b/sdk/python/examples/controls/types/clip_behavior/showcase/main.py similarity index 74% rename from sdk/python/examples/controls/types/clip_behavior/showcase.py rename to sdk/python/examples/controls/types/clip_behavior/showcase/main.py index 19d7373174..6494919a06 100644 --- a/sdk/python/examples/controls/types/clip_behavior/showcase.py +++ b/sdk/python/examples/controls/types/clip_behavior/showcase/main.py @@ -64,16 +64,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="ClipBehavior Showcase") page.add( - ft.Text("Compare how overflow is clipped for each ClipBehavior value."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(cb) for cb in ft.ClipBehavior], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how overflow is clipped for each ClipBehavior value." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(cb) for cb in ft.ClipBehavior], + ), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/clip_behavior/showcase/pyproject.toml b/sdk/python/examples/controls/types/clip_behavior/showcase/pyproject.toml new file mode 100644 index 0000000000..97fcf2a8f1 --- /dev/null +++ b/sdk/python/examples/controls/types/clip_behavior/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-clip-behavior-showcase" +version = "1.0.0" +description = "Compares Clip Behavior values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["clip behavior", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Clip Behavior showcase" +controls = ["SafeArea", "Column", "Container", "Stack", "Icon", "Text", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/context/disable_auto_update.py b/sdk/python/examples/controls/types/context/disable_auto_update/main.py similarity index 62% rename from sdk/python/examples/controls/types/context/disable_auto_update.py rename to sdk/python/examples/controls/types/context/disable_auto_update/main.py index 171892877e..38e4b09ad2 100644 --- a/sdk/python/examples/controls/types/context/disable_auto_update.py +++ b/sdk/python/examples/controls/types/context/disable_auto_update/main.py @@ -11,8 +11,15 @@ def button_click(): page.controls.append(ft.Text("This won't appear")) # no page.update() will be called here - page.controls.append(b := ft.Button("Action!", on_click=button_click)) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[b := ft.Button("Action!", on_click=button_click)] + ) + ) + ) # page.update() - auto-update is enabled by default -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/context/disable_auto_update/pyproject.toml b/sdk/python/examples/controls/types/context/disable_auto_update/pyproject.toml new file mode 100644 index 0000000000..81793bc37a --- /dev/null +++ b/sdk/python/examples/controls/types/context/disable_auto_update/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-context-disable-auto-update" +version = "1.0.0" +description = "Shows how disabling automatic updates requires explicit control refreshes." +requires-python = ">=3.10" +keywords = ["context", "disable auto update"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types"] + +[tool.flet.metadata] +title = "Disable auto update" +controls = ["SafeArea", "Column", "Page", "Text", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["manual updates", "context access"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/context/get_page.py b/sdk/python/examples/controls/types/context/get_page.py deleted file mode 100644 index 39d5d8331f..0000000000 --- a/sdk/python/examples/controls/types/context/get_page.py +++ /dev/null @@ -1,11 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def button_click(e): - print("Page width:", ft.context.page.width) - - page.add(ft.Button("Get page width", on_click=button_click)) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/context/get_page/main.py b/sdk/python/examples/controls/types/context/get_page/main.py new file mode 100644 index 0000000000..092e600c82 --- /dev/null +++ b/sdk/python/examples/controls/types/context/get_page/main.py @@ -0,0 +1,18 @@ +import flet as ft + + +def main(page: ft.Page): + def button_click(e): + print("Page width:", ft.context.page.width) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Button("Get page width", on_click=button_click)] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/context/get_page/pyproject.toml b/sdk/python/examples/controls/types/context/get_page/pyproject.toml new file mode 100644 index 0000000000..2e4fb7a761 --- /dev/null +++ b/sdk/python/examples/controls/types/context/get_page/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-context-get-page" +version = "1.0.0" +description = "Reads the current page from ft.context inside an event handler." +requires-python = ">=3.10" +keywords = ["context", "get page"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types"] + +[tool.flet.metadata] +title = "Get page from context" +controls = ["SafeArea", "Column", "Page", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["context access", "event handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/context_menu_trigger/showcase.py b/sdk/python/examples/controls/types/context_menu_trigger/showcase/main.py similarity index 74% rename from sdk/python/examples/controls/types/context_menu_trigger/showcase.py rename to sdk/python/examples/controls/types/context_menu_trigger/showcase/main.py index c60db87f7a..39203d11b4 100644 --- a/sdk/python/examples/controls/types/context_menu_trigger/showcase.py +++ b/sdk/python/examples/controls/types/context_menu_trigger/showcase/main.py @@ -64,16 +64,27 @@ async def main(page: ft.Page): page.appbar = ft.AppBar(title="ContextMenuTrigger Showcase") page.add( - ft.Text("Compare context-menu open behavior for primary trigger modes."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(trigger) for trigger in ft.ContextMenuTrigger], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare context-menu open behavior for primary trigger modes." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(trigger) for trigger in ft.ContextMenuTrigger + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/context_menu_trigger/showcase/pyproject.toml b/sdk/python/examples/controls/types/context_menu_trigger/showcase/pyproject.toml new file mode 100644 index 0000000000..e45759a38c --- /dev/null +++ b/sdk/python/examples/controls/types/context_menu_trigger/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-context-menu-trigger-showcase" +version = "1.0.0" +description = "Compares Context Menu Trigger values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["context menu trigger", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Context Menu Trigger showcase" +controls = ["SafeArea", "Column", "Container", "ContextMenu", "PopupMenuItem", "Text", "BrowserContextMenu", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/cross_axis_alignment/showcase.py b/sdk/python/examples/controls/types/cross_axis_alignment/showcase/main.py similarity index 76% rename from sdk/python/examples/controls/types/cross_axis_alignment/showcase.py rename to sdk/python/examples/controls/types/cross_axis_alignment/showcase/main.py index 5126081a8d..34986862a2 100644 --- a/sdk/python/examples/controls/types/cross_axis_alignment/showcase.py +++ b/sdk/python/examples/controls/types/cross_axis_alignment/showcase/main.py @@ -75,16 +75,29 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="CrossAxisAlignment Showcase") page.add( - ft.Text("Compare vertical alignment behavior inside the same row height."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(alignment) for alignment in ft.CrossAxisAlignment], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare vertical alignment behavior inside the same " + "row height." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(alignment) + for alignment in ft.CrossAxisAlignment + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/cross_axis_alignment/showcase/pyproject.toml b/sdk/python/examples/controls/types/cross_axis_alignment/showcase/pyproject.toml new file mode 100644 index 0000000000..7c67354a36 --- /dev/null +++ b/sdk/python/examples/controls/types/cross_axis_alignment/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cross-axis-alignment-showcase" +version = "1.0.0" +description = "Compares Cross Axis Alignment values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cross axis alignment", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Cross Axis Alignment showcase" +controls = ["SafeArea", "Column", "Container", "Row", "Text", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/cupertino_button_size/showcase.py b/sdk/python/examples/controls/types/cupertino_button_size/showcase/main.py similarity index 59% rename from sdk/python/examples/controls/types/cupertino_button_size/showcase.py rename to sdk/python/examples/controls/types/cupertino_button_size/showcase/main.py index 20b05de1c5..8313c3e541 100644 --- a/sdk/python/examples/controls/types/cupertino_button_size/showcase.py +++ b/sdk/python/examples/controls/types/cupertino_button_size/showcase/main.py @@ -30,16 +30,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="CupertinoButtonSize Showcase") page.add( - ft.Text("Compare iOS button size presets."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(size) for size in ft.CupertinoButtonSize], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare iOS button size presets."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(size) for size in ft.CupertinoButtonSize + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/cupertino_button_size/showcase/pyproject.toml b/sdk/python/examples/controls/types/cupertino_button_size/showcase/pyproject.toml new file mode 100644 index 0000000000..a188a4b0d0 --- /dev/null +++ b/sdk/python/examples/controls/types/cupertino_button_size/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cupertino-button-size-showcase" +version = "1.0.0" +description = "Compares Cupertino Button Size values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cupertino button size", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Cupertino Button Size showcase" +controls = ["SafeArea", "Column", "Container", "Text", "CupertinoButton", "CupertinoIcons", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase.py b/sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase/main.py similarity index 66% rename from sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase.py rename to sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase/main.py index ce0f1c575d..96b6619de6 100644 --- a/sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase.py +++ b/sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase/main.py @@ -42,19 +42,26 @@ def open_picker(_): page.appbar = ft.AppBar(title="CupertinoDatePickerDateOrder Showcase") page.add( - ft.Text("Open each variant in CupertinoBottomSheet."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(date_order) - for date_order in ft.CupertinoDatePickerDateOrder - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Open each variant in CupertinoBottomSheet."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(date_order) + for date_order in ft.CupertinoDatePickerDateOrder + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase/pyproject.toml b/sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase/pyproject.toml new file mode 100644 index 0000000000..6ddc495dee --- /dev/null +++ b/sdk/python/examples/controls/types/cupertino_date_picker_date_order/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cupertino-date-picker-date-order-showcase" +version = "1.0.0" +description = "Compares Cupertino Date Picker Date Order values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cupertino date picker date order", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Cupertino Date Picker Date Order showcase" +controls = ["SafeArea", "Column", "Container", "CupertinoDatePicker", "CupertinoBottomSheet", "Text", "Button", "CupertinoIcons"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase.py b/sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase/main.py similarity index 64% rename from sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase.py rename to sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase/main.py index abb3824722..9df0fffb59 100644 --- a/sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase.py +++ b/sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase/main.py @@ -42,16 +42,27 @@ def open_picker(_): page.appbar = ft.AppBar(title="CupertinoDatePickerMode Showcase") page.add( - ft.Text("Open each mode in CupertinoBottomSheet to compare behavior."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(mode) for mode in ft.CupertinoDatePickerMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Open each mode in CupertinoBottomSheet to compare behavior." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(mode) for mode in ft.CupertinoDatePickerMode + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..5a7430ea0f --- /dev/null +++ b/sdk/python/examples/controls/types/cupertino_date_picker_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cupertino-date-picker-mode-showcase" +version = "1.0.0" +description = "Compares Cupertino Date Picker Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cupertino date picker mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Cupertino Date Picker Mode showcase" +controls = ["SafeArea", "Column", "Container", "CupertinoDatePicker", "CupertinoBottomSheet", "Text", "Button", "CupertinoIcons"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase.py b/sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase/main.py similarity index 54% rename from sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase.py rename to sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase/main.py index 70d9d71519..570a06b79b 100644 --- a/sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase.py +++ b/sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase/main.py @@ -26,16 +26,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="CupertinoTimerPickerMode Showcase") page.add( - ft.Text("Compare timer picker layouts."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(mode) for mode in ft.CupertinoTimerPickerMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare timer picker layouts."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(mode) for mode in ft.CupertinoTimerPickerMode + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..f0a01dd84d --- /dev/null +++ b/sdk/python/examples/controls/types/cupertino_timer_picker_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cupertino-timer-picker-mode-showcase" +version = "1.0.0" +description = "Compares Cupertino Timer Picker Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cupertino timer picker mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Cupertino Timer Picker Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "CupertinoTimerPicker", "Duration", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/date_picker_entry_mode/showcase.py b/sdk/python/examples/controls/types/date_picker_entry_mode/showcase/main.py similarity index 66% rename from sdk/python/examples/controls/types/date_picker_entry_mode/showcase.py rename to sdk/python/examples/controls/types/date_picker_entry_mode/showcase/main.py index e29813d6c3..96213f1327 100644 --- a/sdk/python/examples/controls/types/date_picker_entry_mode/showcase.py +++ b/sdk/python/examples/controls/types/date_picker_entry_mode/showcase/main.py @@ -39,16 +39,25 @@ def showcase_card(entry_mode: ft.DatePickerEntryMode) -> ft.Container: page.appbar = ft.AppBar(title="DatePickerEntryMode Showcase") page.add( - ft.Text("Open the picker to compare calendar and input entry modes."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(m) for m in ft.DatePickerEntryMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Open the picker to compare calendar and input entry modes." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(m) for m in ft.DatePickerEntryMode], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/date_picker_entry_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/date_picker_entry_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..0b5e787b43 --- /dev/null +++ b/sdk/python/examples/controls/types/date_picker_entry_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-date-picker-entry-mode-showcase" +version = "1.0.0" +description = "Compares Date Picker Entry Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["date picker entry mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Date Picker Entry Mode showcase" +controls = ["SafeArea", "Column", "DatePicker", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/date_picker_mode/showcase.py b/sdk/python/examples/controls/types/date_picker_mode/showcase/main.py similarity index 67% rename from sdk/python/examples/controls/types/date_picker_mode/showcase.py rename to sdk/python/examples/controls/types/date_picker_mode/showcase/main.py index 108b1ac274..48a991503b 100644 --- a/sdk/python/examples/controls/types/date_picker_mode/showcase.py +++ b/sdk/python/examples/controls/types/date_picker_mode/showcase/main.py @@ -39,16 +39,25 @@ def showcase_card(date_picker_mode: ft.DatePickerMode) -> ft.Container: page.appbar = ft.AppBar(title="DatePickerMode Showcase") page.add( - ft.Text("Open the picker to compare initial day vs year display mode."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(m) for m in ft.DatePickerMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Open the picker to compare initial day vs year display mode." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(m) for m in ft.DatePickerMode], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/date_picker_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/date_picker_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..05b4f2f387 --- /dev/null +++ b/sdk/python/examples/controls/types/date_picker_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-date-picker-mode-showcase" +version = "1.0.0" +description = "Compares Date Picker Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["date picker mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Date Picker Mode showcase" +controls = ["SafeArea", "Column", "DatePicker", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/dismiss_direction/showcase.py b/sdk/python/examples/controls/types/dismiss_direction/showcase/main.py similarity index 77% rename from sdk/python/examples/controls/types/dismiss_direction/showcase.py rename to sdk/python/examples/controls/types/dismiss_direction/showcase/main.py index 8d31d62adb..c04aed797c 100644 --- a/sdk/python/examples/controls/types/dismiss_direction/showcase.py +++ b/sdk/python/examples/controls/types/dismiss_direction/showcase/main.py @@ -74,16 +74,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="DismissDirection Showcase") page.add( - ft.Text("Try swipe directions to see which ones are allowed."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(direction) for direction in ft.DismissDirection], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Try swipe directions to see which ones are allowed."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(direction) + for direction in ft.DismissDirection + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/dismiss_direction/showcase/pyproject.toml b/sdk/python/examples/controls/types/dismiss_direction/showcase/pyproject.toml new file mode 100644 index 0000000000..a80ee93ad7 --- /dev/null +++ b/sdk/python/examples/controls/types/dismiss_direction/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-dismiss-direction-showcase" +version = "1.0.0" +description = "Compares Dismiss Direction values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["dismiss direction", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Dismiss Direction showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Dismissible", "Icon", "Button", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/filter_quality/showcase.py b/sdk/python/examples/controls/types/filter_quality/showcase/main.py similarity index 62% rename from sdk/python/examples/controls/types/filter_quality/showcase.py rename to sdk/python/examples/controls/types/filter_quality/showcase/main.py index 126d7e9492..71b37e7189 100644 --- a/sdk/python/examples/controls/types/filter_quality/showcase.py +++ b/sdk/python/examples/controls/types/filter_quality/showcase/main.py @@ -39,16 +39,28 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="FilterQuality Showcase") page.add( - ft.Text("Compare image sampling quality while scaling the same source image."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(quality) for quality in ft.FilterQuality], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare image sampling quality while scaling the " + "same source image." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(quality) for quality in ft.FilterQuality + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/filter_quality/showcase/pyproject.toml b/sdk/python/examples/controls/types/filter_quality/showcase/pyproject.toml new file mode 100644 index 0000000000..3d0cef4a9e --- /dev/null +++ b/sdk/python/examples/controls/types/filter_quality/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-filter-quality-showcase" +version = "1.0.0" +description = "Compares Filter Quality values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["filter quality", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Filter Quality showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Image", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/floating_action_button_location/showcase.py b/sdk/python/examples/controls/types/floating_action_button_location/showcase/main.py similarity index 71% rename from sdk/python/examples/controls/types/floating_action_button_location/showcase.py rename to sdk/python/examples/controls/types/floating_action_button_location/showcase/main.py index 9d3225e7dc..c762d3264c 100644 --- a/sdk/python/examples/controls/types/floating_action_button_location/showcase.py +++ b/sdk/python/examples/controls/types/floating_action_button_location/showcase/main.py @@ -48,18 +48,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="FloatingActionButtonLocation Showcase") page.add( - ft.Text("Compare FloatingActionButton placement presets."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(location) for location in ft.FloatingActionButtonLocation - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare FloatingActionButton placement presets."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(location) + for location in ft.FloatingActionButtonLocation + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/floating_action_button_location/showcase/pyproject.toml b/sdk/python/examples/controls/types/floating_action_button_location/showcase/pyproject.toml new file mode 100644 index 0000000000..c972d830d5 --- /dev/null +++ b/sdk/python/examples/controls/types/floating_action_button_location/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-floating-action-button-location-showcase" +version = "1.0.0" +description = "Compares Floating Action Button Location values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["floating action button location", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Floating Action Button Location showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Pagelet", "AppBar", "BottomAppBar", "FloatingActionButton"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/font_weight/showcase.py b/sdk/python/examples/controls/types/font_weight/showcase/main.py similarity index 54% rename from sdk/python/examples/controls/types/font_weight/showcase.py rename to sdk/python/examples/controls/types/font_weight/showcase/main.py index 1163ca05ba..daaf4a2203 100644 --- a/sdk/python/examples/controls/types/font_weight/showcase.py +++ b/sdk/python/examples/controls/types/font_weight/showcase/main.py @@ -25,16 +25,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="FontWeight Showcase") page.add( - ft.Text("Compare text thickness across all FontWeight values."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(weight) for weight in ft.FontWeight], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare text thickness across all FontWeight values."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(weight) for weight in ft.FontWeight], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/font_weight/showcase/pyproject.toml b/sdk/python/examples/controls/types/font_weight/showcase/pyproject.toml new file mode 100644 index 0000000000..bf4622eb0f --- /dev/null +++ b/sdk/python/examples/controls/types/font_weight/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-font-weight-showcase" +version = "1.0.0" +description = "Compares Font Weight values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["font weight", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Font Weight showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/gradient/container.py b/sdk/python/examples/controls/types/gradient/container.py deleted file mode 100644 index deb3a4fc82..0000000000 --- a/sdk/python/examples/controls/types/gradient/container.py +++ /dev/null @@ -1,95 +0,0 @@ -import math - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - page.add( - ft.Row( - alignment=ft.MainAxisAlignment.CENTER, - scroll=ft.ScrollMode.AUTO, - controls=[ - ft.Container( - content=ft.Text("Linear gradient"), - padding=10, - alignment=ft.Alignment.CENTER, - width=200, - height=200, - border_radius=10, - gradient=ft.LinearGradient( - begin=ft.Alignment.TOP_LEFT, - end=ft.Alignment(0.8, 1), - tile_mode=ft.GradientTileMode.MIRROR, - rotation=math.pi / 3, - colors=[ - "0xff1f005c", - "0xff5b0060", - "0xff870160", - "0xffac255e", - "0xffca485c", - "0xffe16b5c", - "0xfff39060", - "0xffffb56b", - ], - ), - ), - ft.Container( - content=ft.Text("Linear gradient with stops"), - padding=10, - alignment=ft.Alignment.CENTER, - width=200, - height=200, - border_radius=10, - gradient=ft.LinearGradient( - begin=ft.Alignment.CENTER_LEFT, - end=ft.Alignment.CENTER_RIGHT, - tile_mode=ft.GradientTileMode.MIRROR, - stops=[0.1, 0.2, 1.0], - colors=[ft.Colors.RED, ft.Colors.GREEN, ft.Colors.BLUE], - ), - ), - ft.Container( - content=ft.Text("Radial gradient"), - padding=10, - alignment=ft.Alignment.CENTER, - width=200, - height=200, - border_radius=10, - gradient=ft.RadialGradient( - center=ft.Alignment(0.7, -0.6), - radius=0.2, - stops=[0.4, 1.0], - colors=["0xFFFFFF00", "0xFF0099FF"], - ), - ), - ft.Container( - content=ft.Text("Sweep gradient"), - padding=10, - alignment=ft.Alignment.CENTER, - width=200, - height=200, - border_radius=10, - gradient=ft.SweepGradient( - center=ft.Alignment.CENTER, - start_angle=0.0, - end_angle=math.pi * 2, - rotation=math.pi / 4, - stops=[0.0, 0.25, 0.5, 0.75, 1.0], - colors=[ - "0xFF4285F4", - "0xFF34A853", - "0xFFFBBC05", - "0xFFEA4335", - "0xFF4285F4", - ], - ), - ), - ], - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient/container/main.py b/sdk/python/examples/controls/types/gradient/container/main.py new file mode 100644 index 0000000000..d7414b5231 --- /dev/null +++ b/sdk/python/examples/controls/types/gradient/container/main.py @@ -0,0 +1,106 @@ +import math + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + scroll=ft.ScrollMode.AUTO, + controls=[ + ft.Container( + content=ft.Text("Linear gradient"), + padding=10, + alignment=ft.Alignment.CENTER, + width=200, + height=200, + border_radius=10, + gradient=ft.LinearGradient( + begin=ft.Alignment.TOP_LEFT, + end=ft.Alignment(0.8, 1), + tile_mode=ft.GradientTileMode.MIRROR, + rotation=math.pi / 3, + colors=[ + "0xff1f005c", + "0xff5b0060", + "0xff870160", + "0xffac255e", + "0xffca485c", + "0xffe16b5c", + "0xfff39060", + "0xffffb56b", + ], + ), + ), + ft.Container( + content=ft.Text("Linear gradient with stops"), + padding=10, + alignment=ft.Alignment.CENTER, + width=200, + height=200, + border_radius=10, + gradient=ft.LinearGradient( + begin=ft.Alignment.CENTER_LEFT, + end=ft.Alignment.CENTER_RIGHT, + tile_mode=ft.GradientTileMode.MIRROR, + stops=[0.1, 0.2, 1.0], + colors=[ + ft.Colors.RED, + ft.Colors.GREEN, + ft.Colors.BLUE, + ], + ), + ), + ft.Container( + content=ft.Text("Radial gradient"), + padding=10, + alignment=ft.Alignment.CENTER, + width=200, + height=200, + border_radius=10, + gradient=ft.RadialGradient( + center=ft.Alignment(0.7, -0.6), + radius=0.2, + stops=[0.4, 1.0], + colors=["0xFFFFFF00", "0xFF0099FF"], + ), + ), + ft.Container( + content=ft.Text("Sweep gradient"), + padding=10, + alignment=ft.Alignment.CENTER, + width=200, + height=200, + border_radius=10, + gradient=ft.SweepGradient( + center=ft.Alignment.CENTER, + start_angle=0.0, + end_angle=math.pi * 2, + rotation=math.pi / 4, + stops=[0.0, 0.25, 0.5, 0.75, 1.0], + colors=[ + "0xFF4285F4", + "0xFF34A853", + "0xFFFBBC05", + "0xFFEA4335", + "0xFF4285F4", + ], + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient/container/pyproject.toml b/sdk/python/examples/controls/types/gradient/container/pyproject.toml new file mode 100644 index 0000000000..738ddbc64e --- /dev/null +++ b/sdk/python/examples/controls/types/gradient/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-container" +version = "1.0.0" +description = "Demonstrates how Gradient values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["gradient", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Gradient" +controls = ["SafeArea", "Column", "Row", "Container", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["gradient preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/gradient/linear_gradient/container.py b/sdk/python/examples/controls/types/gradient/linear_gradient/container.py deleted file mode 100644 index e90a2a46e2..0000000000 --- a/sdk/python/examples/controls/types/gradient/linear_gradient/container.py +++ /dev/null @@ -1,33 +0,0 @@ -import math - -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Container( - alignment=ft.Alignment.CENTER, - width=150, - height=150, - border_radius=ft.BorderRadius.all(5), - gradient=ft.LinearGradient( - begin=ft.Alignment.TOP_LEFT, - end=ft.Alignment(0.8, 1), - tile_mode=ft.GradientTileMode.MIRROR, - rotation=math.pi / 3, - colors=[ - "0xff1f005c", - "0xff5b0060", - "0xff870160", - "0xffac255e", - "0xffca485c", - "0xffe16b5c", - "0xfff39060", - "0xffffb56b", - ], - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient/linear_gradient/container/main.py b/sdk/python/examples/controls/types/gradient/linear_gradient/container/main.py new file mode 100644 index 0000000000..faf1aaaf4e --- /dev/null +++ b/sdk/python/examples/controls/types/gradient/linear_gradient/container/main.py @@ -0,0 +1,40 @@ +import math + +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + width=150, + height=150, + border_radius=ft.BorderRadius.all(5), + gradient=ft.LinearGradient( + begin=ft.Alignment.TOP_LEFT, + end=ft.Alignment(0.8, 1), + tile_mode=ft.GradientTileMode.MIRROR, + rotation=math.pi / 3, + colors=[ + "0xff1f005c", + "0xff5b0060", + "0xff870160", + "0xffac255e", + "0xffca485c", + "0xffe16b5c", + "0xfff39060", + "0xffffb56b", + ], + ), + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient/linear_gradient/container/pyproject.toml b/sdk/python/examples/controls/types/gradient/linear_gradient/container/pyproject.toml new file mode 100644 index 0000000000..8105824260 --- /dev/null +++ b/sdk/python/examples/controls/types/gradient/linear_gradient/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-linear-gradient-container" +version = "1.0.0" +description = "Demonstrates how Linear Gradient values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["gradient", "linear gradient", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Linear Gradient" +controls = ["SafeArea", "Column", "Container", "BorderRadius"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["linear gradient preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/gradient/radial_gradient/container.py b/sdk/python/examples/controls/types/gradient/radial_gradient/container.py deleted file mode 100644 index 9412477196..0000000000 --- a/sdk/python/examples/controls/types/gradient/radial_gradient/container.py +++ /dev/null @@ -1,21 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Container( - alignment=ft.Alignment.CENTER, - width=150, - height=150, - border_radius=ft.BorderRadius.all(5), - gradient=ft.RadialGradient( - center=ft.Alignment(0.7, -0.6), - radius=0.2, - colors=["0xFFFFFF00", "0xFF0099FF"], - stops=[0.4, 1.0], - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient/radial_gradient/container/main.py b/sdk/python/examples/controls/types/gradient/radial_gradient/container/main.py new file mode 100644 index 0000000000..3777d923b9 --- /dev/null +++ b/sdk/python/examples/controls/types/gradient/radial_gradient/container/main.py @@ -0,0 +1,28 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + width=150, + height=150, + border_radius=ft.BorderRadius.all(5), + gradient=ft.RadialGradient( + center=ft.Alignment(0.7, -0.6), + radius=0.2, + colors=["0xFFFFFF00", "0xFF0099FF"], + stops=[0.4, 1.0], + ), + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient/radial_gradient/container/pyproject.toml b/sdk/python/examples/controls/types/gradient/radial_gradient/container/pyproject.toml new file mode 100644 index 0000000000..b4b9938c0f --- /dev/null +++ b/sdk/python/examples/controls/types/gradient/radial_gradient/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-radial-gradient-container" +version = "1.0.0" +description = "Demonstrates how Radial Gradient values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["gradient", "radial gradient", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Radial Gradient" +controls = ["SafeArea", "Column", "Container", "BorderRadius"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["radial gradient preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/gradient/sweep_gradient/container.py b/sdk/python/examples/controls/types/gradient/sweep_gradient/container.py deleted file mode 100644 index 6e85fb51f8..0000000000 --- a/sdk/python/examples/controls/types/gradient/sweep_gradient/container.py +++ /dev/null @@ -1,30 +0,0 @@ -import math - -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Container( - alignment=ft.Alignment.CENTER, - width=150, - height=150, - border_radius=ft.BorderRadius.all(5), - gradient=ft.SweepGradient( - center=ft.Alignment.CENTER, - start_angle=0.0, - end_angle=math.pi * 2, - stops=[0.0, 0.25, 0.5, 0.75, 1.0], - colors=[ - "0xFF4285F4", - "0xFF34A853", - "0xFFFBBC05", - "0xFFEA4335", - "0xFF4285F4", - ], - ), - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient/sweep_gradient/container/main.py b/sdk/python/examples/controls/types/gradient/sweep_gradient/container/main.py new file mode 100644 index 0000000000..cdc0b70e86 --- /dev/null +++ b/sdk/python/examples/controls/types/gradient/sweep_gradient/container/main.py @@ -0,0 +1,37 @@ +import math + +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + width=150, + height=150, + border_radius=ft.BorderRadius.all(5), + gradient=ft.SweepGradient( + center=ft.Alignment.CENTER, + start_angle=0.0, + end_angle=math.pi * 2, + stops=[0.0, 0.25, 0.5, 0.75, 1.0], + colors=[ + "0xFF4285F4", + "0xFF34A853", + "0xFFFBBC05", + "0xFFEA4335", + "0xFF4285F4", + ], + ), + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient/sweep_gradient/container/pyproject.toml b/sdk/python/examples/controls/types/gradient/sweep_gradient/container/pyproject.toml new file mode 100644 index 0000000000..2e72b54881 --- /dev/null +++ b/sdk/python/examples/controls/types/gradient/sweep_gradient/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-sweep-gradient-container" +version = "1.0.0" +description = "Demonstrates how Sweep Gradient values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["gradient", "sweep gradient", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Sweep Gradient" +controls = ["SafeArea", "Column", "Container", "BorderRadius"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["sweep gradient preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/gradient_tile_mode/showcase.py b/sdk/python/examples/controls/types/gradient_tile_mode/showcase/main.py similarity index 59% rename from sdk/python/examples/controls/types/gradient_tile_mode/showcase.py rename to sdk/python/examples/controls/types/gradient_tile_mode/showcase/main.py index ce980fe2a8..3ebfd0af4a 100644 --- a/sdk/python/examples/controls/types/gradient_tile_mode/showcase.py +++ b/sdk/python/examples/controls/types/gradient_tile_mode/showcase/main.py @@ -33,16 +33,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="GradientTileMode Showcase") page.add( - ft.Text("Compare how gradients behave outside their defined paint region."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(mode) for mode in ft.GradientTileMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how gradients behave outside their defined " + "paint region." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(mode) for mode in ft.GradientTileMode], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/gradient_tile_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/gradient_tile_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..416906ec13 --- /dev/null +++ b/sdk/python/examples/controls/types/gradient_tile_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-tile-mode-showcase" +version = "1.0.0" +description = "Compares Gradient Tile Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["gradient tile mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Gradient Tile Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/image_repeat/showcase.py b/sdk/python/examples/controls/types/image_repeat/showcase/main.py similarity index 62% rename from sdk/python/examples/controls/types/image_repeat/showcase.py rename to sdk/python/examples/controls/types/image_repeat/showcase/main.py index caeba1548c..c6a57acd17 100644 --- a/sdk/python/examples/controls/types/image_repeat/showcase.py +++ b/sdk/python/examples/controls/types/image_repeat/showcase/main.py @@ -35,16 +35,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="ImageRepeat Showcase") page.add( - ft.Text("Compare how an image fills uncovered space using repeat modes."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(repeat) for repeat in ft.ImageRepeat], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how an image fills uncovered space using repeat modes." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(repeat) for repeat in ft.ImageRepeat], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/image_repeat/showcase/pyproject.toml b/sdk/python/examples/controls/types/image_repeat/showcase/pyproject.toml new file mode 100644 index 0000000000..3a00b03bd0 --- /dev/null +++ b/sdk/python/examples/controls/types/image_repeat/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-image-repeat-showcase" +version = "1.0.0" +description = "Compares Image Repeat values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["image repeat", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Image Repeat showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Image", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/label_position/showcase.py b/sdk/python/examples/controls/types/label_position/showcase/main.py similarity index 66% rename from sdk/python/examples/controls/types/label_position/showcase.py rename to sdk/python/examples/controls/types/label_position/showcase/main.py index 1383f40b30..b8b7ab0f05 100644 --- a/sdk/python/examples/controls/types/label_position/showcase.py +++ b/sdk/python/examples/controls/types/label_position/showcase/main.py @@ -44,18 +44,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="LabelPosition Showcase") page.add( - ft.Text("Compare left/right label placement for form controls."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(label_position) for label_position in ft.LabelPosition - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare left/right label placement for form controls."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(label_position) + for label_position in ft.LabelPosition + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/label_position/showcase/pyproject.toml b/sdk/python/examples/controls/types/label_position/showcase/pyproject.toml new file mode 100644 index 0000000000..653d3cb7eb --- /dev/null +++ b/sdk/python/examples/controls/types/label_position/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-label-position-showcase" +version = "1.0.0" +description = "Compares Label Position values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["label position", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Label Position showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Checkbox", "RadioGroup", "Row", "Radio"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/launch_mode/showcase.py b/sdk/python/examples/controls/types/launch_mode/showcase/main.py similarity index 68% rename from sdk/python/examples/controls/types/launch_mode/showcase.py rename to sdk/python/examples/controls/types/launch_mode/showcase/main.py index d3e3942c29..ac43a8254c 100644 --- a/sdk/python/examples/controls/types/launch_mode/showcase.py +++ b/sdk/python/examples/controls/types/launch_mode/showcase/main.py @@ -41,16 +41,25 @@ async def check_support(): page.appbar = ft.AppBar(title="LaunchMode Showcase") page.add( - ft.Text("Check launch-mode support reported by the current platform."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(mode) for mode in ft.LaunchMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Check launch-mode support reported by the current platform." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(mode) for mode in ft.LaunchMode], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/launch_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/launch_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..5ebbee44c5 --- /dev/null +++ b/sdk/python/examples/controls/types/launch_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-launch-mode-showcase" +version = "1.0.0" +description = "Compares Launch Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["launch mode", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Launch Mode showcase" +controls = ["SafeArea", "Column", "UrlLauncher", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/list_tile_style/showcase.py b/sdk/python/examples/controls/types/list_tile_style/showcase/main.py similarity index 65% rename from sdk/python/examples/controls/types/list_tile_style/showcase.py rename to sdk/python/examples/controls/types/list_tile_style/showcase/main.py index 57d20e386e..1005eb83bd 100644 --- a/sdk/python/examples/controls/types/list_tile_style/showcase.py +++ b/sdk/python/examples/controls/types/list_tile_style/showcase/main.py @@ -34,16 +34,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="ListTileStyle Showcase") page.add( - ft.Text("Compare list tile typography presets."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(style) for style in ft.ListTileStyle], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare list tile typography presets."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(style) for style in ft.ListTileStyle], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/list_tile_style/showcase/pyproject.toml b/sdk/python/examples/controls/types/list_tile_style/showcase/pyproject.toml new file mode 100644 index 0000000000..30a155f0cb --- /dev/null +++ b/sdk/python/examples/controls/types/list_tile_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-list-tile-style-showcase" +version = "1.0.0" +description = "Compares List Tile Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["list tile style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "List Tile Style showcase" +controls = ["SafeArea", "Column", "Container", "Text", "ListTile", "Icon", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/list_tile_title_alignment/showcase.py b/sdk/python/examples/controls/types/list_tile_title_alignment/showcase/main.py similarity index 64% rename from sdk/python/examples/controls/types/list_tile_title_alignment/showcase.py rename to sdk/python/examples/controls/types/list_tile_title_alignment/showcase/main.py index a5c95c98fd..64aa6dc654 100644 --- a/sdk/python/examples/controls/types/list_tile_title_alignment/showcase.py +++ b/sdk/python/examples/controls/types/list_tile_title_alignment/showcase/main.py @@ -37,18 +37,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="ListTileTitleAlignment Showcase") page.add( - ft.Text("Compare leading/trailing alignment against title area."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(alignment) for alignment in ft.ListTileTitleAlignment - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare leading/trailing alignment against title area."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(alignment) + for alignment in ft.ListTileTitleAlignment + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/list_tile_title_alignment/showcase/pyproject.toml b/sdk/python/examples/controls/types/list_tile_title_alignment/showcase/pyproject.toml new file mode 100644 index 0000000000..d670e3fb69 --- /dev/null +++ b/sdk/python/examples/controls/types/list_tile_title_alignment/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-list-tile-title-alignment-showcase" +version = "1.0.0" +description = "Compares List Tile Title Alignment values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["list tile title alignment", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "List Tile Title Alignment showcase" +controls = ["SafeArea", "Column", "Container", "Text", "ListTile", "CircleAvatar", "Icon", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/main_axis_alignment/showcase.py b/sdk/python/examples/controls/types/main_axis_alignment/showcase/main.py similarity index 64% rename from sdk/python/examples/controls/types/main_axis_alignment/showcase.py rename to sdk/python/examples/controls/types/main_axis_alignment/showcase/main.py index 3fb3faed23..ae73750d80 100644 --- a/sdk/python/examples/controls/types/main_axis_alignment/showcase.py +++ b/sdk/python/examples/controls/types/main_axis_alignment/showcase/main.py @@ -46,16 +46,29 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="MainAxisAlignment Showcase") page.add( - ft.Text("Compare horizontal distribution of children in a fixed-width row."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(alignment) for alignment in ft.MainAxisAlignment], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare horizontal distribution of children in a " + "fixed-width row." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(alignment) + for alignment in ft.MainAxisAlignment + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/main_axis_alignment/showcase/pyproject.toml b/sdk/python/examples/controls/types/main_axis_alignment/showcase/pyproject.toml new file mode 100644 index 0000000000..5333d6c4a5 --- /dev/null +++ b/sdk/python/examples/controls/types/main_axis_alignment/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-main-axis-alignment-showcase" +version = "1.0.0" +description = "Compares Main Axis Alignment values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["main axis alignment", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Main Axis Alignment showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Row", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/margin/container.py b/sdk/python/examples/controls/types/margin/container.py deleted file mode 100644 index 694ee35e41..0000000000 --- a/sdk/python/examples/controls/types/margin/container.py +++ /dev/null @@ -1,48 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Margin Example" - - page.add( - ft.Row( - spacing=0, - controls=[ - ft.Container( - content=ft.Button("container_1"), - bgcolor=ft.Colors.AMBER, - # padding=ft.Padding.all(10), - margin=ft.Margin.all(10), - width=200, - height=200, - ), - ft.Container( - content=ft.Button("container_2"), - bgcolor=ft.Colors.AMBER, - # padding=ft.Padding.all(20), - margin=ft.Margin.all(20), - width=200, - height=200, - ), - ft.Container( - content=ft.Button("container_3"), - bgcolor=ft.Colors.AMBER, - # padding=ft.Padding.symmetric(horizontal=10), - margin=ft.Margin.symmetric(vertical=10), - width=200, - height=200, - ), - ft.Container( - content=ft.Button("container_4"), - bgcolor=ft.Colors.AMBER, - # padding=ft.Padding.only(left=10), - margin=ft.Margin.only(left=10), - width=200, - height=200, - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/margin/container/main.py b/sdk/python/examples/controls/types/margin/container/main.py new file mode 100644 index 0000000000..1f758862e8 --- /dev/null +++ b/sdk/python/examples/controls/types/margin/container/main.py @@ -0,0 +1,55 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Margin Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + spacing=0, + controls=[ + ft.Container( + content=ft.Button("container_1"), + bgcolor=ft.Colors.AMBER, + # padding=ft.Padding.all(10), + margin=ft.Margin.all(10), + width=200, + height=200, + ), + ft.Container( + content=ft.Button("container_2"), + bgcolor=ft.Colors.AMBER, + # padding=ft.Padding.all(20), + margin=ft.Margin.all(20), + width=200, + height=200, + ), + ft.Container( + content=ft.Button("container_3"), + bgcolor=ft.Colors.AMBER, + # padding=ft.Padding.symmetric(horizontal=10), + margin=ft.Margin.symmetric(vertical=10), + width=200, + height=200, + ), + ft.Container( + content=ft.Button("container_4"), + bgcolor=ft.Colors.AMBER, + # padding=ft.Padding.only(left=10), + margin=ft.Margin.only(left=10), + width=200, + height=200, + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/margin/container/pyproject.toml b/sdk/python/examples/controls/types/margin/container/pyproject.toml new file mode 100644 index 0000000000..fd0bc98b32 --- /dev/null +++ b/sdk/python/examples/controls/types/margin/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-margin-container" +version = "1.0.0" +description = "Demonstrates how Margin values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["margin", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Margin" +controls = ["SafeArea", "Column", "Row", "Container", "Button", "Margin"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["margin preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/mouse_cursor/showcase.py b/sdk/python/examples/controls/types/mouse_cursor/showcase/main.py similarity index 54% rename from sdk/python/examples/controls/types/mouse_cursor/showcase.py rename to sdk/python/examples/controls/types/mouse_cursor/showcase/main.py index 1550036d46..fb4ab60f81 100644 --- a/sdk/python/examples/controls/types/mouse_cursor/showcase.py +++ b/sdk/python/examples/controls/types/mouse_cursor/showcase/main.py @@ -28,19 +28,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="MouseCursor Showcase") page.add( - ft.Text( - "Hover each card to compare cursor styles. " - "Cursor rendering can vary by OS and browser.", - ), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(cursor) for cursor in ft.MouseCursor], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Hover each card to compare cursor styles. " + "Cursor rendering can vary by OS and browser.", + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(cursor) for cursor in ft.MouseCursor], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/mouse_cursor/showcase/pyproject.toml b/sdk/python/examples/controls/types/mouse_cursor/showcase/pyproject.toml new file mode 100644 index 0000000000..21fff09eb8 --- /dev/null +++ b/sdk/python/examples/controls/types/mouse_cursor/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-mouse-cursor-showcase" +version = "1.0.0" +description = "Compares Mouse Cursor values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["mouse cursor", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Mouse Cursor showcase" +controls = ["SafeArea", "Column", "GestureDetector", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase.py b/sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase/main.py similarity index 59% rename from sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase.py rename to sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase/main.py index cbe4c5aa95..7471161a3b 100644 --- a/sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase.py +++ b/sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase/main.py @@ -33,18 +33,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="NavigationBarLabelBehavior Showcase") page.add( - ft.Text("Compare destination label visibility strategies."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(behavior) for behavior in ft.NavigationBarLabelBehavior - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare destination label visibility strategies."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(behavior) + for behavior in ft.NavigationBarLabelBehavior + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase/pyproject.toml b/sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase/pyproject.toml new file mode 100644 index 0000000000..8464025443 --- /dev/null +++ b/sdk/python/examples/controls/types/navigation_bar_label_behavior/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-navigation-bar-label-behavior-showcase" +version = "1.0.0" +description = "Compares Navigation Bar Label Behavior values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["navigation bar label behavior", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Navigation Bar Label Behavior showcase" +controls = ["SafeArea", "Column", "Container", "NavigationBar", "NavigationBarDestination", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/navigation_rail_label_type/showcase.py b/sdk/python/examples/controls/types/navigation_rail_label_type/showcase/main.py similarity index 64% rename from sdk/python/examples/controls/types/navigation_rail_label_type/showcase.py rename to sdk/python/examples/controls/types/navigation_rail_label_type/showcase/main.py index 366bb316e5..7ad4568f5c 100644 --- a/sdk/python/examples/controls/types/navigation_rail_label_type/showcase.py +++ b/sdk/python/examples/controls/types/navigation_rail_label_type/showcase/main.py @@ -36,16 +36,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="NavigationRailLabelType Showcase") page.add( - ft.Text("Compare label visibility in compact navigation rail."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(t) for t in ft.NavigationRailLabelType], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare label visibility in compact navigation rail."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(t) for t in ft.NavigationRailLabelType], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/navigation_rail_label_type/showcase/pyproject.toml b/sdk/python/examples/controls/types/navigation_rail_label_type/showcase/pyproject.toml new file mode 100644 index 0000000000..c675a018d6 --- /dev/null +++ b/sdk/python/examples/controls/types/navigation_rail_label_type/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-navigation-rail-label-type-showcase" +version = "1.0.0" +description = "Compares Navigation Rail Label Type values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["navigation rail label type", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Navigation Rail Label Type showcase" +controls = ["SafeArea", "Column", "Container", "NavigationRail", "NavigationRailDestination", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/orientation/showcase.py b/sdk/python/examples/controls/types/orientation/showcase/main.py similarity index 61% rename from sdk/python/examples/controls/types/orientation/showcase.py rename to sdk/python/examples/controls/types/orientation/showcase/main.py index 2b6e3b7c67..5edf88fd5e 100644 --- a/sdk/python/examples/controls/types/orientation/showcase.py +++ b/sdk/python/examples/controls/types/orientation/showcase/main.py @@ -34,16 +34,25 @@ def showcase_card(orientation: ft.Orientation) -> ft.Container: page.appbar = ft.AppBar(title="Orientation Showcase") page.add( - ft.Text("TimePicker supports PORTRAIT and LANDSCAPE layouts."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(orientation) for orientation in ft.Orientation], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("TimePicker supports PORTRAIT and LANDSCAPE layouts."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(orientation) for orientation in ft.Orientation + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/orientation/showcase/pyproject.toml b/sdk/python/examples/controls/types/orientation/showcase/pyproject.toml new file mode 100644 index 0000000000..3c15afd632 --- /dev/null +++ b/sdk/python/examples/controls/types/orientation/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-orientation-showcase" +version = "1.0.0" +description = "Compares Orientation values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["orientation", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Orientation showcase" +controls = ["SafeArea", "Column", "Container", "TimePicker", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/overlay_visibility_mode/showcase.py b/sdk/python/examples/controls/types/overlay_visibility_mode/showcase/main.py similarity index 66% rename from sdk/python/examples/controls/types/overlay_visibility_mode/showcase.py rename to sdk/python/examples/controls/types/overlay_visibility_mode/showcase/main.py index 2652401f6e..7fcb7b0265 100644 --- a/sdk/python/examples/controls/types/overlay_visibility_mode/showcase.py +++ b/sdk/python/examples/controls/types/overlay_visibility_mode/showcase/main.py @@ -37,16 +37,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="OverlayVisibilityMode Showcase") page.add( - ft.Text("Compare when Cupertino text field overlays appear."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(mode) for mode in ft.OverlayVisibilityMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare when Cupertino text field overlays appear."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(mode) for mode in ft.OverlayVisibilityMode + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/overlay_visibility_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/overlay_visibility_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..e5d493d06b --- /dev/null +++ b/sdk/python/examples/controls/types/overlay_visibility_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-overlay-visibility-mode-showcase" +version = "1.0.0" +description = "Compares Overlay Visibility Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["overlay visibility mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Overlay Visibility Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "CupertinoTextField", "Icon", "CupertinoIcons", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/padding/container.py b/sdk/python/examples/controls/types/padding/container.py deleted file mode 100644 index 89f578601d..0000000000 --- a/sdk/python/examples/controls/types/padding/container.py +++ /dev/null @@ -1,43 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Containers with different padding" - - page.add( - ft.Row( - controls=[ - ft.Container( - content=ft.Button("container_1"), - bgcolor=ft.Colors.AMBER, - padding=ft.Padding.all(10), - width=150, - height=150, - ), - ft.Container( - content=ft.Button("container_2"), - bgcolor=ft.Colors.AMBER, - padding=ft.Padding.all(20), - width=150, - height=150, - ), - ft.Container( - content=ft.Button("container_3"), - bgcolor=ft.Colors.AMBER, - padding=ft.Padding.symmetric(horizontal=10), - width=150, - height=150, - ), - ft.Container( - content=ft.Button("container_4"), - bgcolor=ft.Colors.AMBER, - padding=ft.Padding.only(left=10), - width=150, - height=150, - ), - ] - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/padding/container/main.py b/sdk/python/examples/controls/types/padding/container/main.py new file mode 100644 index 0000000000..053c724922 --- /dev/null +++ b/sdk/python/examples/controls/types/padding/container/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Containers with different padding" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Container( + content=ft.Button("container_1"), + bgcolor=ft.Colors.AMBER, + padding=ft.Padding.all(10), + width=150, + height=150, + ), + ft.Container( + content=ft.Button("container_2"), + bgcolor=ft.Colors.AMBER, + padding=ft.Padding.all(20), + width=150, + height=150, + ), + ft.Container( + content=ft.Button("container_3"), + bgcolor=ft.Colors.AMBER, + padding=ft.Padding.symmetric(horizontal=10), + width=150, + height=150, + ), + ft.Container( + content=ft.Button("container_4"), + bgcolor=ft.Colors.AMBER, + padding=ft.Padding.only(left=10), + width=150, + height=150, + ), + ] + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/padding/container/pyproject.toml b/sdk/python/examples/controls/types/padding/container/pyproject.toml new file mode 100644 index 0000000000..60644494af --- /dev/null +++ b/sdk/python/examples/controls/types/padding/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-padding-container" +version = "1.0.0" +description = "Demonstrates how Padding values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["padding", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Padding" +controls = ["SafeArea", "Column", "Row", "Container", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["padding preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/paint_gradient/canvas_paint.py b/sdk/python/examples/controls/types/paint_gradient/canvas_paint.py deleted file mode 100644 index fe2b161bda..0000000000 --- a/sdk/python/examples/controls/types/paint_gradient/canvas_paint.py +++ /dev/null @@ -1,71 +0,0 @@ -import math - -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Rect( - x=10, - y=10, - width=100, - height=100, - border_radius=5, - paint=ft.Paint( - style=ft.PaintingStyle.FILL, - gradient=ft.PaintLinearGradient( - begin=(0, 10), - end=(100, 50), - colors=[ft.Colors.BLUE, ft.Colors.YELLOW], - ), - ), - ), - cv.Circle( - x=60, - y=170, - radius=50, - paint=ft.Paint( - style=ft.PaintingStyle.FILL, - gradient=ft.PaintRadialGradient( - radius=50, - center=(60, 170), - colors=[ft.Colors.YELLOW, ft.Colors.BLUE], - ), - ), - ), - cv.Path( - elements=[ - cv.Path.Arc( - x=10, - y=230, - width=100, - height=100, - start_angle=3 * math.pi / 4, - sweep_angle=3 * math.pi / 2, - ), - ], - paint=ft.Paint( - stroke_width=15, - stroke_join=ft.StrokeJoin.ROUND, - style=ft.PaintingStyle.STROKE, - gradient=ft.PaintSweepGradient( - start_angle=0, - end_angle=math.pi * 2, - rotation=3 * math.pi / 4, - center=(60, 280), - colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], - color_stops=[0.0, 1.0], - ), - ), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/paint_gradient/canvas_paint/main.py b/sdk/python/examples/controls/types/paint_gradient/canvas_paint/main.py new file mode 100644 index 0000000000..399cae0f65 --- /dev/null +++ b/sdk/python/examples/controls/types/paint_gradient/canvas_paint/main.py @@ -0,0 +1,78 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Rect( + x=10, + y=10, + width=100, + height=100, + border_radius=5, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintLinearGradient( + begin=(0, 10), + end=(100, 50), + colors=[ft.Colors.BLUE, ft.Colors.YELLOW], + ), + ), + ), + cv.Circle( + x=60, + y=170, + radius=50, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintRadialGradient( + radius=50, + center=(60, 170), + colors=[ft.Colors.YELLOW, ft.Colors.BLUE], + ), + ), + ), + cv.Path( + elements=[ + cv.Path.Arc( + x=10, + y=230, + width=100, + height=100, + start_angle=3 * math.pi / 4, + sweep_angle=3 * math.pi / 2, + ), + ], + paint=ft.Paint( + stroke_width=15, + stroke_join=ft.StrokeJoin.ROUND, + style=ft.PaintingStyle.STROKE, + gradient=ft.PaintSweepGradient( + start_angle=0, + end_angle=math.pi * 2, + rotation=3 * math.pi / 4, + center=(60, 280), + colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], + color_stops=[0.0, 1.0], + ), + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/paint_gradient/canvas_paint/pyproject.toml b/sdk/python/examples/controls/types/paint_gradient/canvas_paint/pyproject.toml new file mode 100644 index 0000000000..a1d64c3203 --- /dev/null +++ b/sdk/python/examples/controls/types/paint_gradient/canvas_paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-paint-gradient-canvas-paint" +version = "1.0.0" +description = "Draws a canvas preview using Paint Gradient gradient settings and paint objects." +requires-python = ">=3.10" +keywords = ["paint gradient", "canvas paint"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Canvas/Shapes"] + +[tool.flet.metadata] +title = "Paint Gradient" +controls = ["SafeArea", "Column", "Canvas", "Rect", "Circle", "Path"] +layout_pattern = "canvas" +complexity = "basic" +features = ["canvas drawing", "gradient paint preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint.py b/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint.py deleted file mode 100644 index 088a985cff..0000000000 --- a/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Rect( - x=10, - y=10, - width=100, - height=100, - border_radius=5, - paint=ft.Paint( - style=ft.PaintingStyle.FILL, - gradient=ft.PaintLinearGradient( - begin=(0, 10), - end=(100, 50), - colors=[ft.Colors.BLUE, ft.Colors.YELLOW], - ), - ), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/main.py b/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/main.py new file mode 100644 index 0000000000..e318a22fe6 --- /dev/null +++ b/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/main.py @@ -0,0 +1,38 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Rect( + x=10, + y=10, + width=100, + height=100, + border_radius=5, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintLinearGradient( + begin=(0, 10), + end=(100, 50), + colors=[ft.Colors.BLUE, ft.Colors.YELLOW], + ), + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/pyproject.toml b/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/pyproject.toml new file mode 100644 index 0000000000..bd2ab5d01c --- /dev/null +++ b/sdk/python/examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-paint-gradient-paint-linear-gradient-canvas-paint" +version = "1.0.0" +description = "Draws a canvas preview using Paint Linear Gradient gradient settings and paint objects." +requires-python = ">=3.10" +keywords = ["paint gradient", "paint linear gradient", "canvas paint"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Canvas/Shapes"] + +[tool.flet.metadata] +title = "Paint Linear Gradient" +controls = ["SafeArea", "Column", "Canvas", "Rect"] +layout_pattern = "canvas" +complexity = "basic" +features = ["canvas drawing", "gradient paint preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint.py b/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint.py deleted file mode 100644 index 8ccae77728..0000000000 --- a/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint.py +++ /dev/null @@ -1,29 +0,0 @@ -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Circle( - x=60, - y=170, - radius=50, - paint=ft.Paint( - style=ft.PaintingStyle.FILL, - gradient=ft.PaintRadialGradient( - radius=50, - center=(60, 170), - colors=[ft.Colors.YELLOW, ft.Colors.BLUE], - ), - ), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/main.py b/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/main.py new file mode 100644 index 0000000000..6e8470470a --- /dev/null +++ b/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/main.py @@ -0,0 +1,36 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Circle( + x=60, + y=170, + radius=50, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintRadialGradient( + radius=50, + center=(60, 170), + colors=[ft.Colors.YELLOW, ft.Colors.BLUE], + ), + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/pyproject.toml b/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/pyproject.toml new file mode 100644 index 0000000000..061c411171 --- /dev/null +++ b/sdk/python/examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-paint-gradient-paint-radial-gradient-canvas-paint" +version = "1.0.0" +description = "Draws a canvas preview using Paint Radial Gradient gradient settings and paint objects." +requires-python = ">=3.10" +keywords = ["paint gradient", "paint radial gradient", "canvas paint"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Canvas/Shapes"] + +[tool.flet.metadata] +title = "Paint Radial Gradient" +controls = ["SafeArea", "Column", "Canvas", "Circle"] +layout_pattern = "canvas" +complexity = "basic" +features = ["canvas drawing", "gradient paint preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint.py b/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint.py deleted file mode 100644 index 29fc05ce64..0000000000 --- a/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint.py +++ /dev/null @@ -1,43 +0,0 @@ -import math - -import flet as ft -import flet.canvas as cv - - -def main(page: ft.Page): - page.add( - cv.Canvas( - width=float("inf"), - expand=True, - shapes=[ - cv.Path( - elements=[ - cv.Path.Arc( - x=10, - y=230, - width=100, - height=100, - start_angle=3 * math.pi / 4, - sweep_angle=3 * math.pi / 2, - ), - ], - paint=ft.Paint( - stroke_width=15, - stroke_join=ft.StrokeJoin.ROUND, - style=ft.PaintingStyle.STROKE, - gradient=ft.PaintSweepGradient( - start_angle=0, - end_angle=math.pi * 2, - rotation=3 * math.pi / 4, - center=(60, 280), - colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], - color_stops=[0.0, 1.0], - ), - ), - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/main.py b/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/main.py new file mode 100644 index 0000000000..f8c6b76e4a --- /dev/null +++ b/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/main.py @@ -0,0 +1,50 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Path( + elements=[ + cv.Path.Arc( + x=10, + y=230, + width=100, + height=100, + start_angle=3 * math.pi / 4, + sweep_angle=3 * math.pi / 2, + ), + ], + paint=ft.Paint( + stroke_width=15, + stroke_join=ft.StrokeJoin.ROUND, + style=ft.PaintingStyle.STROKE, + gradient=ft.PaintSweepGradient( + start_angle=0, + end_angle=math.pi * 2, + rotation=3 * math.pi / 4, + center=(60, 280), + colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], + color_stops=[0.0, 1.0], + ), + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/pyproject.toml b/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/pyproject.toml new file mode 100644 index 0000000000..ee12b75ce1 --- /dev/null +++ b/sdk/python/examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-paint-gradient-paint-sweep-gradient-canvas-paint" +version = "1.0.0" +description = "Draws a canvas preview using Paint Sweep Gradient gradient settings and paint objects." +requires-python = ">=3.10" +keywords = ["paint gradient", "paint sweep gradient", "canvas paint"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Canvas/Shapes"] + +[tool.flet.metadata] +title = "Paint Sweep Gradient" +controls = ["SafeArea", "Column", "Canvas", "Path"] +layout_pattern = "canvas" +complexity = "basic" +features = ["canvas drawing", "gradient paint preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/painting_style/showcase.py b/sdk/python/examples/controls/types/painting_style/showcase/main.py similarity index 65% rename from sdk/python/examples/controls/types/painting_style/showcase.py rename to sdk/python/examples/controls/types/painting_style/showcase/main.py index 4cf44871fe..7166d110cd 100644 --- a/sdk/python/examples/controls/types/painting_style/showcase.py +++ b/sdk/python/examples/controls/types/painting_style/showcase/main.py @@ -39,16 +39,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="PaintingStyle Showcase") page.add( - ft.Text("Compare filled vs outlined rendering for the same shape."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(style) for style in ft.PaintingStyle], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare filled vs outlined rendering for the same shape."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(style) for style in ft.PaintingStyle], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/painting_style/showcase/pyproject.toml b/sdk/python/examples/controls/types/painting_style/showcase/pyproject.toml new file mode 100644 index 0000000000..5cdfabdc10 --- /dev/null +++ b/sdk/python/examples/controls/types/painting_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-painting-style-showcase" +version = "1.0.0" +description = "Compares Painting Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["painting style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Canvas/Shapes"] + +[tool.flet.metadata] +title = "Painting Style showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Canvas", "Circle", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/point_mode/showcase.py b/sdk/python/examples/controls/types/point_mode/showcase/main.py similarity index 64% rename from sdk/python/examples/controls/types/point_mode/showcase.py rename to sdk/python/examples/controls/types/point_mode/showcase/main.py index 912f36213e..cd3d733724 100644 --- a/sdk/python/examples/controls/types/point_mode/showcase.py +++ b/sdk/python/examples/controls/types/point_mode/showcase/main.py @@ -46,18 +46,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="PointMode Showcase") page.add( - ft.Text( - "Compare how the same coordinate list is interpreted by each point mode." - ), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(mode) for mode in cv.PointMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how the same coordinate list is interpreted " + "by each point mode." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(mode) for mode in cv.PointMode], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/point_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/point_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..8524348a99 --- /dev/null +++ b/sdk/python/examples/controls/types/point_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-point-mode-showcase" +version = "1.0.0" +description = "Compares Point Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["point mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Canvas/Shapes"] + +[tool.flet.metadata] +title = "Point Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Canvas", "Points", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/popup_menu_position/showcase.py b/sdk/python/examples/controls/types/popup_menu_position/showcase/main.py similarity index 63% rename from sdk/python/examples/controls/types/popup_menu_position/showcase.py rename to sdk/python/examples/controls/types/popup_menu_position/showcase/main.py index ba875fab69..b04aa79b57 100644 --- a/sdk/python/examples/controls/types/popup_menu_position/showcase.py +++ b/sdk/python/examples/controls/types/popup_menu_position/showcase/main.py @@ -36,16 +36,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="PopupMenuPosition Showcase") page.add( - ft.Text("Open each popup menu to compare their positioning."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(position) for position in ft.PopupMenuPosition], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Open each popup menu to compare their positioning."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(position) for position in ft.PopupMenuPosition + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/popup_menu_position/showcase/pyproject.toml b/sdk/python/examples/controls/types/popup_menu_position/showcase/pyproject.toml new file mode 100644 index 0000000000..185e99d110 --- /dev/null +++ b/sdk/python/examples/controls/types/popup_menu_position/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-popup-menu-position-showcase" +version = "1.0.0" +description = "Compares Popup Menu Position values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["popup menu position", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Popup Menu Position showcase" +controls = ["SafeArea", "Column", "Container", "PopupMenuButton", "Text", "PopupMenuItem", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/scroll_bar/showcase.py b/sdk/python/examples/controls/types/scroll_bar/showcase.py deleted file mode 100644 index a5ad78e154..0000000000 --- a/sdk/python/examples/controls/types/scroll_bar/showcase.py +++ /dev/null @@ -1,190 +0,0 @@ -from typing import Optional - -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.appbar = ft.AppBar(title="Scrollbar Dataclass Showcase") - - def get_scrollbar() -> ft.Scrollbar: - def str_as_bool(value: Optional[str]) -> Optional[bool]: - return True if value == "true" else False if value == "false" else None - - return ft.Scrollbar( - thumb_visibility=str_as_bool(thumb_visibility.value), - track_visibility=str_as_bool(track_visibility.value), - interactive=str_as_bool(interactive.value), - thickness=thickness_value.value if use_thickness.value else None, - radius=radius_value.value if use_radius.value else None, - orientation=None - if orientation.value == "none" - else ft.ScrollbarOrientation(orientation.value), - ) - - def get_preview_content(scrollbar: ft.Scrollbar) -> tuple[str, ft.Control]: - selected_orientation = scrollbar.orientation - is_horizontal = selected_orientation in ( - ft.ScrollbarOrientation.TOP, - ft.ScrollbarOrientation.BOTTOM, - ) - if is_horizontal: - return ( - "Horizontal preview (TOP/BOTTOM orientation)", - ft.Row( - spacing=8, - scroll=scrollbar, - controls=[ - ft.Container( - width=110, - height=80, - border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), - border_radius=8, - bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, - alignment=ft.Alignment.CENTER, - content=ft.Text(f"Tile {i + 1}"), - ) - for i in range(18) - ], - ), - ) - - return ( - "Vertical preview (None/LEFT/RIGHT orientation)", - ft.Column( - spacing=4, - scroll=scrollbar, - controls=[ft.Text(f"Item {i + 1}") for i in range(40)], - ), - ) - - def update_preview(): - thickness_value.disabled = not use_thickness.value - radius_value.disabled = not use_radius.value - - scrollbar = get_scrollbar() - title, content = get_preview_content(scrollbar) - preview_title.value = title - preview_viewport.content = content - page.update() - - page.add( - ft.Text( - "Interactive playground for the Scrollbar dataclass. Change each property " - "and inspect the live result." - ), - ft.Row( - wrap=True, - spacing=12, - run_spacing=12, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - ft.Container( - width=360, - padding=12, - border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), - border_radius=10, - bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, - content=ft.Column( - spacing=10, - controls=[ - ft.Text("Configuration", weight=ft.FontWeight.BOLD), - thumb_visibility := ft.Dropdown( - label="thumb_visibility", - value="none", - on_select=update_preview, - options=[ - ft.DropdownOption("none", "None (theme default)"), - ft.DropdownOption("true", "True"), - ft.DropdownOption("false", "False"), - ], - ), - track_visibility := ft.Dropdown( - label="track_visibility", - value="none", - on_select=update_preview, - options=[ - ft.DropdownOption("none", "None (theme default)"), - ft.DropdownOption("true", "True"), - ft.DropdownOption("false", "False"), - ], - ), - interactive := ft.Dropdown( - label="interactive", - value="none", - on_select=update_preview, - options=[ - ft.DropdownOption( - "none", "None (platform default)" - ), - ft.DropdownOption("true", "True"), - ft.DropdownOption("false", "False"), - ], - ), - orientation := ft.Dropdown( - label="orientation", - value="none", - on_select=update_preview, - options=[ft.DropdownOption("none", "None (auto side)")] - + [ - ft.DropdownOption(o.value, o.name) - for o in ft.ScrollbarOrientation - ], - ), - use_thickness := ft.Checkbox( - label="Set thickness", - value=False, - on_change=update_preview, - ), - thickness_value := ft.Slider( - min=0, - max=20, - divisions=20, - value=8, - label="{value}", - on_change=update_preview, - ), - use_radius := ft.Checkbox( - label="Set radius", - value=False, - on_change=update_preview, - ), - radius_value := ft.Slider( - min=0, - max=20, - divisions=20, - value=8, - label="{value}", - on_change=update_preview, - ), - ], - ), - ), - ft.Container( - width=420, - padding=12, - border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), - border_radius=10, - bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, - content=ft.Column( - spacing=10, - controls=[ - ft.Text("Live preview", weight=ft.FontWeight.BOLD), - preview_title := ft.Text(weight=ft.FontWeight.BOLD), - preview_viewport := ft.Container( - height=260, - border=ft.Border.all(1, ft.Colors.OUTLINE), - border_radius=8, - padding=8, - ), - ], - ), - ), - ], - ), - ) - - update_preview() - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/scroll_bar/showcase/main.py b/sdk/python/examples/controls/types/scroll_bar/showcase/main.py new file mode 100644 index 0000000000..ad2c09a7a9 --- /dev/null +++ b/sdk/python/examples/controls/types/scroll_bar/showcase/main.py @@ -0,0 +1,211 @@ +from typing import Optional + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.appbar = ft.AppBar(title="Scrollbar Dataclass Showcase") + + def get_scrollbar() -> ft.Scrollbar: + def str_as_bool(value: Optional[str]) -> Optional[bool]: + return True if value == "true" else False if value == "false" else None + + return ft.Scrollbar( + thumb_visibility=str_as_bool(thumb_visibility.value), + track_visibility=str_as_bool(track_visibility.value), + interactive=str_as_bool(interactive.value), + thickness=thickness_value.value if use_thickness.value else None, + radius=radius_value.value if use_radius.value else None, + orientation=None + if orientation.value == "none" + else ft.ScrollbarOrientation(orientation.value), + ) + + def get_preview_content(scrollbar: ft.Scrollbar) -> tuple[str, ft.Control]: + selected_orientation = scrollbar.orientation + is_horizontal = selected_orientation in ( + ft.ScrollbarOrientation.TOP, + ft.ScrollbarOrientation.BOTTOM, + ) + if is_horizontal: + return ( + "Horizontal preview (TOP/BOTTOM orientation)", + ft.Row( + spacing=8, + scroll=scrollbar, + controls=[ + ft.Container( + width=110, + height=80, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=8, + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + alignment=ft.Alignment.CENTER, + content=ft.Text(f"Tile {i + 1}"), + ) + for i in range(18) + ], + ), + ) + + return ( + "Vertical preview (None/LEFT/RIGHT orientation)", + ft.Column( + spacing=4, + scroll=scrollbar, + controls=[ft.Text(f"Item {i + 1}") for i in range(40)], + ), + ) + + def update_preview(): + thickness_value.disabled = not use_thickness.value + radius_value.disabled = not use_radius.value + + scrollbar = get_scrollbar() + title, content = get_preview_content(scrollbar) + preview_title.value = title + preview_viewport.content = content + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Interactive playground for the Scrollbar dataclass. " + "Change each property and inspect the live result." + ), + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Container( + width=360, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=10, + controls=[ + ft.Text( + "Configuration", weight=ft.FontWeight.BOLD + ), + thumb_visibility := ft.Dropdown( + label="thumb_visibility", + value="none", + on_select=update_preview, + options=[ + ft.DropdownOption( + "none", "None (theme default)" + ), + ft.DropdownOption("true", "True"), + ft.DropdownOption("false", "False"), + ], + ), + track_visibility := ft.Dropdown( + label="track_visibility", + value="none", + on_select=update_preview, + options=[ + ft.DropdownOption( + "none", "None (theme default)" + ), + ft.DropdownOption("true", "True"), + ft.DropdownOption("false", "False"), + ], + ), + interactive := ft.Dropdown( + label="interactive", + value="none", + on_select=update_preview, + options=[ + ft.DropdownOption( + "none", "None (platform default)" + ), + ft.DropdownOption("true", "True"), + ft.DropdownOption("false", "False"), + ], + ), + orientation := ft.Dropdown( + label="orientation", + value="none", + on_select=update_preview, + options=[ + ft.DropdownOption( + "none", "None (auto side)" + ) + ] + + [ + ft.DropdownOption(o.value, o.name) + for o in ft.ScrollbarOrientation + ], + ), + use_thickness := ft.Checkbox( + label="Set thickness", + value=False, + on_change=update_preview, + ), + thickness_value := ft.Slider( + min=0, + max=20, + divisions=20, + value=8, + label="{value}", + on_change=update_preview, + ), + use_radius := ft.Checkbox( + label="Set radius", + value=False, + on_change=update_preview, + ), + radius_value := ft.Slider( + min=0, + max=20, + divisions=20, + value=8, + label="{value}", + on_change=update_preview, + ), + ], + ), + ), + ft.Container( + width=420, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=10, + controls=[ + ft.Text( + "Live preview", weight=ft.FontWeight.BOLD + ), + preview_title := ft.Text( + weight=ft.FontWeight.BOLD + ), + preview_viewport := ft.Container( + height=260, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + padding=8, + ), + ], + ), + ), + ], + ), + ], + ), + ) + ) + + update_preview() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/scroll_bar/showcase/pyproject.toml b/sdk/python/examples/controls/types/scroll_bar/showcase/pyproject.toml new file mode 100644 index 0000000000..bcb3d5f2cb --- /dev/null +++ b/sdk/python/examples/controls/types/scroll_bar/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-bar-showcase" +version = "1.0.0" +description = "Compares Scroll Bar values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll bar", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Bar showcase" +controls = ["SafeArea", "Column", "AppBar", "Scrollbar", "Row", "Container", "Text", "Dropdown"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/scroll_bar_orientation/showcase.py b/sdk/python/examples/controls/types/scroll_bar_orientation/showcase/main.py similarity index 72% rename from sdk/python/examples/controls/types/scroll_bar_orientation/showcase.py rename to sdk/python/examples/controls/types/scroll_bar_orientation/showcase/main.py index ea8c463407..f4705443e0 100644 --- a/sdk/python/examples/controls/types/scroll_bar_orientation/showcase.py +++ b/sdk/python/examples/controls/types/scroll_bar_orientation/showcase/main.py @@ -71,21 +71,29 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="ScrollbarOrientation Showcase") page.add( - ft.Text( - "LEFT/RIGHT apply to vertical scrollables, TOP/BOTTOM apply to " - "horizontal scrollables.", - ), - ft.Row( - wrap=True, - spacing=12, - run_spacing=12, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(orientation) for orientation in ft.ScrollbarOrientation - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "LEFT/RIGHT apply to vertical scrollables, TOP/BOTTOM apply to " + "horizontal scrollables.", + ), + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(orientation) + for orientation in ft.ScrollbarOrientation + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/scroll_bar_orientation/showcase/pyproject.toml b/sdk/python/examples/controls/types/scroll_bar_orientation/showcase/pyproject.toml new file mode 100644 index 0000000000..c4cf0a87d6 --- /dev/null +++ b/sdk/python/examples/controls/types/scroll_bar_orientation/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-bar-orientation-showcase" +version = "1.0.0" +description = "Compares Scroll Bar Orientation values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll bar orientation", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Bar Orientation showcase" +controls = ["SafeArea", "Column", "Container", "Scrollbar", "Text", "Row", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/scroll_direction/showcase.py b/sdk/python/examples/controls/types/scroll_direction/showcase.py deleted file mode 100644 index b41c0ac979..0000000000 --- a/sdk/python/examples/controls/types/scroll_direction/showcase.py +++ /dev/null @@ -1,48 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - counts = {direction: 0 for direction in ft.ScrollDirection} - count_labels = { - direction: ft.Text(f"{direction.name}: 0") for direction in ft.ScrollDirection - } - - def on_scroll(e: ft.OnScrollEvent): - if e.event_type == ft.ScrollType.USER and e.direction is not None: - counts[e.direction] += 1 - count_labels[ - e.direction - ].value = f"{e.direction.name}: {counts[e.direction]}" - last.value = f"Last USER direction: {e.direction.name}" - for label in count_labels.values(): - label.update() - last.update() - - page.appbar = ft.AppBar(title="ScrollDirection Showcase") - page.add( - ft.Text("Scroll the list and watch USER direction notifications."), - last := ft.Text("Last USER direction: none"), - ft.Row( - wrap=True, - spacing=10, - controls=[count_labels[d] for d in ft.ScrollDirection], - alignment=ft.MainAxisAlignment.CENTER, - ), - ft.Container( - width=360, - height=240, - border=ft.Border.all(1, ft.Colors.OUTLINE), - border_radius=8, - padding=8, - content=ft.Column( - scroll=ft.ScrollMode.ALWAYS, - on_scroll=on_scroll, - controls=[ft.Text(f"Scrollable item {i + 1}") for i in range(60)], - ), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/scroll_direction/showcase/main.py b/sdk/python/examples/controls/types/scroll_direction/showcase/main.py new file mode 100644 index 0000000000..b3294e3e50 --- /dev/null +++ b/sdk/python/examples/controls/types/scroll_direction/showcase/main.py @@ -0,0 +1,57 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + counts = {direction: 0 for direction in ft.ScrollDirection} + count_labels = { + direction: ft.Text(f"{direction.name}: 0") for direction in ft.ScrollDirection + } + + def on_scroll(e: ft.OnScrollEvent): + if e.event_type == ft.ScrollType.USER and e.direction is not None: + counts[e.direction] += 1 + count_labels[ + e.direction + ].value = f"{e.direction.name}: {counts[e.direction]}" + last.value = f"Last USER direction: {e.direction.name}" + for label in count_labels.values(): + label.update() + last.update() + + page.appbar = ft.AppBar(title="ScrollDirection Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Scroll the list and watch USER direction notifications."), + last := ft.Text("Last USER direction: none"), + ft.Row( + wrap=True, + spacing=10, + controls=[count_labels[d] for d in ft.ScrollDirection], + alignment=ft.MainAxisAlignment.CENTER, + ), + ft.Container( + width=360, + height=240, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + padding=8, + content=ft.Column( + scroll=ft.ScrollMode.ALWAYS, + on_scroll=on_scroll, + controls=[ + ft.Text(f"Scrollable item {i + 1}") for i in range(60) + ], + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/scroll_direction/showcase/pyproject.toml b/sdk/python/examples/controls/types/scroll_direction/showcase/pyproject.toml new file mode 100644 index 0000000000..e1052da622 --- /dev/null +++ b/sdk/python/examples/controls/types/scroll_direction/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-direction-showcase" +version = "1.0.0" +description = "Compares Scroll Direction values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll direction", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Direction showcase" +controls = ["SafeArea", "Column", "Text", "OnScrollEvent", "AppBar", "Row", "Container"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/scroll_mode/showcase.py b/sdk/python/examples/controls/types/scroll_mode/showcase/main.py similarity index 61% rename from sdk/python/examples/controls/types/scroll_mode/showcase.py rename to sdk/python/examples/controls/types/scroll_mode/showcase/main.py index 1964e2f87b..28fb6062ac 100644 --- a/sdk/python/examples/controls/types/scroll_mode/showcase.py +++ b/sdk/python/examples/controls/types/scroll_mode/showcase/main.py @@ -35,16 +35,27 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="ScrollMode Showcase") page.add( - ft.Text("Compare scrollbar visibility and scrolling behavior modes."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(scroll_mode) for scroll_mode in ft.ScrollMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare scrollbar visibility and scrolling behavior modes." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(scroll_mode) for scroll_mode in ft.ScrollMode + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/scroll_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/scroll_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..43e22593b7 --- /dev/null +++ b/sdk/python/examples/controls/types/scroll_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-mode-showcase" +version = "1.0.0" +description = "Compares Scroll Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/scroll_type/showcase.py b/sdk/python/examples/controls/types/scroll_type/showcase.py deleted file mode 100644 index f08cdaf0be..0000000000 --- a/sdk/python/examples/controls/types/scroll_type/showcase.py +++ /dev/null @@ -1,50 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - counts = {event_type: 0 for event_type in ft.ScrollType} - count_labels = { - event_type: ft.Text(f"{event_type.name}: 0") for event_type in ft.ScrollType - } - - def on_scroll(e: ft.OnScrollEvent): - counts[e.event_type] += 1 - count_labels[ - e.event_type - ].value = f"{e.event_type.name}: {counts[e.event_type]}" - last.value = ( - f"Last event: {e.event_type.name}, pixels={round(e.pixels, 1)}" - f"{', direction=' if e.direction else ''}" - ) - for label in count_labels.values(): - label.update() - last.update() - - page.appbar = ft.AppBar(title="ScrollType Showcase") - page.add( - ft.Text("Scroll the list to generate start/update/user/end notifications."), - last := ft.Text(), - ft.Row( - wrap=True, - spacing=10, - controls=[count_labels[t] for t in ft.ScrollType], - alignment=ft.MainAxisAlignment.CENTER, - ), - ft.Container( - width=360, - height=240, - border=ft.Border.all(1, ft.Colors.OUTLINE), - border_radius=8, - padding=8, - content=ft.Column( - scroll=ft.ScrollMode.ALWAYS, - on_scroll=on_scroll, - controls=[ft.Text(f"Scrollable item {i + 1}") for i in range(60)], - ), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/scroll_type/showcase/main.py b/sdk/python/examples/controls/types/scroll_type/showcase/main.py new file mode 100644 index 0000000000..919aa2a67a --- /dev/null +++ b/sdk/python/examples/controls/types/scroll_type/showcase/main.py @@ -0,0 +1,62 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + counts = {event_type: 0 for event_type in ft.ScrollType} + count_labels = { + event_type: ft.Text(f"{event_type.name}: 0") for event_type in ft.ScrollType + } + + def on_scroll(e: ft.OnScrollEvent): + counts[e.event_type] += 1 + count_labels[ + e.event_type + ].value = f"{e.event_type.name}: {counts[e.event_type]}" + last.value = ( + f"Last event: {e.event_type.name}, pixels={round(e.pixels, 1)}" + f"{', direction=' if e.direction else ''}" + ) + for label in count_labels.values(): + label.update() + last.update() + + page.appbar = ft.AppBar(title="ScrollType Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Scroll the list to generate start/update/user/end " + "notifications." + ), + last := ft.Text(), + ft.Row( + wrap=True, + spacing=10, + controls=[count_labels[t] for t in ft.ScrollType], + alignment=ft.MainAxisAlignment.CENTER, + ), + ft.Container( + width=360, + height=240, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + padding=8, + content=ft.Column( + scroll=ft.ScrollMode.ALWAYS, + on_scroll=on_scroll, + controls=[ + ft.Text(f"Scrollable item {i + 1}") for i in range(60) + ], + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/scroll_type/showcase/pyproject.toml b/sdk/python/examples/controls/types/scroll_type/showcase/pyproject.toml new file mode 100644 index 0000000000..8c83f4e473 --- /dev/null +++ b/sdk/python/examples/controls/types/scroll_type/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-type-showcase" +version = "1.0.0" +description = "Compares Scroll Type values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll type", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Type showcase" +controls = ["SafeArea", "Column", "Text", "OnScrollEvent", "AppBar", "Row", "Container"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/slider_interaction/showcase.py b/sdk/python/examples/controls/types/slider_interaction/showcase/main.py similarity index 70% rename from sdk/python/examples/controls/types/slider_interaction/showcase.py rename to sdk/python/examples/controls/types/slider_interaction/showcase/main.py index 12481437a6..1f10f9589c 100644 --- a/sdk/python/examples/controls/types/slider_interaction/showcase.py +++ b/sdk/python/examples/controls/types/slider_interaction/showcase/main.py @@ -45,16 +45,23 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="SliderInteraction Showcase") page.add( - ft.Text("Compare which gestures are accepted by each slider mode."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(i) for i in ft.SliderInteraction], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare which gestures are accepted by each slider mode."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(i) for i in ft.SliderInteraction], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/slider_interaction/showcase/pyproject.toml b/sdk/python/examples/controls/types/slider_interaction/showcase/pyproject.toml new file mode 100644 index 0000000000..f88c501c93 --- /dev/null +++ b/sdk/python/examples/controls/types/slider_interaction/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-slider-interaction-showcase" +version = "1.0.0" +description = "Compares Slider Interaction values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["slider interaction", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Slider Interaction showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Slider", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/snack_bar_behavior/showcase.py b/sdk/python/examples/controls/types/snack_bar_behavior/showcase/main.py similarity index 64% rename from sdk/python/examples/controls/types/snack_bar_behavior/showcase.py rename to sdk/python/examples/controls/types/snack_bar_behavior/showcase/main.py index a2c6e95bf9..b8ef114c9b 100644 --- a/sdk/python/examples/controls/types/snack_bar_behavior/showcase.py +++ b/sdk/python/examples/controls/types/snack_bar_behavior/showcase/main.py @@ -36,16 +36,25 @@ def showcase_card(behavior: ft.SnackBarBehavior) -> ft.Container: page.appbar = ft.AppBar(title="SnackBarBehavior Showcase") page.add( - ft.Text("Compare snack bar placement: fixed vs floating."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(behavior) for behavior in ft.SnackBarBehavior], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare snack bar placement: fixed vs floating."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(behavior) for behavior in ft.SnackBarBehavior + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/snack_bar_behavior/showcase/pyproject.toml b/sdk/python/examples/controls/types/snack_bar_behavior/showcase/pyproject.toml new file mode 100644 index 0000000000..08ef2b070b --- /dev/null +++ b/sdk/python/examples/controls/types/snack_bar_behavior/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-snack-bar-behavior-showcase" +version = "1.0.0" +description = "Compares Snack Bar Behavior values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["snack bar behavior", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Snack Bar Behavior showcase" +controls = ["SafeArea", "Column", "SnackBar", "Text", "Margin", "SnackBarAction", "Container", "Button"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/stroke_cap/showcase.py b/sdk/python/examples/controls/types/stroke_cap/showcase/main.py similarity index 72% rename from sdk/python/examples/controls/types/stroke_cap/showcase.py rename to sdk/python/examples/controls/types/stroke_cap/showcase/main.py index 16137049a9..1629021e79 100644 --- a/sdk/python/examples/controls/types/stroke_cap/showcase.py +++ b/sdk/python/examples/controls/types/stroke_cap/showcase/main.py @@ -54,16 +54,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="StrokeCap Showcase") page.add( - ft.Text("Compare line endings for each StrokeCap value."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(stroke_cap) for stroke_cap in ft.StrokeCap], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare line endings for each StrokeCap value."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(stroke_cap) for stroke_cap in ft.StrokeCap + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/stroke_cap/showcase/pyproject.toml b/sdk/python/examples/controls/types/stroke_cap/showcase/pyproject.toml new file mode 100644 index 0000000000..e2a1be6d26 --- /dev/null +++ b/sdk/python/examples/controls/types/stroke_cap/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-stroke-cap-showcase" +version = "1.0.0" +description = "Compares Stroke Cap values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["stroke cap", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Canvas/Shapes"] + +[tool.flet.metadata] +title = "Stroke Cap showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Canvas", "Line", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/stroke_join/showcase.py b/sdk/python/examples/controls/types/stroke_join/showcase/main.py similarity index 68% rename from sdk/python/examples/controls/types/stroke_join/showcase.py rename to sdk/python/examples/controls/types/stroke_join/showcase/main.py index 99269e5b49..57a5bea667 100644 --- a/sdk/python/examples/controls/types/stroke_join/showcase.py +++ b/sdk/python/examples/controls/types/stroke_join/showcase/main.py @@ -43,16 +43,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="StrokeJoin Showcase") page.add( - ft.Text("Compare corner rendering for each StrokeJoin value."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(stroke_join) for stroke_join in ft.StrokeJoin], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare corner rendering for each StrokeJoin value."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(stroke_join) for stroke_join in ft.StrokeJoin + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/stroke_join/showcase/pyproject.toml b/sdk/python/examples/controls/types/stroke_join/showcase/pyproject.toml new file mode 100644 index 0000000000..e11faa95c4 --- /dev/null +++ b/sdk/python/examples/controls/types/stroke_join/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-stroke-join-showcase" +version = "1.0.0" +description = "Compares Stroke Join values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["stroke join", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Canvas/Shapes"] + +[tool.flet.metadata] +title = "Stroke Join showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Canvas", "Path", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/tab_alignment/showcase.py b/sdk/python/examples/controls/types/tab_alignment/showcase/main.py similarity index 69% rename from sdk/python/examples/controls/types/tab_alignment/showcase.py rename to sdk/python/examples/controls/types/tab_alignment/showcase/main.py index 2fedb81458..89d73b37d5 100644 --- a/sdk/python/examples/controls/types/tab_alignment/showcase.py +++ b/sdk/python/examples/controls/types/tab_alignment/showcase/main.py @@ -53,16 +53,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="TabAlignment Showcase") page.add( - ft.Text("Compare how tabs are positioned within the tab bar."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(alignment) for alignment in ft.TabAlignment], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare how tabs are positioned within the tab bar."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(alignment) for alignment in ft.TabAlignment + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/tab_alignment/showcase/pyproject.toml b/sdk/python/examples/controls/types/tab_alignment/showcase/pyproject.toml new file mode 100644 index 0000000000..05fabd4b47 --- /dev/null +++ b/sdk/python/examples/controls/types/tab_alignment/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tab-alignment-showcase" +version = "1.0.0" +description = "Compares Tab Alignment values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["tab alignment", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Navigation/Tabs"] + +[tool.flet.metadata] +title = "Tab Alignment showcase" +controls = ["SafeArea", "Column", "Container", "TabBar", "Tab", "TabBarView", "Text", "Tabs"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/tab_bar_indicator_size/showcase.py b/sdk/python/examples/controls/types/tab_bar_indicator_size/showcase/main.py similarity index 68% rename from sdk/python/examples/controls/types/tab_bar_indicator_size/showcase.py rename to sdk/python/examples/controls/types/tab_bar_indicator_size/showcase/main.py index 75fc094ff7..76b09a4ba7 100644 --- a/sdk/python/examples/controls/types/tab_bar_indicator_size/showcase.py +++ b/sdk/python/examples/controls/types/tab_bar_indicator_size/showcase/main.py @@ -59,19 +59,29 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="TabBarIndicatorSize Showcase") page.add( - ft.Text("Compare indicator width when matching tab bounds vs label bounds."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(indicator_size) - for indicator_size in ft.TabBarIndicatorSize - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare indicator width when matching tab bounds vs " + "label bounds." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(indicator_size) + for indicator_size in ft.TabBarIndicatorSize + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/tab_bar_indicator_size/showcase/pyproject.toml b/sdk/python/examples/controls/types/tab_bar_indicator_size/showcase/pyproject.toml new file mode 100644 index 0000000000..0c37e1c753 --- /dev/null +++ b/sdk/python/examples/controls/types/tab_bar_indicator_size/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tab-bar-indicator-size-showcase" +version = "1.0.0" +description = "Compares Tab Bar Indicator Size values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["tab bar indicator size", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Navigation/Tabs"] + +[tool.flet.metadata] +title = "Tab Bar Indicator Size showcase" +controls = ["SafeArea", "Column", "Container", "TabBar", "UnderlineTabIndicator", "Tab", "TabBarView", "Text"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/tab_indicator_animation/showcase.py b/sdk/python/examples/controls/types/tab_indicator_animation/showcase/main.py similarity index 70% rename from sdk/python/examples/controls/types/tab_indicator_animation/showcase.py rename to sdk/python/examples/controls/types/tab_indicator_animation/showcase/main.py index a81654df91..cd4faea466 100644 --- a/sdk/python/examples/controls/types/tab_indicator_animation/showcase.py +++ b/sdk/python/examples/controls/types/tab_indicator_animation/showcase/main.py @@ -59,18 +59,26 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="TabIndicatorAnimation Showcase") page.add( - ft.Text("Click tabs to compare indicator movement animation."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(animation) for animation in ft.TabIndicatorAnimation - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Click tabs to compare indicator movement animation."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(animation) + for animation in ft.TabIndicatorAnimation + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/tab_indicator_animation/showcase/pyproject.toml b/sdk/python/examples/controls/types/tab_indicator_animation/showcase/pyproject.toml new file mode 100644 index 0000000000..9e38d6dda5 --- /dev/null +++ b/sdk/python/examples/controls/types/tab_indicator_animation/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tab-indicator-animation-showcase" +version = "1.0.0" +description = "Compares Tab Indicator Animation values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["tab indicator animation", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Navigation/Tabs"] + +[tool.flet.metadata] +title = "Tab Indicator Animation showcase" +controls = ["SafeArea", "Column", "Container", "TabBar", "UnderlineTabIndicator", "Tab", "TabBarView", "Text"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/text_align/showcase.py b/sdk/python/examples/controls/types/text_align/showcase/main.py similarity index 59% rename from sdk/python/examples/controls/types/text_align/showcase.py rename to sdk/python/examples/controls/types/text_align/showcase/main.py index 4ade0fc511..5ecc9fdfba 100644 --- a/sdk/python/examples/controls/types/text_align/showcase.py +++ b/sdk/python/examples/controls/types/text_align/showcase/main.py @@ -34,16 +34,28 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="TextAlign Showcase") page.add( - ft.Text("Compare horizontal text alignment modes in the same text block."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(text_align) for text_align in ft.TextAlign], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare horizontal text alignment modes in the same " + "text block." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(text_align) for text_align in ft.TextAlign + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/text_align/showcase/pyproject.toml b/sdk/python/examples/controls/types/text_align/showcase/pyproject.toml new file mode 100644 index 0000000000..a11ba3fea4 --- /dev/null +++ b/sdk/python/examples/controls/types/text_align/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-text-align-showcase" +version = "1.0.0" +description = "Compares Text Align values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["text align", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Text Align showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/text_capitalization/showcase.py b/sdk/python/examples/controls/types/text_capitalization/showcase/main.py similarity index 54% rename from sdk/python/examples/controls/types/text_capitalization/showcase.py rename to sdk/python/examples/controls/types/text_capitalization/showcase/main.py index f3988cc0e1..c0679c974a 100644 --- a/sdk/python/examples/controls/types/text_capitalization/showcase.py +++ b/sdk/python/examples/controls/types/text_capitalization/showcase/main.py @@ -30,16 +30,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="TextCapitalization Showcase") page.add( - ft.Text("Compare keyboard capitalization preferences for text fields."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(c) for c in ft.TextCapitalization], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare keyboard capitalization preferences for text fields." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(c) for c in ft.TextCapitalization], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/text_capitalization/showcase/pyproject.toml b/sdk/python/examples/controls/types/text_capitalization/showcase/pyproject.toml new file mode 100644 index 0000000000..d9f09d775c --- /dev/null +++ b/sdk/python/examples/controls/types/text_capitalization/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-text-capitalization-showcase" +version = "1.0.0" +description = "Compares Text Capitalization values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["text capitalization", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Text Capitalization showcase" +controls = ["SafeArea", "Column", "Container", "TextField", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/text_decoration_style/showcase.py b/sdk/python/examples/controls/types/text_decoration_style/showcase/main.py similarity index 67% rename from sdk/python/examples/controls/types/text_decoration_style/showcase.py rename to sdk/python/examples/controls/types/text_decoration_style/showcase/main.py index c67aa2cb00..fea90b1a74 100644 --- a/sdk/python/examples/controls/types/text_decoration_style/showcase.py +++ b/sdk/python/examples/controls/types/text_decoration_style/showcase/main.py @@ -40,16 +40,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="TextDecorationStyle Showcase") page.add( - ft.Text("Compare underline rendering for each decoration style."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(style) for style in ft.TextDecorationStyle], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare underline rendering for each decoration style."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(style) for style in ft.TextDecorationStyle + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/text_decoration_style/showcase/pyproject.toml b/sdk/python/examples/controls/types/text_decoration_style/showcase/pyproject.toml new file mode 100644 index 0000000000..9f639038e5 --- /dev/null +++ b/sdk/python/examples/controls/types/text_decoration_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-text-decoration-style-showcase" +version = "1.0.0" +description = "Compares Text Decoration Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["text decoration style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Text Decoration Style showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/text_overflow/showcase.py b/sdk/python/examples/controls/types/text_overflow/showcase/main.py similarity index 61% rename from sdk/python/examples/controls/types/text_overflow/showcase.py rename to sdk/python/examples/controls/types/text_overflow/showcase/main.py index 55e2ecdee7..461c94e0dc 100644 --- a/sdk/python/examples/controls/types/text_overflow/showcase.py +++ b/sdk/python/examples/controls/types/text_overflow/showcase/main.py @@ -35,16 +35,27 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="TextOverflow Showcase") page.add( - ft.Text("Compare how one-line text behaves when content exceeds width."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(overflow) for overflow in ft.TextOverflow], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how one-line text behaves when content exceeds width." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(overflow) for overflow in ft.TextOverflow + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/text_overflow/showcase/pyproject.toml b/sdk/python/examples/controls/types/text_overflow/showcase/pyproject.toml new file mode 100644 index 0000000000..45827b6df9 --- /dev/null +++ b/sdk/python/examples/controls/types/text_overflow/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-text-overflow-showcase" +version = "1.0.0" +description = "Compares Text Overflow values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["text overflow", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Text Overflow showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/theme_mode/showcase.py b/sdk/python/examples/controls/types/theme_mode/showcase.py deleted file mode 100644 index 75b9913f98..0000000000 --- a/sdk/python/examples/controls/types/theme_mode/showcase.py +++ /dev/null @@ -1,63 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.SYSTEM - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def apply_theme_mode(theme_mode: ft.ThemeMode): - page.theme_mode = theme_mode - status.value = f"Active mode: {theme_mode.name}" - page.update() - - def showcase_card(theme_mode: ft.ThemeMode) -> ft.Container: - return ft.Container( - width=250, - padding=12, - border=ft.Border.all(1, ft.Colors.RED), - border_radius=10, - bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, - content=ft.Column( - spacing=8, - controls=[ - ft.Text(theme_mode.name, weight=ft.FontWeight.BOLD), - ft.Button( - "Apply", - on_click=lambda _, m=theme_mode: apply_theme_mode(m), - ), - ], - ), - ) - - page.appbar = ft.AppBar(title="ThemeMode Showcase") - page.add( - ft.Text("Switch the app theme mode and inspect the preview below."), - status := ft.Text(f"Active mode: {page.theme_mode.name}"), - ft.Container( - width=500, - padding=12, - border=ft.Border.all(1, ft.Colors.OUTLINE), - border_radius=10, - content=ft.Row( - alignment=ft.MainAxisAlignment.SPACE_AROUND, - controls=[ - ft.OutlinedButton("Outlined"), - ft.FilledButton("Filled"), - ft.Switch(label="Switch", value=True), - ], - ), - ), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(theme_mode) for theme_mode in ft.ThemeMode], - ), - ) - - apply_theme_mode(ft.ThemeMode.SYSTEM) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/theme_mode/showcase/main.py b/sdk/python/examples/controls/types/theme_mode/showcase/main.py new file mode 100644 index 0000000000..8534532bdd --- /dev/null +++ b/sdk/python/examples/controls/types/theme_mode/showcase/main.py @@ -0,0 +1,72 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.SYSTEM + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def apply_theme_mode(theme_mode: ft.ThemeMode): + page.theme_mode = theme_mode + status.value = f"Active mode: {theme_mode.name}" + page.update() + + def showcase_card(theme_mode: ft.ThemeMode) -> ft.Container: + return ft.Container( + width=250, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(theme_mode.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Apply", + on_click=lambda _, m=theme_mode: apply_theme_mode(m), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="ThemeMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Switch the app theme mode and inspect the preview below."), + status := ft.Text(f"Active mode: {page.theme_mode.name}"), + ft.Container( + width=500, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=10, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.OutlinedButton("Outlined"), + ft.FilledButton("Filled"), + ft.Switch(label="Switch", value=True), + ], + ), + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(theme_mode) for theme_mode in ft.ThemeMode + ], + ), + ], + ), + ) + ) + + apply_theme_mode(ft.ThemeMode.SYSTEM) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/theme_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/theme_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..0557b5ccac --- /dev/null +++ b/sdk/python/examples/controls/types/theme_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-theme-mode-showcase" +version = "1.0.0" +description = "Compares Theme Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["theme mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Theme Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Button", "AppBar", "Row", "OutlinedButton"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/tile_affinity/showcase.py b/sdk/python/examples/controls/types/tile_affinity/showcase/main.py similarity index 58% rename from sdk/python/examples/controls/types/tile_affinity/showcase.py rename to sdk/python/examples/controls/types/tile_affinity/showcase/main.py index 90c0d5c351..2ae4ca3e84 100644 --- a/sdk/python/examples/controls/types/tile_affinity/showcase.py +++ b/sdk/python/examples/controls/types/tile_affinity/showcase/main.py @@ -34,16 +34,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="TileAffinity Showcase") page.add( - ft.Text("Compare expand-arrow placement in ExpansionTile."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(affinity) for affinity in ft.TileAffinity], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare expand-arrow placement in ExpansionTile."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(affinity) for affinity in ft.TileAffinity + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/tile_affinity/showcase/pyproject.toml b/sdk/python/examples/controls/types/tile_affinity/showcase/pyproject.toml new file mode 100644 index 0000000000..70c6f3b9af --- /dev/null +++ b/sdk/python/examples/controls/types/tile_affinity/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tile-affinity-showcase" +version = "1.0.0" +description = "Compares Tile Affinity values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["tile affinity", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Tile Affinity showcase" +controls = ["SafeArea", "Column", "Container", "ExpansionTile", "ListTile", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/time_picker_entry_mode/showcase.py b/sdk/python/examples/controls/types/time_picker_entry_mode/showcase/main.py similarity index 64% rename from sdk/python/examples/controls/types/time_picker_entry_mode/showcase.py rename to sdk/python/examples/controls/types/time_picker_entry_mode/showcase/main.py index 7f13ac974b..702e7e9d80 100644 --- a/sdk/python/examples/controls/types/time_picker_entry_mode/showcase.py +++ b/sdk/python/examples/controls/types/time_picker_entry_mode/showcase/main.py @@ -34,16 +34,23 @@ def showcase_card(entry_mode: ft.TimePickerEntryMode) -> ft.Container: page.appbar = ft.AppBar(title="TimePickerEntryMode Showcase") page.add( - ft.Text("Open the picker to compare dial/input entry modes."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(m) for m in ft.TimePickerEntryMode], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Open the picker to compare dial/input entry modes."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(m) for m in ft.TimePickerEntryMode], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/time_picker_entry_mode/showcase/pyproject.toml b/sdk/python/examples/controls/types/time_picker_entry_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..c12e5cc6a0 --- /dev/null +++ b/sdk/python/examples/controls/types/time_picker_entry_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-time-picker-entry-mode-showcase" +version = "1.0.0" +description = "Compares Time Picker Entry Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["time picker entry mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Time Picker Entry Mode showcase" +controls = ["SafeArea", "Column", "TimePicker", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/time_picker_hour_format/showcase.py b/sdk/python/examples/controls/types/time_picker_hour_format/showcase/main.py similarity index 62% rename from sdk/python/examples/controls/types/time_picker_hour_format/showcase.py rename to sdk/python/examples/controls/types/time_picker_hour_format/showcase/main.py index de4b77318d..7fe31551b1 100644 --- a/sdk/python/examples/controls/types/time_picker_hour_format/showcase.py +++ b/sdk/python/examples/controls/types/time_picker_hour_format/showcase/main.py @@ -37,18 +37,26 @@ def showcase_card(hour_format: ft.TimePickerHourFormat) -> ft.Container: page.appbar = ft.AppBar(title="TimePickerHourFormat Showcase") page.add( - ft.Text("Open the picker to compare 12h, 24h, and system modes."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[ - showcase_card(hour_format) for hour_format in ft.TimePickerHourFormat - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Open the picker to compare 12h, 24h, and system modes."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(hour_format) + for hour_format in ft.TimePickerHourFormat + ], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/time_picker_hour_format/showcase/pyproject.toml b/sdk/python/examples/controls/types/time_picker_hour_format/showcase/pyproject.toml new file mode 100644 index 0000000000..37c6ed004c --- /dev/null +++ b/sdk/python/examples/controls/types/time_picker_hour_format/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-time-picker-hour-format-showcase" +version = "1.0.0" +description = "Compares Time Picker Hour Format values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["time picker hour format", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Time Picker Hour Format showcase" +controls = ["SafeArea", "Column", "TimePicker", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/tooltip/with_decoration.py b/sdk/python/examples/controls/types/tooltip/with_decoration.py deleted file mode 100644 index dc035b81ca..0000000000 --- a/sdk/python/examples/controls/types/tooltip/with_decoration.py +++ /dev/null @@ -1,39 +0,0 @@ -import math - -import flet as ft - - -def main(page: ft.Page): - page.add( - ft.Text("Hover to see the simple tooltip", tooltip="This is a simple tooltip"), - ft.Text( - value="Hover to see the complex tooltip", - tooltip=ft.Tooltip( - message="This is a complex tooltip", - padding=20, - text_style=ft.TextStyle(size=20, color=ft.Colors.WHITE), - decoration=ft.BoxDecoration( - border_radius=10, - gradient=ft.LinearGradient( - begin=ft.Alignment.TOP_LEFT, - end=ft.Alignment(0.8, 1), - tile_mode=ft.GradientTileMode.MIRROR, - rotation=math.pi / 3, - colors=[ - "0xff1f005c", - "0xff5b0060", - "0xff870160", - "0xffac255e", - "0xffca485c", - "0xffe16b5c", - "0xfff39060", - "0xffffb56b", - ], - ), - ), - ), - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/tooltip/with_decoration/main.py b/sdk/python/examples/controls/types/tooltip/with_decoration/main.py new file mode 100644 index 0000000000..0aa6566bc5 --- /dev/null +++ b/sdk/python/examples/controls/types/tooltip/with_decoration/main.py @@ -0,0 +1,49 @@ +import math + +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Hover to see the simple tooltip", + tooltip="This is a simple tooltip", + ), + ft.Text( + value="Hover to see the complex tooltip", + tooltip=ft.Tooltip( + message="This is a complex tooltip", + padding=20, + text_style=ft.TextStyle(size=20, color=ft.Colors.WHITE), + decoration=ft.BoxDecoration( + border_radius=10, + gradient=ft.LinearGradient( + begin=ft.Alignment.TOP_LEFT, + end=ft.Alignment(0.8, 1), + tile_mode=ft.GradientTileMode.MIRROR, + rotation=math.pi / 3, + colors=[ + "0xff1f005c", + "0xff5b0060", + "0xff870160", + "0xffac255e", + "0xffca485c", + "0xffe16b5c", + "0xfff39060", + "0xffffb56b", + ], + ), + ), + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/tooltip/with_decoration/pyproject.toml b/sdk/python/examples/controls/types/tooltip/with_decoration/pyproject.toml new file mode 100644 index 0000000000..00c209a71e --- /dev/null +++ b/sdk/python/examples/controls/types/tooltip/with_decoration/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tooltip-with-decoration" +version = "1.0.0" +description = "Shows simple and decorated tooltips with custom gradient styling." +requires-python = ">=3.10" +keywords = ["tooltip", "with decoration"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Displays/Tooltip"] + +[tool.flet.metadata] +title = "Tooltip with decoration" +controls = ["SafeArea", "Column", "Text", "Tooltip", "BoxDecoration"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["tooltip styling", "gradient decoration"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/url_target/showcase.py b/sdk/python/examples/controls/types/url_target/showcase/main.py similarity index 63% rename from sdk/python/examples/controls/types/url_target/showcase.py rename to sdk/python/examples/controls/types/url_target/showcase/main.py index 979c826adb..f77405a13e 100644 --- a/sdk/python/examples/controls/types/url_target/showcase.py +++ b/sdk/python/examples/controls/types/url_target/showcase/main.py @@ -33,17 +33,26 @@ def showcase_card(target: ft.UrlTarget) -> ft.Container: page.appbar = ft.AppBar(title="UrlTarget Showcase") page.add( - ft.Text("Click a card to launch URL with the selected browser target."), - status := ft.Text(), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[showcase_card(target) for target in ft.UrlTarget], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Click a card to launch URL with the selected browser target." + ), + status := ft.Text(), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(target) for target in ft.UrlTarget], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/url_target/showcase/pyproject.toml b/sdk/python/examples/controls/types/url_target/showcase/pyproject.toml new file mode 100644 index 0000000000..d887d3879f --- /dev/null +++ b/sdk/python/examples/controls/types/url_target/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-url-target-showcase" +version = "1.0.0" +description = "Compares URL Target values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["url target", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "URL Target showcase" +controls = ["SafeArea", "Column", "UrlLauncher", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/visual_density/showcase.py b/sdk/python/examples/controls/types/visual_density/showcase/main.py similarity index 66% rename from sdk/python/examples/controls/types/visual_density/showcase.py rename to sdk/python/examples/controls/types/visual_density/showcase/main.py index 6f26af3a78..e95d06311e 100644 --- a/sdk/python/examples/controls/types/visual_density/showcase.py +++ b/sdk/python/examples/controls/types/visual_density/showcase/main.py @@ -38,16 +38,25 @@ def main(page: ft.Page): page.appbar = ft.AppBar(title="VisualDensity Showcase") page.add( - ft.Text("Compare component density presets across Material controls."), - ft.Row( - wrap=True, - spacing=12, - expand=True, - scroll=ft.ScrollMode.AUTO, - alignment=ft.MainAxisAlignment.CENTER, - controls=[density_card(vd) for vd in ft.VisualDensity], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare component density presets across Material controls." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[density_card(vd) for vd in ft.VisualDensity], + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/visual_density/showcase/pyproject.toml b/sdk/python/examples/controls/types/visual_density/showcase/pyproject.toml new file mode 100644 index 0000000000..9304ed08ae --- /dev/null +++ b/sdk/python/examples/controls/types/visual_density/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-visual-density-showcase" +version = "1.0.0" +description = "Compares Visual Density values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["visual density", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Visual Density showcase" +controls = ["SafeArea", "Column", "Container", "Theme", "Text", "IconButton", "Checkbox", "Chip"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/types/window_event_type/showcase.py b/sdk/python/examples/controls/types/window_event_type/showcase.py deleted file mode 100644 index c6a4584a7b..0000000000 --- a/sdk/python/examples/controls/types/window_event_type/showcase.py +++ /dev/null @@ -1,55 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - log = ft.Column( - spacing=4, - scroll=ft.ScrollMode.AUTO, - height=220, - ) - - def add_log(message: str): - log.controls.insert(0, ft.Text(message, size=12)) - if len(log.controls) > 20: - log.controls.pop() - log.update() - - def on_window_event(e: ft.WindowEvent): - add_log(f"Received: {e.type.name}") - - page.window.on_event = on_window_event - - page.appbar = ft.AppBar(title="WindowEventType Showcase") - page.add( - ft.Text("Interact with the app window and watch incoming event types."), - ft.Text( - "Desktop only. Try focus, blur, resize, move, minimize, maximize.", - size=11, - ), - ft.Row( - wrap=True, - spacing=8, - controls=[ - ft.Container( - padding=ft.Padding.symmetric(horizontal=8, vertical=4), - border=ft.Border.all(1, ft.Colors.OUTLINE), - border_radius=12, - content=ft.Text(event_type.name, size=11), - ) - for event_type in ft.WindowEventType - ], - ), - ft.Container( - width=720, - padding=12, - border=ft.Border.all(1, ft.Colors.RED), - border_radius=10, - bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, - content=log, - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/controls/types/window_event_type/showcase/main.py b/sdk/python/examples/controls/types/window_event_type/showcase/main.py new file mode 100644 index 0000000000..f55feb9479 --- /dev/null +++ b/sdk/python/examples/controls/types/window_event_type/showcase/main.py @@ -0,0 +1,65 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + log = ft.Column( + spacing=4, + scroll=ft.ScrollMode.AUTO, + height=220, + ) + + def add_log(message: str): + log.controls.insert(0, ft.Text(message, size=12)) + if len(log.controls) > 20: + log.controls.pop() + log.update() + + def on_window_event(e: ft.WindowEvent): + add_log(f"Received: {e.type.name}") + + page.window.on_event = on_window_event + + page.appbar = ft.AppBar(title="WindowEventType Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Interact with the app window and watch incoming event types." + ), + ft.Text( + "Desktop only. Try focus, blur, resize, move, " + "minimize, maximize.", + size=11, + ), + ft.Row( + wrap=True, + spacing=8, + controls=[ + ft.Container( + padding=ft.Padding.symmetric(horizontal=8, vertical=4), + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=12, + content=ft.Text(event_type.name, size=11), + ) + for event_type in ft.WindowEventType + ], + ), + ft.Container( + width=720, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=log, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/types/window_event_type/showcase/pyproject.toml b/sdk/python/examples/controls/types/window_event_type/showcase/pyproject.toml new file mode 100644 index 0000000000..fb22960c3e --- /dev/null +++ b/sdk/python/examples/controls/types/window_event_type/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-window-event-type-showcase" +version = "1.0.0" +description = "Compares Window Event Type values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["window event type", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types", "Layout/Container"] + +[tool.flet.metadata] +title = "Window Event Type showcase" +controls = ["SafeArea", "Column", "Text", "AppBar", "Row", "Container"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/types/animatedswitchertransition.md b/sdk/python/packages/flet/docs/types/animatedswitchertransition.md index 1be795d167..a7ec5b96c4 100644 --- a/sdk/python/packages/flet/docs/types/animatedswitchertransition.md +++ b/sdk/python/packages/flet/docs/types/animatedswitchertransition.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/animated_switcher_transition ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/animationcurve.md b/sdk/python/packages/flet/docs/types/animationcurve.md index 2013613b55..8ee3fe6763 100644 --- a/sdk/python/packages/flet/docs/types/animationcurve.md +++ b/sdk/python/packages/flet/docs/types/animationcurve.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/animation_curve ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/applifecyclestate.md b/sdk/python/packages/flet/docs/types/applifecyclestate.md index 4f7fabec72..b54a534f0e 100644 --- a/sdk/python/packages/flet/docs/types/applifecyclestate.md +++ b/sdk/python/packages/flet/docs/types/applifecyclestate.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/app_lifecycle_state ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/assertiveness.md b/sdk/python/packages/flet/docs/types/assertiveness.md index dfd5651bb2..a39f75fc8a 100644 --- a/sdk/python/packages/flet/docs/types/assertiveness.md +++ b/sdk/python/packages/flet/docs/types/assertiveness.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/assertiveness ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/axis.md b/sdk/python/packages/flet/docs/types/axis.md index b9a614f653..f3a670387a 100644 --- a/sdk/python/packages/flet/docs/types/axis.md +++ b/sdk/python/packages/flet/docs/types/axis.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/axis ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/blendmode.md b/sdk/python/packages/flet/docs/types/blendmode.md index 1236800fc5..47bda18f35 100644 --- a/sdk/python/packages/flet/docs/types/blendmode.md +++ b/sdk/python/packages/flet/docs/types/blendmode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/blend_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/blur.md b/sdk/python/packages/flet/docs/types/blur.md index 38c2321494..e94da2118d 100644 --- a/sdk/python/packages/flet/docs/types/blur.md +++ b/sdk/python/packages/flet/docs/types/blur.md @@ -5,7 +5,7 @@ ### Example 1 ```python ---8<-- "../../examples/controls/types/blur/container.py" +--8<-- "../../examples/controls/types/blur/container/main.py" ``` {{ image("../examples/controls/types/blur/media/container.gif", alt="container", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/blurstyle.md b/sdk/python/packages/flet/docs/types/blurstyle.md index daa337dc6c..90ebe5c32c 100644 --- a/sdk/python/packages/flet/docs/types/blurstyle.md +++ b/sdk/python/packages/flet/docs/types/blurstyle.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/blur_style ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/blurtilemode.md b/sdk/python/packages/flet/docs/types/blurtilemode.md index 509457fb85..96b7d9e9e9 100644 --- a/sdk/python/packages/flet/docs/types/blurtilemode.md +++ b/sdk/python/packages/flet/docs/types/blurtilemode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/blur_tile_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/border.md b/sdk/python/packages/flet/docs/types/border.md index 8bc6a847b3..a5b196f347 100644 --- a/sdk/python/packages/flet/docs/types/border.md +++ b/sdk/python/packages/flet/docs/types/border.md @@ -5,5 +5,5 @@ ### Example 1 ```python ---8<-- "../../examples/controls/types/border/container.py" +--8<-- "../../examples/controls/types/border/container/main.py" ``` diff --git a/sdk/python/packages/flet/docs/types/bordersidestrokealign.md b/sdk/python/packages/flet/docs/types/bordersidestrokealign.md index c50b49ac0b..dcbf39cb6f 100644 --- a/sdk/python/packages/flet/docs/types/bordersidestrokealign.md +++ b/sdk/python/packages/flet/docs/types/bordersidestrokealign.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/border_side_stroke_align ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/borderstyle.md b/sdk/python/packages/flet/docs/types/borderstyle.md index 246a764187..ebb02e4c4c 100644 --- a/sdk/python/packages/flet/docs/types/borderstyle.md +++ b/sdk/python/packages/flet/docs/types/borderstyle.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/border_style ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/boxfit.md b/sdk/python/packages/flet/docs/types/boxfit.md index 1677b6a5f1..c3e0f4dbee 100644 --- a/sdk/python/packages/flet/docs/types/boxfit.md +++ b/sdk/python/packages/flet/docs/types/boxfit.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/box_fit ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/boxshadow.md b/sdk/python/packages/flet/docs/types/boxshadow.md index 45d22447ba..588a778eb6 100644 --- a/sdk/python/packages/flet/docs/types/boxshadow.md +++ b/sdk/python/packages/flet/docs/types/boxshadow.md @@ -5,5 +5,5 @@ ### Example 1 ```python ---8<-- "../../examples/controls/types/box_shadow/container.py" +--8<-- "../../examples/controls/types/box_shadow/container/main.py" ``` diff --git a/sdk/python/packages/flet/docs/types/boxshape.md b/sdk/python/packages/flet/docs/types/boxshape.md index ad9c31da6b..d7e576d895 100644 --- a/sdk/python/packages/flet/docs/types/boxshape.md +++ b/sdk/python/packages/flet/docs/types/boxshape.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/box_shape ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/cardvariant.md b/sdk/python/packages/flet/docs/types/cardvariant.md index a81ecd0b56..7b6be41335 100644 --- a/sdk/python/packages/flet/docs/types/cardvariant.md +++ b/sdk/python/packages/flet/docs/types/cardvariant.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/card_variant ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/clipbehavior.md b/sdk/python/packages/flet/docs/types/clipbehavior.md index 4449b82a89..6d7d6a9f0e 100644 --- a/sdk/python/packages/flet/docs/types/clipbehavior.md +++ b/sdk/python/packages/flet/docs/types/clipbehavior.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/clip_behavior ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/contextmenutrigger.md b/sdk/python/packages/flet/docs/types/contextmenutrigger.md index d02b4a7fe5..371cedcc91 100644 --- a/sdk/python/packages/flet/docs/types/contextmenutrigger.md +++ b/sdk/python/packages/flet/docs/types/contextmenutrigger.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/context_menu_trigger ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/crossaxisalignment.md b/sdk/python/packages/flet/docs/types/crossaxisalignment.md index 6a823f189c..891b3566c2 100644 --- a/sdk/python/packages/flet/docs/types/crossaxisalignment.md +++ b/sdk/python/packages/flet/docs/types/crossaxisalignment.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/cross_axis_alignment ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/cupertinobuttonsize.md b/sdk/python/packages/flet/docs/types/cupertinobuttonsize.md index acb9798760..213d344aa6 100644 --- a/sdk/python/packages/flet/docs/types/cupertinobuttonsize.md +++ b/sdk/python/packages/flet/docs/types/cupertinobuttonsize.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/cupertino_button_size ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/cupertinodatepickerdateorder.md b/sdk/python/packages/flet/docs/types/cupertinodatepickerdateorder.md index 13af23f92b..e0c8a83155 100644 --- a/sdk/python/packages/flet/docs/types/cupertinodatepickerdateorder.md +++ b/sdk/python/packages/flet/docs/types/cupertinodatepickerdateorder.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/cupertino_date_picker_date_order ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/cupertinodatepickermode.md b/sdk/python/packages/flet/docs/types/cupertinodatepickermode.md index 522295bba7..27a24f61cd 100644 --- a/sdk/python/packages/flet/docs/types/cupertinodatepickermode.md +++ b/sdk/python/packages/flet/docs/types/cupertinodatepickermode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/cupertino_date_picker_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/cupertinotimerpickermode.md b/sdk/python/packages/flet/docs/types/cupertinotimerpickermode.md index 237661c671..c743b4ba91 100644 --- a/sdk/python/packages/flet/docs/types/cupertinotimerpickermode.md +++ b/sdk/python/packages/flet/docs/types/cupertinotimerpickermode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/cupertino_timer_picker_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/datepickerentrymode.md b/sdk/python/packages/flet/docs/types/datepickerentrymode.md index 196e9aa504..245c360314 100644 --- a/sdk/python/packages/flet/docs/types/datepickerentrymode.md +++ b/sdk/python/packages/flet/docs/types/datepickerentrymode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/date_picker_entry_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/datepickermode.md b/sdk/python/packages/flet/docs/types/datepickermode.md index fdbb8d1710..dbcb6b07e1 100644 --- a/sdk/python/packages/flet/docs/types/datepickermode.md +++ b/sdk/python/packages/flet/docs/types/datepickermode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/date_picker_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/dismissdirection.md b/sdk/python/packages/flet/docs/types/dismissdirection.md index a3e082b489..a928606dff 100644 --- a/sdk/python/packages/flet/docs/types/dismissdirection.md +++ b/sdk/python/packages/flet/docs/types/dismissdirection.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/dismiss_direction ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/filterquality.md b/sdk/python/packages/flet/docs/types/filterquality.md index 6a6795dde8..7686c380c2 100644 --- a/sdk/python/packages/flet/docs/types/filterquality.md +++ b/sdk/python/packages/flet/docs/types/filterquality.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/filter_quality ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/floatingactionbuttonlocation.md b/sdk/python/packages/flet/docs/types/floatingactionbuttonlocation.md index 71f82e30b2..fd258d0fea 100644 --- a/sdk/python/packages/flet/docs/types/floatingactionbuttonlocation.md +++ b/sdk/python/packages/flet/docs/types/floatingactionbuttonlocation.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/floating_action_button_location ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/fontweight.md b/sdk/python/packages/flet/docs/types/fontweight.md index b12002695c..24aa3ef6f8 100644 --- a/sdk/python/packages/flet/docs/types/fontweight.md +++ b/sdk/python/packages/flet/docs/types/fontweight.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/font_weight ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/gradient/index.md b/sdk/python/packages/flet/docs/types/gradient/index.md index f1c652e0f9..33a14ad41c 100644 --- a/sdk/python/packages/flet/docs/types/gradient/index.md +++ b/sdk/python/packages/flet/docs/types/gradient/index.md @@ -5,5 +5,5 @@ ### Containers with gradients ```python ---8<-- "../../examples/controls/types/gradient/container.py" +--8<-- "../../examples/controls/types/gradient/container/main.py" ``` diff --git a/sdk/python/packages/flet/docs/types/gradienttilemode.md b/sdk/python/packages/flet/docs/types/gradienttilemode.md index d2d2cd169f..473eb2a945 100644 --- a/sdk/python/packages/flet/docs/types/gradienttilemode.md +++ b/sdk/python/packages/flet/docs/types/gradienttilemode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/gradient_tile_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/imagerepeat.md b/sdk/python/packages/flet/docs/types/imagerepeat.md index ec56b99715..8ea9197213 100644 --- a/sdk/python/packages/flet/docs/types/imagerepeat.md +++ b/sdk/python/packages/flet/docs/types/imagerepeat.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/image_repeat ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/labelposition.md b/sdk/python/packages/flet/docs/types/labelposition.md index f11d4c90dc..570819cd38 100644 --- a/sdk/python/packages/flet/docs/types/labelposition.md +++ b/sdk/python/packages/flet/docs/types/labelposition.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/label_position ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/launchmode.md b/sdk/python/packages/flet/docs/types/launchmode.md index eae14c3c9d..d608d40dfa 100644 --- a/sdk/python/packages/flet/docs/types/launchmode.md +++ b/sdk/python/packages/flet/docs/types/launchmode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/launch_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/lineargradient.md b/sdk/python/packages/flet/docs/types/lineargradient.md index 5ac84b9b98..5887f9c23e 100644 --- a/sdk/python/packages/flet/docs/types/lineargradient.md +++ b/sdk/python/packages/flet/docs/types/lineargradient.md @@ -5,7 +5,7 @@ ### Container with linear gradient ```python ---8<-- "../../examples/controls/types/gradient/linear_gradient/container.py" +--8<-- "../../examples/controls/types/gradient/linear_gradient/container/main.py" ``` {{ image("../examples/controls/types/gradient/linear_gradient/media/container.png", alt="container", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/listtilestyle.md b/sdk/python/packages/flet/docs/types/listtilestyle.md index 0100694017..98731f89c7 100644 --- a/sdk/python/packages/flet/docs/types/listtilestyle.md +++ b/sdk/python/packages/flet/docs/types/listtilestyle.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/list_tile_style ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/listtiletitlealignment.md b/sdk/python/packages/flet/docs/types/listtiletitlealignment.md index 2b1c888e98..b596a3c297 100644 --- a/sdk/python/packages/flet/docs/types/listtiletitlealignment.md +++ b/sdk/python/packages/flet/docs/types/listtiletitlealignment.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/list_tile_title_alignment ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/mainaxisalignment.md b/sdk/python/packages/flet/docs/types/mainaxisalignment.md index 97c4a07042..662451729c 100644 --- a/sdk/python/packages/flet/docs/types/mainaxisalignment.md +++ b/sdk/python/packages/flet/docs/types/mainaxisalignment.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/main_axis_alignment ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/margin.md b/sdk/python/packages/flet/docs/types/margin.md index b86381f051..bcca7b5d85 100644 --- a/sdk/python/packages/flet/docs/types/margin.md +++ b/sdk/python/packages/flet/docs/types/margin.md @@ -5,5 +5,5 @@ ### Example 1 ```python ---8<-- "../../examples/controls/types/margin/container.py" +--8<-- "../../examples/controls/types/margin/container/main.py" ``` diff --git a/sdk/python/packages/flet/docs/types/mousecursor.md b/sdk/python/packages/flet/docs/types/mousecursor.md index 377a886920..9a43481805 100644 --- a/sdk/python/packages/flet/docs/types/mousecursor.md +++ b/sdk/python/packages/flet/docs/types/mousecursor.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/mouse_cursor ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/navigationbarlabelbehavior.md b/sdk/python/packages/flet/docs/types/navigationbarlabelbehavior.md index bcdccb4e2b..6b7503f839 100644 --- a/sdk/python/packages/flet/docs/types/navigationbarlabelbehavior.md +++ b/sdk/python/packages/flet/docs/types/navigationbarlabelbehavior.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/navigation_bar_label_behavior ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/navigationraillabeltype.md b/sdk/python/packages/flet/docs/types/navigationraillabeltype.md index 7e62d73ede..9667db4552 100644 --- a/sdk/python/packages/flet/docs/types/navigationraillabeltype.md +++ b/sdk/python/packages/flet/docs/types/navigationraillabeltype.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/navigation_rail_label_type ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/orientation.md b/sdk/python/packages/flet/docs/types/orientation.md index 44854abade..e3c2a8341e 100644 --- a/sdk/python/packages/flet/docs/types/orientation.md +++ b/sdk/python/packages/flet/docs/types/orientation.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/orientation ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/overlayvisibilitymode.md b/sdk/python/packages/flet/docs/types/overlayvisibilitymode.md index c462b4a08f..a3e3fcfc98 100644 --- a/sdk/python/packages/flet/docs/types/overlayvisibilitymode.md +++ b/sdk/python/packages/flet/docs/types/overlayvisibilitymode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/overlay_visibility_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/padding.md b/sdk/python/packages/flet/docs/types/padding.md index d7365d43dd..e6ec8c3a06 100644 --- a/sdk/python/packages/flet/docs/types/padding.md +++ b/sdk/python/packages/flet/docs/types/padding.md @@ -5,7 +5,7 @@ ### Example 1 ```python ---8<-- "../../examples/controls/types/padding/container.py" +--8<-- "../../examples/controls/types/padding/container/main.py" ``` {{ image("../examples/controls/types/padding/media/container.png", alt="container", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/paintgradient/index.md b/sdk/python/packages/flet/docs/types/paintgradient/index.md index c5a8337be7..4e96cc86c1 100644 --- a/sdk/python/packages/flet/docs/types/paintgradient/index.md +++ b/sdk/python/packages/flet/docs/types/paintgradient/index.md @@ -5,5 +5,5 @@ ### Canvas paint ```python ---8<-- "../../examples/controls/types/paint_gradient/canvas_paint.py" +--8<-- "../../examples/controls/types/paint_gradient/canvas_paint/main.py" ``` diff --git a/sdk/python/packages/flet/docs/types/paintingstyle.md b/sdk/python/packages/flet/docs/types/paintingstyle.md index 51645db9d1..0bd4290226 100644 --- a/sdk/python/packages/flet/docs/types/paintingstyle.md +++ b/sdk/python/packages/flet/docs/types/paintingstyle.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/painting_style ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/paintlineargradient.md b/sdk/python/packages/flet/docs/types/paintlineargradient.md index e46d3cf861..af04caa489 100644 --- a/sdk/python/packages/flet/docs/types/paintlineargradient.md +++ b/sdk/python/packages/flet/docs/types/paintlineargradient.md @@ -5,7 +5,7 @@ ### Canvas paint ```python ---8<-- "../../examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint.py" +--8<-- "../../examples/controls/types/paint_gradient/paint_linear_gradient/canvas_paint/main.py" ``` {{ image("../examples/controls/types/paint_gradient/paint_linear_gradient/media/canvas_paint.png", alt="canvas-paint", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/paintradialgradient.md b/sdk/python/packages/flet/docs/types/paintradialgradient.md index 7293d8fde5..ef08e96989 100644 --- a/sdk/python/packages/flet/docs/types/paintradialgradient.md +++ b/sdk/python/packages/flet/docs/types/paintradialgradient.md @@ -5,7 +5,7 @@ ### Canvas paint ```python ---8<-- "../../examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint.py" +--8<-- "../../examples/controls/types/paint_gradient/paint_radial_gradient/canvas_paint/main.py" ``` {{ image("../examples/controls/types/paint_gradient/paint_radial_gradient/media/canvas_paint.png", alt="canvas-paint", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/paintsweepgradient.md b/sdk/python/packages/flet/docs/types/paintsweepgradient.md index 21f2f1441c..1593e045fb 100644 --- a/sdk/python/packages/flet/docs/types/paintsweepgradient.md +++ b/sdk/python/packages/flet/docs/types/paintsweepgradient.md @@ -5,7 +5,7 @@ ### Canvas paint ```python ---8<-- "../../examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint.py" +--8<-- "../../examples/controls/types/paint_gradient/paint_sweep_gradient/canvas_paint/main.py" ``` {{ image("../examples/controls/types/paint_gradient/paint_sweep_gradient/media/canvas_paint.png", alt="canvas-paint", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/pointmode.md b/sdk/python/packages/flet/docs/types/pointmode.md index 821ac4e70f..8e2269171d 100644 --- a/sdk/python/packages/flet/docs/types/pointmode.md +++ b/sdk/python/packages/flet/docs/types/pointmode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/point_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/popupmenuposition.md b/sdk/python/packages/flet/docs/types/popupmenuposition.md index fee12117d9..0632a7d501 100644 --- a/sdk/python/packages/flet/docs/types/popupmenuposition.md +++ b/sdk/python/packages/flet/docs/types/popupmenuposition.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/popup_menu_position ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/radialgradient.md b/sdk/python/packages/flet/docs/types/radialgradient.md index 75004ee3b5..d5653a061c 100644 --- a/sdk/python/packages/flet/docs/types/radialgradient.md +++ b/sdk/python/packages/flet/docs/types/radialgradient.md @@ -5,7 +5,7 @@ ### Container with radial gradient ```python ---8<-- "../../examples/controls/types/gradient/radial_gradient/container.py" +--8<-- "../../examples/controls/types/gradient/radial_gradient/container/main.py" ``` {{ image("../examples/controls/types/gradient/radial_gradient/media/container.png", alt="container", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/scrollbar.md b/sdk/python/packages/flet/docs/types/scrollbar.md index 283521427a..8bf700e2da 100644 --- a/sdk/python/packages/flet/docs/types/scrollbar.md +++ b/sdk/python/packages/flet/docs/types/scrollbar.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/scroll_bar ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/types/scrollbarorientation.md b/sdk/python/packages/flet/docs/types/scrollbarorientation.md index 13960d5fec..d240429b83 100644 --- a/sdk/python/packages/flet/docs/types/scrollbarorientation.md +++ b/sdk/python/packages/flet/docs/types/scrollbarorientation.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/scroll_bar_orientation ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/scrolldirection.md b/sdk/python/packages/flet/docs/types/scrolldirection.md index 0e93f34d48..56b5ce8886 100644 --- a/sdk/python/packages/flet/docs/types/scrolldirection.md +++ b/sdk/python/packages/flet/docs/types/scrolldirection.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/scroll_direction ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/scrollmode.md b/sdk/python/packages/flet/docs/types/scrollmode.md index 75c5518642..2cfec74409 100644 --- a/sdk/python/packages/flet/docs/types/scrollmode.md +++ b/sdk/python/packages/flet/docs/types/scrollmode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/scroll_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/scrolltype.md b/sdk/python/packages/flet/docs/types/scrolltype.md index 9366f9c186..71e9821983 100644 --- a/sdk/python/packages/flet/docs/types/scrolltype.md +++ b/sdk/python/packages/flet/docs/types/scrolltype.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/scroll_type ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/sliderinteraction.md b/sdk/python/packages/flet/docs/types/sliderinteraction.md index 0b5cb54fe8..6014fdc429 100644 --- a/sdk/python/packages/flet/docs/types/sliderinteraction.md +++ b/sdk/python/packages/flet/docs/types/sliderinteraction.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/slider_interaction ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/snackbarbehavior.md b/sdk/python/packages/flet/docs/types/snackbarbehavior.md index 1e5cdca2b8..f160cb3e04 100644 --- a/sdk/python/packages/flet/docs/types/snackbarbehavior.md +++ b/sdk/python/packages/flet/docs/types/snackbarbehavior.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/snack_bar_behavior ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/strokecap.md b/sdk/python/packages/flet/docs/types/strokecap.md index 15e3f96c61..4ee70c33f2 100644 --- a/sdk/python/packages/flet/docs/types/strokecap.md +++ b/sdk/python/packages/flet/docs/types/strokecap.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/stroke_cap ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/strokejoin.md b/sdk/python/packages/flet/docs/types/strokejoin.md index 569f03b83f..d9c137f541 100644 --- a/sdk/python/packages/flet/docs/types/strokejoin.md +++ b/sdk/python/packages/flet/docs/types/strokejoin.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/stroke_join ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/sweepgradient.md b/sdk/python/packages/flet/docs/types/sweepgradient.md index c2fc1e5b02..a6720843f4 100644 --- a/sdk/python/packages/flet/docs/types/sweepgradient.md +++ b/sdk/python/packages/flet/docs/types/sweepgradient.md @@ -5,7 +5,7 @@ ### Container with sweep gradient ```python ---8<-- "../../examples/controls/types/gradient/sweep_gradient/container.py" +--8<-- "../../examples/controls/types/gradient/sweep_gradient/container/main.py" ``` {{ image("../examples/controls/types/gradient/sweep_gradient/media/container.png", alt="container", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/tabalignment.md b/sdk/python/packages/flet/docs/types/tabalignment.md index 4a6bcff4ba..eb6ac7ba3f 100644 --- a/sdk/python/packages/flet/docs/types/tabalignment.md +++ b/sdk/python/packages/flet/docs/types/tabalignment.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/tab_alignment ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/tabbarindicatorsize.md b/sdk/python/packages/flet/docs/types/tabbarindicatorsize.md index d8c3e4e5b6..2635d70803 100644 --- a/sdk/python/packages/flet/docs/types/tabbarindicatorsize.md +++ b/sdk/python/packages/flet/docs/types/tabbarindicatorsize.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/tab_bar_indicator_size ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/tabindicatoranimation.md b/sdk/python/packages/flet/docs/types/tabindicatoranimation.md index 5883719fb3..d75718ad59 100644 --- a/sdk/python/packages/flet/docs/types/tabindicatoranimation.md +++ b/sdk/python/packages/flet/docs/types/tabindicatoranimation.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/tab_indicator_animation ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/textalign.md b/sdk/python/packages/flet/docs/types/textalign.md index 5d6f86a0a6..6e8479e2a7 100644 --- a/sdk/python/packages/flet/docs/types/textalign.md +++ b/sdk/python/packages/flet/docs/types/textalign.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/text_align ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/textcapitalization.md b/sdk/python/packages/flet/docs/types/textcapitalization.md index d33ef51986..3515cfa7a7 100644 --- a/sdk/python/packages/flet/docs/types/textcapitalization.md +++ b/sdk/python/packages/flet/docs/types/textcapitalization.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/text_capitalization ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/textdecorationstyle.md b/sdk/python/packages/flet/docs/types/textdecorationstyle.md index 93da4c20df..37699870ff 100644 --- a/sdk/python/packages/flet/docs/types/textdecorationstyle.md +++ b/sdk/python/packages/flet/docs/types/textdecorationstyle.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/text_decoration_style ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/textoverflow.md b/sdk/python/packages/flet/docs/types/textoverflow.md index 7109524f95..05bf614876 100644 --- a/sdk/python/packages/flet/docs/types/textoverflow.md +++ b/sdk/python/packages/flet/docs/types/textoverflow.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/text_overflow ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/thememode.md b/sdk/python/packages/flet/docs/types/thememode.md index 574938727c..c2d8506414 100644 --- a/sdk/python/packages/flet/docs/types/thememode.md +++ b/sdk/python/packages/flet/docs/types/thememode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/theme_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/tileaffinity.md b/sdk/python/packages/flet/docs/types/tileaffinity.md index e5327a850d..b93b40db9a 100644 --- a/sdk/python/packages/flet/docs/types/tileaffinity.md +++ b/sdk/python/packages/flet/docs/types/tileaffinity.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/tile_affinity ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/timepickerentrymode.md b/sdk/python/packages/flet/docs/types/timepickerentrymode.md index 3fe38ba71c..86a9aa576f 100644 --- a/sdk/python/packages/flet/docs/types/timepickerentrymode.md +++ b/sdk/python/packages/flet/docs/types/timepickerentrymode.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/time_picker_entry_mode ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/timepickerhourformat.md b/sdk/python/packages/flet/docs/types/timepickerhourformat.md index 3134538cdc..25caf9ec22 100644 --- a/sdk/python/packages/flet/docs/types/timepickerhourformat.md +++ b/sdk/python/packages/flet/docs/types/timepickerhourformat.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/time_picker_hour_format ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/tooltip.md b/sdk/python/packages/flet/docs/types/tooltip.md index 5600cf21ea..ec48e74af8 100644 --- a/sdk/python/packages/flet/docs/types/tooltip.md +++ b/sdk/python/packages/flet/docs/types/tooltip.md @@ -5,7 +5,7 @@ ### Tooltip with decoration ```python ---8<-- "../../examples/controls/types/tooltip/with_decoration.py" +--8<-- "../../examples/controls/types/tooltip/with_decoration/main.py" ``` {{ image("../examples/controls/types/tooltip/media/with_decoration.gif", alt="with-decoration", width="80%") }} diff --git a/sdk/python/packages/flet/docs/types/urltarget.md b/sdk/python/packages/flet/docs/types/urltarget.md index c23ebc7fb7..a24b1ffc78 100644 --- a/sdk/python/packages/flet/docs/types/urltarget.md +++ b/sdk/python/packages/flet/docs/types/urltarget.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/url_target ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/visualdensity.md b/sdk/python/packages/flet/docs/types/visualdensity.md index 86d5bdcc9f..4708f21821 100644 --- a/sdk/python/packages/flet/docs/types/visualdensity.md +++ b/sdk/python/packages/flet/docs/types/visualdensity.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/visual_density ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} diff --git a/sdk/python/packages/flet/docs/types/windoweventtype.md b/sdk/python/packages/flet/docs/types/windoweventtype.md index 9224f0ff41..41d82741a6 100644 --- a/sdk/python/packages/flet/docs/types/windoweventtype.md +++ b/sdk/python/packages/flet/docs/types/windoweventtype.md @@ -10,7 +10,7 @@ examples: ../../examples/controls/types/window_event_type ### Showcase ```python ---8<-- "{{ examples }}/showcase.py" +--8<-- "{{ examples }}/showcase/main.py" ``` {{ class_members(class_name, separate_signature=False) }} From d50e5e02b6b39115dbd1e4ece967935a8062e9cb Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 08:17:30 -0700 Subject: [PATCH 82/96] Remove unused examples.controls package init --- sdk/python/examples/controls/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 sdk/python/examples/controls/__init__.py diff --git a/sdk/python/examples/controls/__init__.py b/sdk/python/examples/controls/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 From 7c3552a886fbb7b6a4f944c015287b010c1b6add Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 08:30:30 -0700 Subject: [PATCH 83/96] Migrate audio and accelerometer service examples --- .../create-flet-example-projects/SKILL.md | 4 + .../accelerometer/{basic.py => basic/main.py} | 14 ++- .../accelerometer/basic/pyproject.toml | 27 ++++++ .../main.py} | 30 +++--- .../audio/declarative_1/pyproject.toml | 26 ++++++ .../examples/services/audio/example_1.py | 73 --------------- .../examples/services/audio/example_1/main.py | 93 +++++++++++++++++++ .../services/audio/example_1/pyproject.toml | 26 ++++++ sdk/python/packages/flet/docs/audio/index.md | 2 +- .../flet/docs/services/accelerometer.md | 2 +- 10 files changed, 205 insertions(+), 92 deletions(-) rename sdk/python/examples/services/accelerometer/{basic.py => basic/main.py} (64%) create mode 100644 sdk/python/examples/services/accelerometer/basic/pyproject.toml rename sdk/python/examples/services/audio/{declarative_1.py => declarative_1/main.py} (53%) create mode 100644 sdk/python/examples/services/audio/declarative_1/pyproject.toml delete mode 100644 sdk/python/examples/services/audio/example_1.py create mode 100644 sdk/python/examples/services/audio/example_1/main.py create mode 100644 sdk/python/examples/services/audio/example_1/pyproject.toml diff --git a/.codex/skills/create-flet-example-projects/SKILL.md b/.codex/skills/create-flet-example-projects/SKILL.md index d0bac8903a..f1c8845bf0 100644 --- a/.codex/skills/create-flet-example-projects/SKILL.md +++ b/.codex/skills/create-flet-example-projects/SKILL.md @@ -39,6 +39,10 @@ Ensure each runnable example is a standalone project containing: - Infer from path and code. - Create missing `pyproject.toml` files for existing project folders. - Update obviously stale metadata when migrating existing examples (for example wrong title/description/categories). +- Verify platform support before adding or omitting `[tool.flet].platforms`: + - Check the local implementation and docs for explicit platform guards, support tables, or platform-specific exceptions. + - If support is limited, add `[tool.flet].platforms` with only the supported platforms. + - If support is broad/all-platform, omit `[tool.flet].platforms`. - Required fields: - `[project]`: `name`, `version`, `description`, `requires-python`, `keywords`, `authors`, `dependencies` - `[dependency-groups].dev`: include `flet-cli`, `flet-desktop`, `flet-web` diff --git a/sdk/python/examples/services/accelerometer/basic.py b/sdk/python/examples/services/accelerometer/basic/main.py similarity index 64% rename from sdk/python/examples/services/accelerometer/basic.py rename to sdk/python/examples/services/accelerometer/basic/main.py index e88f09475d..3e2a60a515 100644 --- a/sdk/python/examples/services/accelerometer/basic.py +++ b/sdk/python/examples/services/accelerometer/basic/main.py @@ -4,7 +4,6 @@ def main(page: ft.Page): def handle_reading(e: ft.AccelerometerReadingEvent): reading.value = f"x={e.x:.2f} m/s^2, y={e.y:.2f} m/s^2, z={e.z:.2f} m/s^2" - page.update() def handle_error(e: ft.SensorErrorEvent): page.add(ft.Text(f"Accelerometer error: {e.message}")) @@ -19,9 +18,16 @@ def handle_error(e: ft.SensorErrorEvent): ) page.add( - ft.Text("Move your device to see accelerometer readings."), - reading := ft.Text("Waiting for data..."), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Move your device to see accelerometer readings."), + reading := ft.Text("Waiting for data..."), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/accelerometer/basic/pyproject.toml b/sdk/python/examples/services/accelerometer/basic/pyproject.toml new file mode 100644 index 0000000000..d1fcfb3317 --- /dev/null +++ b/sdk/python/examples/services/accelerometer/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-accelerometer-basic" +version = "1.0.0" +description = "Streams live accelerometer readings and displays sensor errors from the device." +requires-python = ">=3.10" +keywords = ["services", "accelerometer", "sensor", "device", "readings"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Accelerometer"] + +[tool.flet.metadata] +title = "Basic accelerometer" +controls = ["SafeArea", "Column", "Text", "Accelerometer"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios", "web"] diff --git a/sdk/python/examples/services/audio/declarative_1.py b/sdk/python/examples/services/audio/declarative_1/main.py similarity index 53% rename from sdk/python/examples/services/audio/declarative_1.py rename to sdk/python/examples/services/audio/declarative_1/main.py index 70ad139e79..3c721cfd86 100644 --- a/sdk/python/examples/services/audio/declarative_1.py +++ b/sdk/python/examples/services/audio/declarative_1/main.py @@ -1,10 +1,6 @@ import flet as ft import flet_audio as fta -# https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3 -# https://luan.xyz/files/audio/ambient_c_motion.mp3 -# https://github.com/mdn/webaudio-examples/blob/main/audio-analyser/viper.mp3?raw=true - @ft.component def App(): @@ -20,8 +16,7 @@ def App(): ) ) - print("duration:", duration) - print("position:", position) + ft.on_mounted(lambda: ft.context.page.services.append(audio)) async def play(): await audio.play() @@ -32,12 +27,21 @@ async def pause(): async def resume(): await audio.resume() - return [ - ft.ProgressBar(position / duration if duration > 0 else 0), - ft.Button("Play", disabled=duration == 0, on_click=play), - ft.Button("Pause", disabled=duration == 0, on_click=pause), - ft.Button("Resume", disabled=duration == 0, on_click=resume), - ] + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.ProgressBar(position / duration if duration > 0 else 0), + ft.Button("Play", disabled=duration == 0, on_click=play), + ft.Button("Pause", disabled=duration == 0, on_click=pause), + ft.Button("Resume", disabled=duration == 0, on_click=resume), + ] + ) + ) + + +def main(page: ft.Page): + page.render(App) -ft.run(lambda page: page.render(App)) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/audio/declarative_1/pyproject.toml b/sdk/python/examples/services/audio/declarative_1/pyproject.toml new file mode 100644 index 0000000000..857c68174f --- /dev/null +++ b/sdk/python/examples/services/audio/declarative_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-audio-declarative-1" +version = "1.0.0" +description = "Builds a declarative audio player with playback controls and live progress updates." +requires-python = ">=3.10" +keywords = ["services", "audio", "declarative", "progress", "playback", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-audio"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Audio"] + +[tool.flet.metadata] +title = "Declarative audio player" +controls = ["SafeArea", "Column", "ProgressBar", "Button", "Audio"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["declarative state", "audio playback", "live progress updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/audio/example_1.py b/sdk/python/examples/services/audio/example_1.py deleted file mode 100644 index e1051c8b16..0000000000 --- a/sdk/python/examples/services/audio/example_1.py +++ /dev/null @@ -1,73 +0,0 @@ -import flet as ft -import flet_audio as fta - - -def main(page: ft.Page): - url = "https://github.com/mdn/webaudio-examples/blob/main/audio-analyser/viper.mp3?raw=true" - - async def play(): - await audio.play() - - async def pause(): - await audio.pause() - - async def resume(): - await audio.resume() - - async def release(): - await audio.release() - - def set_volume(value: float): - audio.volume += value - - def set_balance(value: float): - audio.balance += value - - async def seek_2s(): - await audio.seek(ft.Duration(seconds=2)) - - async def get_duration(): - duration = await audio.get_duration() - print("Duration:", duration) - - async def on_get_current_position(): - position = await audio.get_current_position() - print("Current position:", position) - - audio = fta.Audio( - src=url, - autoplay=False, - volume=1, - balance=0, - release_mode=fta.ReleaseMode.STOP, - on_loaded=lambda _: print("Loaded"), - on_duration_change=lambda e: print("Duration changed:", e.duration), - on_position_change=lambda e: print("Position changed:", e.position), - on_state_change=lambda e: print("State changed:", e.state), - on_seek_complete=lambda _: print("Seek complete"), - ) - - page.add( - ft.Button("Play", on_click=play), - ft.Button("Pause", on_click=pause), - ft.Button("Resume", on_click=resume), - ft.Button("Release", on_click=release), - ft.Button("Seek 2s", on_click=seek_2s), - ft.Row( - controls=[ - ft.Button("Volume down", on_click=lambda _: set_volume(-0.1)), - ft.Button("Volume up", on_click=lambda _: set_volume(0.1)), - ] - ), - ft.Row( - controls=[ - ft.Button("Balance left", on_click=lambda _: set_balance(-0.1)), - ft.Button("Balance right", on_click=lambda _: set_balance(0.1)), - ] - ), - ft.Button("Get duration", on_click=get_duration), - ft.Button("Get current position", on_click=on_get_current_position), - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/audio/example_1/main.py b/sdk/python/examples/services/audio/example_1/main.py new file mode 100644 index 0000000000..eb58bbc180 --- /dev/null +++ b/sdk/python/examples/services/audio/example_1/main.py @@ -0,0 +1,93 @@ +import flet as ft +import flet_audio as fta + + +def main(page: ft.Page): + url = "https://github.com/mdn/webaudio-examples/blob/main/audio-analyser/viper.mp3?raw=true" + + async def play(): + await audio.play() + + async def pause(): + await audio.pause() + + async def resume(): + await audio.resume() + + async def release(): + await audio.release() + + def set_volume(value: float): + audio.volume += value + + def set_balance(value: float): + audio.balance += value + + async def seek_2s(): + await audio.seek(ft.Duration(seconds=2)) + + async def get_duration(): + duration = await audio.get_duration() + print("Duration:", duration) + + async def on_get_current_position(): + position = await audio.get_current_position() + print("Current position:", position) + + audio = fta.Audio( + src=url, + autoplay=False, + volume=1, + balance=0, + release_mode=fta.ReleaseMode.STOP, + on_loaded=lambda _: print("Loaded"), + on_duration_change=lambda e: print("Duration changed:", e.duration), + on_position_change=lambda e: print("Position changed:", e.position), + on_state_change=lambda e: print("State changed:", e.state), + on_seek_complete=lambda _: print("Seek complete"), + ) + page.services.append(audio) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button("Play", on_click=play), + ft.Button("Pause", on_click=pause), + ft.Button("Resume", on_click=resume), + ft.Button("Release", on_click=release), + ft.Button("Seek 2s", on_click=seek_2s), + ft.Row( + controls=[ + ft.Button( + "Volume down", + on_click=lambda _: set_volume(-0.1), + ), + ft.Button("Volume up", on_click=lambda _: set_volume(0.1)), + ] + ), + ft.Row( + controls=[ + ft.Button( + "Balance left", + on_click=lambda _: set_balance(-0.1), + ), + ft.Button( + "Balance right", + on_click=lambda _: set_balance(0.1), + ), + ] + ), + ft.Button("Get duration", on_click=get_duration), + ft.Button( + "Get current position", + on_click=on_get_current_position, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/audio/example_1/pyproject.toml b/sdk/python/examples/services/audio/example_1/pyproject.toml new file mode 100644 index 0000000000..2a709202d3 --- /dev/null +++ b/sdk/python/examples/services/audio/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-audio-example-1" +version = "1.0.0" +description = "Controls audio playback, seek position, volume, and balance for a remote track." +requires-python = ">=3.10" +keywords = ["services", "audio", "playback", "seek", "volume", "balance", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-audio"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Audio"] + +[tool.flet.metadata] +title = "Audio playback controls" +controls = ["SafeArea", "Column", "Row", "Button", "Audio"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["audio playback", "seek control", "volume adjustment", "balance adjustment"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/audio/index.md b/sdk/python/packages/flet/docs/audio/index.md index 154086be69..34e35cf70b 100644 --- a/sdk/python/packages/flet/docs/audio/index.md +++ b/sdk/python/packages/flet/docs/audio/index.md @@ -65,7 +65,7 @@ for installing on other Linux distributions. ### Basic example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Description diff --git a/sdk/python/packages/flet/docs/services/accelerometer.md b/sdk/python/packages/flet/docs/services/accelerometer.md index fc9c0e01a2..9a949f66f5 100644 --- a/sdk/python/packages/flet/docs/services/accelerometer.md +++ b/sdk/python/packages/flet/docs/services/accelerometer.md @@ -8,7 +8,7 @@ examples: ../../examples/services/accelerometer ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} From 78073e1756382cac03b9ae8209d4bcd58b351f86 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 09:48:51 -0700 Subject: [PATCH 84/96] Migrate remaining service examples --- .../{example_1.py => example_1/main.py} | 36 ++++--- .../audio_recorder/example_1/pyproject.toml | 26 +++++ .../barometer/{basic.py => basic/main.py} | 14 ++- .../services/barometer/basic/pyproject.toml | 27 ++++++ .../battery/{basic.py => basic/main.py} | 3 +- .../services/battery/basic/pyproject.toml | 26 +++++ .../services/browsercontextmenu/basic.py | 32 ------- .../services/browsercontextmenu/basic/main.py | 39 ++++++++ .../browsercontextmenu/basic/pyproject.toml | 27 ++++++ .../clipboard/{files.py => files/main.py} | 3 +- .../services/clipboard/files/pyproject.toml | 26 +++++ .../clipboard/{images.py => images/main.py} | 3 +- .../services/clipboard/images/pyproject.toml | 26 +++++ .../examples/services/clipboard/text.py | 25 ----- .../examples/services/clipboard/text/main.py | 34 +++++++ .../services/clipboard/text/pyproject.toml | 26 +++++ .../connectivity/{basic.py => basic/main.py} | 21 ++-- .../connectivity/basic/pyproject.toml | 26 +++++ .../main.py} | 45 +++++---- .../pick_and_save_text_content/pyproject.toml | 26 +++++ .../main.py} | 59 +++++++----- .../pick_and_upload/pyproject.toml | 27 ++++++ .../pick_save_and_get_directory_path.py | 53 ---------- .../pick_save_and_get_directory_path/main.py | 60 ++++++++++++ .../pyproject.toml | 26 +++++ .../examples/services/flashlight/example_1.py | 18 ---- .../services/flashlight/example_1/main.py | 25 +++++ .../flashlight/example_1/pyproject.toml | 27 ++++++ .../{example_1.py => example_1/main.py} | 81 +++++++++------- .../geolocator/example_1/pyproject.toml | 26 +++++ .../gyroscope/{basic.py => basic/main.py} | 14 ++- .../services/gyroscope/basic/pyproject.toml | 27 ++++++ .../services/haptic_feedback/basic.py | 27 ------ .../services/haptic_feedback/basic/main.py | 34 +++++++ .../haptic_feedback/basic/pyproject.toml | 26 +++++ .../magnetometer/{basic.py => basic/main.py} | 14 ++- .../magnetometer/basic/pyproject.toml | 27 ++++++ .../{example_1.py => example_1/main.py} | 22 +++-- .../example_1/pyproject.toml | 27 ++++++ .../{basic.py => basic/main.py} | 59 +++++++----- .../screen_brightness/basic/pyproject.toml | 27 ++++++ .../{basic.py => basic/main.py} | 62 ++++++------ .../secure_storage/basic/pyproject.toml | 26 +++++ .../main.py} | 13 ++- .../accessibility_features/pyproject.toml | 26 +++++ .../{basic.py => basic/main.py} | 11 ++- .../shake_detector/basic/pyproject.toml | 26 +++++ .../share/{basic.py => basic/main.py} | 3 +- .../services/share/basic/pyproject.toml | 26 +++++ .../services/sharedpreferences/basic.py | 37 ------- .../services/sharedpreferences/basic/main.py | 44 +++++++++ .../sharedpreferences/basic/pyproject.toml | 26 +++++ .../storagepaths/{basic.py => basic/main.py} | 11 ++- .../storagepaths/basic/pyproject.toml | 26 +++++ .../examples/services/urllauncher/basic.py | 81 ---------------- .../services/urllauncher/basic/main.py | 96 +++++++++++++++++++ .../services/urllauncher/basic/pyproject.toml | 26 +++++ .../{basic.py => basic/main.py} | 20 ++-- .../user_accelerometer/basic/pyproject.toml | 27 ++++++ .../examples/services/wakelock/basic.py | 39 -------- .../examples/services/wakelock/basic/main.py | 48 ++++++++++ .../services/wakelock/basic/pyproject.toml | 26 +++++ .../flet/docs/audio_recorder/index.md | 2 +- .../packages/flet/docs/flashlight/index.md | 2 +- .../packages/flet/docs/geolocator/index.md | 2 +- .../flet/docs/permission_handler/index.md | 2 +- .../flet/docs/secure_storage/index.md | 2 +- .../packages/flet/docs/services/barometer.md | 2 +- .../packages/flet/docs/services/battery.md | 2 +- .../flet/docs/services/browsercontextmenu.md | 2 +- .../packages/flet/docs/services/clipboard.md | 6 +- .../flet/docs/services/connectivity.md | 2 +- .../packages/flet/docs/services/filepicker.md | 6 +- .../packages/flet/docs/services/gyroscope.md | 2 +- .../flet/docs/services/hapticfeedback.md | 2 +- .../flet/docs/services/magnetometer.md | 2 +- .../flet/docs/services/screenbrightness.md | 2 +- .../flet/docs/services/semanticsservice.md | 2 +- .../flet/docs/services/shakedetector.md | 2 +- .../packages/flet/docs/services/share.md | 2 +- .../flet/docs/services/sharedpreferences.md | 2 +- .../flet/docs/services/storagepaths.md | 2 +- .../flet/docs/services/urllauncher.md | 2 +- .../flet/docs/services/useraccelerometer.md | 2 +- .../packages/flet/docs/services/wakelock.md | 2 +- 85 files changed, 1427 insertions(+), 524 deletions(-) rename sdk/python/examples/services/audio_recorder/{example_1.py => example_1/main.py} (65%) create mode 100644 sdk/python/examples/services/audio_recorder/example_1/pyproject.toml rename sdk/python/examples/services/barometer/{basic.py => basic/main.py} (61%) create mode 100644 sdk/python/examples/services/barometer/basic/pyproject.toml rename sdk/python/examples/services/battery/{basic.py => basic/main.py} (96%) create mode 100644 sdk/python/examples/services/battery/basic/pyproject.toml delete mode 100644 sdk/python/examples/services/browsercontextmenu/basic.py create mode 100644 sdk/python/examples/services/browsercontextmenu/basic/main.py create mode 100644 sdk/python/examples/services/browsercontextmenu/basic/pyproject.toml rename sdk/python/examples/services/clipboard/{files.py => files/main.py} (98%) create mode 100644 sdk/python/examples/services/clipboard/files/pyproject.toml rename sdk/python/examples/services/clipboard/{images.py => images/main.py} (98%) create mode 100644 sdk/python/examples/services/clipboard/images/pyproject.toml delete mode 100644 sdk/python/examples/services/clipboard/text.py create mode 100644 sdk/python/examples/services/clipboard/text/main.py create mode 100644 sdk/python/examples/services/clipboard/text/pyproject.toml rename sdk/python/examples/services/connectivity/{basic.py => basic/main.py} (59%) create mode 100644 sdk/python/examples/services/connectivity/basic/pyproject.toml rename sdk/python/examples/services/file_picker/{pick_and_save_text_content.py => pick_and_save_text_content/main.py} (65%) create mode 100644 sdk/python/examples/services/file_picker/pick_and_save_text_content/pyproject.toml rename sdk/python/examples/services/file_picker/{pick_and_upload.py => pick_and_upload/main.py} (55%) create mode 100644 sdk/python/examples/services/file_picker/pick_and_upload/pyproject.toml delete mode 100644 sdk/python/examples/services/file_picker/pick_save_and_get_directory_path.py create mode 100644 sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/main.py create mode 100644 sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/pyproject.toml delete mode 100644 sdk/python/examples/services/flashlight/example_1.py create mode 100644 sdk/python/examples/services/flashlight/example_1/main.py create mode 100644 sdk/python/examples/services/flashlight/example_1/pyproject.toml rename sdk/python/examples/services/geolocator/{example_1.py => example_1/main.py} (58%) create mode 100644 sdk/python/examples/services/geolocator/example_1/pyproject.toml rename sdk/python/examples/services/gyroscope/{basic.py => basic/main.py} (61%) create mode 100644 sdk/python/examples/services/gyroscope/basic/pyproject.toml delete mode 100644 sdk/python/examples/services/haptic_feedback/basic.py create mode 100644 sdk/python/examples/services/haptic_feedback/basic/main.py create mode 100644 sdk/python/examples/services/haptic_feedback/basic/pyproject.toml rename sdk/python/examples/services/magnetometer/{basic.py => basic/main.py} (62%) create mode 100644 sdk/python/examples/services/magnetometer/basic/pyproject.toml rename sdk/python/examples/services/permission_handler/{example_1.py => example_1/main.py} (59%) create mode 100644 sdk/python/examples/services/permission_handler/example_1/pyproject.toml rename sdk/python/examples/services/screen_brightness/{basic.py => basic/main.py} (62%) create mode 100644 sdk/python/examples/services/screen_brightness/basic/pyproject.toml rename sdk/python/examples/services/secure_storage/{basic.py => basic/main.py} (58%) create mode 100644 sdk/python/examples/services/secure_storage/basic/pyproject.toml rename sdk/python/examples/services/semantics_service/{accessibility_features.py => accessibility_features/main.py} (77%) create mode 100644 sdk/python/examples/services/semantics_service/accessibility_features/pyproject.toml rename sdk/python/examples/services/shake_detector/{basic.py => basic/main.py} (60%) create mode 100644 sdk/python/examples/services/shake_detector/basic/pyproject.toml rename sdk/python/examples/services/share/{basic.py => basic/main.py} (98%) create mode 100644 sdk/python/examples/services/share/basic/pyproject.toml delete mode 100644 sdk/python/examples/services/sharedpreferences/basic.py create mode 100644 sdk/python/examples/services/sharedpreferences/basic/main.py create mode 100644 sdk/python/examples/services/sharedpreferences/basic/pyproject.toml rename sdk/python/examples/services/storagepaths/{basic.py => basic/main.py} (89%) create mode 100644 sdk/python/examples/services/storagepaths/basic/pyproject.toml delete mode 100644 sdk/python/examples/services/urllauncher/basic.py create mode 100644 sdk/python/examples/services/urllauncher/basic/main.py create mode 100644 sdk/python/examples/services/urllauncher/basic/pyproject.toml rename sdk/python/examples/services/user_accelerometer/{basic.py => basic/main.py} (55%) create mode 100644 sdk/python/examples/services/user_accelerometer/basic/pyproject.toml delete mode 100644 sdk/python/examples/services/wakelock/basic.py create mode 100644 sdk/python/examples/services/wakelock/basic/main.py create mode 100644 sdk/python/examples/services/wakelock/basic/pyproject.toml diff --git a/sdk/python/examples/services/audio_recorder/example_1.py b/sdk/python/examples/services/audio_recorder/example_1/main.py similarity index 65% rename from sdk/python/examples/services/audio_recorder/example_1.py rename to sdk/python/examples/services/audio_recorder/example_1/main.py index 9a0502ec15..c2d4b8b5bb 100644 --- a/sdk/python/examples/services/audio_recorder/example_1.py +++ b/sdk/python/examples/services/audio_recorder/example_1/main.py @@ -51,17 +51,31 @@ async def handle_audio_encoder_test(e: ft.Event[ft.Button]): ) page.add( - ft.Button(content="Start Audio Recorder", on_click=handle_recording_start), - ft.Button(content="Stop Audio Recorder", on_click=handle_recording_stop), - ft.Button(content="List Devices", on_click=handle_list_devices), - ft.Button(content="Pause Recording", on_click=handle_pause), - ft.Button(content="Resume Recording", on_click=handle_resume), - ft.Button(content="WAV Encoder Support", on_click=handle_audio_encoder_test), - ft.Button( - content="Get Audio Recording Permission Status", - on_click=handle_has_permission, - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Start Audio Recorder", on_click=handle_recording_start + ), + ft.Button( + content="Stop Audio Recorder", on_click=handle_recording_stop + ), + ft.Button(content="List Devices", on_click=handle_list_devices), + ft.Button(content="Pause Recording", on_click=handle_pause), + ft.Button(content="Resume Recording", on_click=handle_resume), + ft.Button( + content="WAV Encoder Support", + on_click=handle_audio_encoder_test, + ), + ft.Button( + content="Get Audio Recording Permission Status", + on_click=handle_has_permission, + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/audio_recorder/example_1/pyproject.toml b/sdk/python/examples/services/audio_recorder/example_1/pyproject.toml new file mode 100644 index 0000000000..4f77381365 --- /dev/null +++ b/sdk/python/examples/services/audio_recorder/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-audio-recorder-example-1" +version = "1.0.0" +description = "Records audio, lists input devices, and checks recorder permissions from one screen." +requires-python = ">=3.10" +keywords = ["audio recorder", "example 1", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-audio-recorder"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/AudioRecorder"] + +[tool.flet.metadata] +title = "Audio recorder example" +controls = ["SafeArea", "Column", "Page", "AppBar", "Text", "Button", "AudioRecorder"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["audio recording", "permission check", "device listing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/barometer/basic.py b/sdk/python/examples/services/barometer/basic/main.py similarity index 61% rename from sdk/python/examples/services/barometer/basic.py rename to sdk/python/examples/services/barometer/basic/main.py index 5242711a46..36fd76ff3a 100644 --- a/sdk/python/examples/services/barometer/basic.py +++ b/sdk/python/examples/services/barometer/basic/main.py @@ -4,7 +4,6 @@ def main(page: ft.Page): def handle_reading(e: ft.BarometerReadingEvent): reading.value = f"{e.pressure:.2f} hPa" - page.update() def handle_error(e: ft.SensorErrorEvent): page.add(ft.Text(f"Barometer error: {e.message}")) @@ -18,9 +17,16 @@ def handle_error(e: ft.SensorErrorEvent): ) page.add( - ft.Text("Atmospheric pressure (hPa)."), - reading := ft.Text("Waiting for data..."), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Atmospheric pressure (hPa)."), + reading := ft.Text("Waiting for data..."), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/barometer/basic/pyproject.toml b/sdk/python/examples/services/barometer/basic/pyproject.toml new file mode 100644 index 0000000000..e6a25849a6 --- /dev/null +++ b/sdk/python/examples/services/barometer/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-barometer-basic" +version = "1.0.0" +description = "Streams atmospheric pressure readings and reports barometer errors from the device sensor." +requires-python = ">=3.10" +keywords = ["barometer", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Barometer"] + +[tool.flet.metadata] +title = "Basic barometer" +controls = ["SafeArea", "Column", "Page", "BarometerReadingEvent", "Text", "Barometer"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/battery/basic.py b/sdk/python/examples/services/battery/basic/main.py similarity index 96% rename from sdk/python/examples/services/battery/basic.py rename to sdk/python/examples/services/battery/basic/main.py index 8ec1891842..53816b5a4d 100644 --- a/sdk/python/examples/services/battery/basic.py +++ b/sdk/python/examples/services/battery/basic/main.py @@ -36,4 +36,5 @@ async def on_state_change(e: ft.BatteryStateChangeEvent): await refresh_info() -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/battery/basic/pyproject.toml b/sdk/python/examples/services/battery/basic/pyproject.toml new file mode 100644 index 0000000000..2297da7f8d --- /dev/null +++ b/sdk/python/examples/services/battery/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-battery-basic" +version = "1.0.0" +description = "Shows battery level, battery state, and battery saver status with a refresh action." +requires-python = ">=3.10" +keywords = ["battery", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Battery"] + +[tool.flet.metadata] +title = "Basic battery" +controls = ["SafeArea", "Column", "Page", "Button", "Battery", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["battery state", "battery saver status"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/browsercontextmenu/basic.py b/sdk/python/examples/services/browsercontextmenu/basic.py deleted file mode 100644 index f2225a0e14..0000000000 --- a/sdk/python/examples/services/browsercontextmenu/basic.py +++ /dev/null @@ -1,32 +0,0 @@ -# -# Run this example as a web app using the command: -# -# flet run --web basic.py -# - - -import flet as ft - - -async def main(page: ft.Page): - bcm = ft.BrowserContextMenu() - - async def disable_context_menu(): - await bcm.disable() - - async def enable_context_menu(): - await bcm.enable() - - page.add( - ft.Column( - [ - ft.Button( - "Disable browser context menu", on_click=disable_context_menu - ), - ft.Button("Enable browser context menu", on_click=enable_context_menu), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/browsercontextmenu/basic/main.py b/sdk/python/examples/services/browsercontextmenu/basic/main.py new file mode 100644 index 0000000000..0956cf47ca --- /dev/null +++ b/sdk/python/examples/services/browsercontextmenu/basic/main.py @@ -0,0 +1,39 @@ +# +# Run this example as a web app using the command: +# +# flet run --web main.py +# + + +import flet as ft + + +async def main(page: ft.Page): + bcm = ft.BrowserContextMenu() + + async def disable_context_menu(): + await bcm.disable() + + async def enable_context_menu(): + await bcm.enable() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Disable browser context menu", + on_click=disable_context_menu, + ), + ft.Button( + "Enable browser context menu", + on_click=enable_context_menu, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/browsercontextmenu/basic/pyproject.toml b/sdk/python/examples/services/browsercontextmenu/basic/pyproject.toml new file mode 100644 index 0000000000..85ea479917 --- /dev/null +++ b/sdk/python/examples/services/browsercontextmenu/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-browsercontextmenu-basic" +version = "1.0.0" +description = "Enables and disables the browser context menu from a simple web control panel." +requires-python = ">=3.10" +keywords = ["browsercontextmenu", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/BrowserContextMenu"] + +[tool.flet.metadata] +title = "Basic browser context menu" +controls = ["SafeArea", "Column", "Page", "BrowserContextMenu", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["web context menu toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["web"] diff --git a/sdk/python/examples/services/clipboard/files.py b/sdk/python/examples/services/clipboard/files/main.py similarity index 98% rename from sdk/python/examples/services/clipboard/files.py rename to sdk/python/examples/services/clipboard/files/main.py index a35b453fcc..cbef745747 100644 --- a/sdk/python/examples/services/clipboard/files.py +++ b/sdk/python/examples/services/clipboard/files/main.py @@ -103,4 +103,5 @@ async def get_files_from_clipboard(e: ft.Event[ft.Button]): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/clipboard/files/pyproject.toml b/sdk/python/examples/services/clipboard/files/pyproject.toml new file mode 100644 index 0000000000..ae4b274107 --- /dev/null +++ b/sdk/python/examples/services/clipboard/files/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-clipboard-files" +version = "1.0.0" +description = "Writes sample file references to the clipboard and reads clipboard file entries back." +requires-python = ">=3.10" +keywords = ["clipboard", "files", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Clipboard"] + +[tool.flet.metadata] +title = "Clipboard files" +controls = ["SafeArea", "Column", "Page", "Button", "Clipboard", "Row", "Text", "IconButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["clipboard file references", "desktop file open"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/clipboard/images.py b/sdk/python/examples/services/clipboard/images/main.py similarity index 98% rename from sdk/python/examples/services/clipboard/images.py rename to sdk/python/examples/services/clipboard/images/main.py index 77d4328600..8f544359ba 100644 --- a/sdk/python/examples/services/clipboard/images.py +++ b/sdk/python/examples/services/clipboard/images/main.py @@ -52,4 +52,5 @@ async def get_image_from_clipboard(e: ft.Event[ft.Button]): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/clipboard/images/pyproject.toml b/sdk/python/examples/services/clipboard/images/pyproject.toml new file mode 100644 index 0000000000..d6d10f773e --- /dev/null +++ b/sdk/python/examples/services/clipboard/images/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-clipboard-images" +version = "1.0.0" +description = "Copies a sample image to the clipboard and previews image data loaded from the clipboard." +requires-python = ">=3.10" +keywords = ["clipboard", "images", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Clipboard"] + +[tool.flet.metadata] +title = "Clipboard images" +controls = ["SafeArea", "Column", "Page", "Button", "Clipboard", "Image", "Text", "Container"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["copy image", "clipboard image preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/clipboard/text.py b/sdk/python/examples/services/clipboard/text.py deleted file mode 100644 index bdf01a1d04..0000000000 --- a/sdk/python/examples/services/clipboard/text.py +++ /dev/null @@ -1,25 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - async def set_to_clipboard(): - await ft.Clipboard().set(text_to_copy.value) - text_to_copy.value = "" - page.show_dialog(ft.SnackBar("Text copied to clipboard")) - - async def get_from_clipboard(): - contents = await ft.Clipboard().get() - page.add(ft.Text(f"Clipboard contents: {contents}")) - - page.add( - ft.Column( - controls=[ - text_to_copy := ft.TextField(label="Text to copy"), - ft.Button("Set to clipboard", on_click=set_to_clipboard), - ft.Button("Get from clipboard", on_click=get_from_clipboard), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/clipboard/text/main.py b/sdk/python/examples/services/clipboard/text/main.py new file mode 100644 index 0000000000..a2113c092f --- /dev/null +++ b/sdk/python/examples/services/clipboard/text/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +async def main(page: ft.Page): + async def set_to_clipboard(): + await ft.Clipboard().set(text_to_copy.value) + text_to_copy.value = "" + page.show_dialog(ft.SnackBar("Text copied to clipboard")) + + async def get_from_clipboard(): + contents = await ft.Clipboard().get() + page.add(ft.Text(f"Clipboard contents: {contents}")) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + text_to_copy := ft.TextField(label="Text to copy"), + ft.Button("Set to clipboard", on_click=set_to_clipboard), + ft.Button( + "Get from clipboard", on_click=get_from_clipboard + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/clipboard/text/pyproject.toml b/sdk/python/examples/services/clipboard/text/pyproject.toml new file mode 100644 index 0000000000..119a9a9f0d --- /dev/null +++ b/sdk/python/examples/services/clipboard/text/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-clipboard-text" +version = "1.0.0" +description = "Copies text to the clipboard and reads the current clipboard text back into the app." +requires-python = ">=3.10" +keywords = ["clipboard", "text", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Clipboard"] + +[tool.flet.metadata] +title = "Clipboard text" +controls = ["SafeArea", "Column", "Page", "Clipboard", "Text", "TextField", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["copy text", "read clipboard"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/connectivity/basic.py b/sdk/python/examples/services/connectivity/basic/main.py similarity index 59% rename from sdk/python/examples/services/connectivity/basic.py rename to sdk/python/examples/services/connectivity/basic/main.py index 895c15f1ad..f7314d8ca3 100644 --- a/sdk/python/examples/services/connectivity/basic.py +++ b/sdk/python/examples/services/connectivity/basic/main.py @@ -22,14 +22,21 @@ async def on_change(e: ft.ConnectivityChangeEvent): await refresh() page.add( - ft.Column( - [ - status, - ft.Button("Refresh connectivity", on_click=refresh), - changes, - ], + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + status, + ft.Button("Refresh connectivity", on_click=refresh), + changes, + ], + ) + ], + ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/connectivity/basic/pyproject.toml b/sdk/python/examples/services/connectivity/basic/pyproject.toml new file mode 100644 index 0000000000..f258dc1988 --- /dev/null +++ b/sdk/python/examples/services/connectivity/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-connectivity-basic" +version = "1.0.0" +description = "Displays current connectivity state and listens for connectivity change events." +requires-python = ">=3.10" +keywords = ["connectivity", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Connectivity"] + +[tool.flet.metadata] +title = "Basic connectivity" +controls = ["SafeArea", "Column", "Page", "Connectivity", "Text", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["connectivity status", "change events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/file_picker/pick_and_save_text_content.py b/sdk/python/examples/services/file_picker/pick_and_save_text_content/main.py similarity index 65% rename from sdk/python/examples/services/file_picker/pick_and_save_text_content.py rename to sdk/python/examples/services/file_picker/pick_and_save_text_content/main.py index eca794d165..5109eb7369 100644 --- a/sdk/python/examples/services/file_picker/pick_and_save_text_content.py +++ b/sdk/python/examples/services/file_picker/pick_and_save_text_content/main.py @@ -2,7 +2,7 @@ # Example of picking and saving text content with FilePicker. # # Run this example with: -# uv run flet run --web pick_and_save_text_content.py +# uv run flet run --web main.py # import flet as ft @@ -27,7 +27,6 @@ async def pick_text_file(_: ft.Event[ft.Button]): if not files: selected_file_name.value = "Selection cancelled" selected_file_content.value = "" - page.update() return selected = files[0] @@ -36,7 +35,6 @@ async def pick_text_file(_: ft.Event[ft.Button]): selected.bytes.decode("utf-8", errors="replace") if selected.bytes else "" ) save_status.value = "" - page.update() async def save_text_file(_: ft.Event[ft.Button]): file_name = "flet_text_content.txt" @@ -52,24 +50,33 @@ async def save_text_file(_: ft.Event[ft.Button]): save_status.value = ( f"Saved to: {file_path}" if file_path else "Save cancelled" ) - page.update() page.add( - ft.Text("Pick a .txt/.md file and load its text from FilePickerFile.bytes"), - ft.Button( - content="Pick text file", - icon=ft.Icons.UPLOAD_FILE, - on_click=pick_text_file, - ), - selected_file_name, - selected_file_content, - ft.Button( - content="Save / Download text", - icon=ft.Icons.DOWNLOAD, - on_click=save_text_file, - ), - save_status, + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Pick a .txt/.md file and load its text from " + "FilePickerFile.bytes" + ), + ft.Button( + content="Pick text file", + icon=ft.Icons.UPLOAD_FILE, + on_click=pick_text_file, + ), + selected_file_name, + selected_file_content, + ft.Button( + content="Save / Download text", + icon=ft.Icons.DOWNLOAD, + on_click=save_text_file, + ), + save_status, + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/file_picker/pick_and_save_text_content/pyproject.toml b/sdk/python/examples/services/file_picker/pick_and_save_text_content/pyproject.toml new file mode 100644 index 0000000000..e766700ea7 --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_and_save_text_content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-file-picker-pick-and-save-text-content" +version = "1.0.0" +description = "Loads text file contents from picked files and saves or downloads edited text output." +requires-python = ">=3.10" +keywords = ["file picker", "pick and save text content", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/FilePicker"] + +[tool.flet.metadata] +title = "Pick and save text content" +controls = ["SafeArea", "Column", "Page", "Text", "TextField", "Button", "FilePicker"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["file picking", "save to file"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/file_picker/pick_and_upload.py b/sdk/python/examples/services/file_picker/pick_and_upload/main.py similarity index 55% rename from sdk/python/examples/services/file_picker/pick_and_upload.py rename to sdk/python/examples/services/file_picker/pick_and_upload/main.py index aabadd4f0d..a521cca52d 100644 --- a/sdk/python/examples/services/file_picker/pick_and_upload.py +++ b/sdk/python/examples/services/file_picker/pick_and_upload/main.py @@ -3,7 +3,7 @@ # # Run this example with: # export FLET_SECRET_KEY= -# uv run flet run --web examples/services/file_picker/pick_and_upload.py +# uv run flet run --web examples/services/file_picker/pick_and_upload/main.py # from dataclasses import dataclass, field @@ -22,15 +22,21 @@ class State: def main(page: ft.Page): if not page.web: page.add( - ft.Text( - "This example is only available in Flet Web mode.\n" - "\n" - "Run this example with:\n" - " export FLET_SECRET_KEY=\n" - " flet run --web " - "examples/services/file_picker/pick_and_upload.py", - color=ft.Colors.RED, - selectable=True, + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "This example is only available in Flet Web mode.\n" + "\n" + "Run this example with:\n" + " export FLET_SECRET_KEY=\n" + " flet run --web " + "examples/services/file_picker/pick_and_upload/main.py", + color=ft.Colors.RED, + selectable=True, + ) + ], + ), ) ) return @@ -68,19 +74,26 @@ async def handle_file_upload(e: ft.Event[ft.Button]): ) page.add( - ft.Button( - content="Select files...", - icon=ft.Icons.FOLDER_OPEN, - on_click=handle_files_pick, - ), - upload_progress := ft.Column(), - upload_button := ft.Button( - content="Upload", - icon=ft.Icons.UPLOAD, - on_click=handle_file_upload, - disabled=True, - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Select files...", + icon=ft.Icons.FOLDER_OPEN, + on_click=handle_files_pick, + ), + upload_progress := ft.Column(), + upload_button := ft.Button( + content="Upload", + icon=ft.Icons.UPLOAD, + on_click=handle_file_upload, + disabled=True, + ), + ], + ), + ) ) -ft.run(main, upload_dir="examples") +if __name__ == "__main__": + ft.run(main, upload_dir="examples") diff --git a/sdk/python/examples/services/file_picker/pick_and_upload/pyproject.toml b/sdk/python/examples/services/file_picker/pick_and_upload/pyproject.toml new file mode 100644 index 0000000000..16f310155b --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_and_upload/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-file-picker-pick-and-upload" +version = "1.0.0" +description = "Picks multiple files in web mode and uploads them with live progress indicators." +requires-python = ">=3.10" +keywords = ["file picker", "pick and upload", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/FilePicker"] + +[tool.flet.metadata] +title = "Pick and upload files" +controls = ["SafeArea", "Column", "FilePicker", "FilePickerFile", "Page", "Text", "ProgressRing", "FilePickerUploadEvent"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["file upload", "upload progress"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["web"] diff --git a/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path.py b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path.py deleted file mode 100644 index f9677e67cd..0000000000 --- a/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path.py +++ /dev/null @@ -1,53 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - async def handle_pick_files(e: ft.Event[ft.Button]): - files = await ft.FilePicker().pick_files(allow_multiple=True) - selected_files.value = ( - ", ".join(map(lambda f: f.name, files)) if files else "Cancelled!" - ) - - async def handle_save_file(e: ft.Event[ft.Button]): - save_file_path.value = await ft.FilePicker().save_file() - - async def handle_get_directory_path(e: ft.Event[ft.Button]): - directory_path.value = await ft.FilePicker().get_directory_path() - - page.add( - ft.Row( - controls=[ - ft.Button( - content="Pick files", - icon=ft.Icons.UPLOAD_FILE, - on_click=handle_pick_files, - ), - selected_files := ft.Text(), - ] - ), - ft.Row( - controls=[ - ft.Button( - content="Save file", - icon=ft.Icons.SAVE, - on_click=handle_save_file, - disabled=page.web, # disable this button in web mode - ), - save_file_path := ft.Text(), - ] - ), - ft.Row( - controls=[ - ft.Button( - content="Open directory", - icon=ft.Icons.FOLDER_OPEN, - on_click=handle_get_directory_path, - disabled=page.web, # disable this button in web mode - ), - directory_path := ft.Text(), - ] - ), - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/main.py b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/main.py new file mode 100644 index 0000000000..855604f2b9 --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/main.py @@ -0,0 +1,60 @@ +import flet as ft + + +def main(page: ft.Page): + async def handle_pick_files(e: ft.Event[ft.Button]): + files = await ft.FilePicker().pick_files(allow_multiple=True) + selected_files.value = ( + ", ".join(map(lambda f: f.name, files)) if files else "Cancelled!" + ) + + async def handle_save_file(e: ft.Event[ft.Button]): + save_file_path.value = await ft.FilePicker().save_file() + + async def handle_get_directory_path(e: ft.Event[ft.Button]): + directory_path.value = await ft.FilePicker().get_directory_path() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Button( + content="Pick files", + icon=ft.Icons.UPLOAD_FILE, + on_click=handle_pick_files, + ), + selected_files := ft.Text(), + ] + ), + ft.Row( + controls=[ + ft.Button( + content="Save file", + icon=ft.Icons.SAVE, + on_click=handle_save_file, + disabled=page.web, # disable this button in web mode + ), + save_file_path := ft.Text(), + ] + ), + ft.Row( + controls=[ + ft.Button( + content="Open directory", + icon=ft.Icons.FOLDER_OPEN, + on_click=handle_get_directory_path, + disabled=page.web, # disable this button in web mode + ), + directory_path := ft.Text(), + ] + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/pyproject.toml b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/pyproject.toml new file mode 100644 index 0000000000..7fd8487e16 --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-file-picker-pick-save-and-get-directory-path" +version = "1.0.0" +description = "Demonstrates file picking, save dialogs, and directory selection in one example." +requires-python = ">=3.10" +keywords = ["file picker", "pick save and get directory path", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/FilePicker"] + +[tool.flet.metadata] +title = "Pick, save, and browse directories" +controls = ["SafeArea", "Column", "Page", "Button", "FilePicker", "Row", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["file picking", "save dialog", "directory picker"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/flashlight/example_1.py b/sdk/python/examples/services/flashlight/example_1.py deleted file mode 100644 index cb098b18f0..0000000000 --- a/sdk/python/examples/services/flashlight/example_1.py +++ /dev/null @@ -1,18 +0,0 @@ -import flet as ft -import flet_flashlight as ffl - - -def main(page: ft.Page): - async def turn_on_flashlight(): - await ffl.Flashlight().on() - - async def turn_off_flashlight(): - await ffl.Flashlight().off() - - page.add( - ft.Button("Turn On Flashlight", on_click=turn_on_flashlight), - ft.Button("Turn Off Flashlight", on_click=turn_off_flashlight), - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/flashlight/example_1/main.py b/sdk/python/examples/services/flashlight/example_1/main.py new file mode 100644 index 0000000000..453c7682be --- /dev/null +++ b/sdk/python/examples/services/flashlight/example_1/main.py @@ -0,0 +1,25 @@ +import flet as ft +import flet_flashlight as ffl + + +def main(page: ft.Page): + async def turn_on_flashlight(): + await ffl.Flashlight().on() + + async def turn_off_flashlight(): + await ffl.Flashlight().off() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button("Turn On Flashlight", on_click=turn_on_flashlight), + ft.Button("Turn Off Flashlight", on_click=turn_off_flashlight), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/flashlight/example_1/pyproject.toml b/sdk/python/examples/services/flashlight/example_1/pyproject.toml new file mode 100644 index 0000000000..4e44c44f1f --- /dev/null +++ b/sdk/python/examples/services/flashlight/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-flashlight-example-1" +version = "1.0.0" +description = "Turns the device flashlight on and off with two simple actions." +requires-python = ">=3.10" +keywords = ["flashlight", "example 1", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-flashlight"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Flashlight"] + +[tool.flet.metadata] +title = "Flashlight example" +controls = ["SafeArea", "Column", "Page", "Flashlight", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["flashlight toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["ios", "android"] diff --git a/sdk/python/examples/services/geolocator/example_1.py b/sdk/python/examples/services/geolocator/example_1/main.py similarity index 58% rename from sdk/python/examples/services/geolocator/example_1.py rename to sdk/python/examples/services/geolocator/example_1/main.py index eef035f3c1..cb8de409fd 100644 --- a/sdk/python/examples/services/geolocator/example_1.py +++ b/sdk/python/examples/services/geolocator/example_1/main.py @@ -75,43 +75,52 @@ async def handle_open_app_settings(e: ft.Event[ft.OutlinedButton]): ) page.add( - ft.Row( - wrap=True, - controls=[ - ft.OutlinedButton( - content="Request Permission", - on_click=handle_permission_request, - ), - ft.OutlinedButton( - content="Get Permission Status", - on_click=handle_get_permission_status, - ), - ft.OutlinedButton( - content="Get Current Position", - on_click=handle_get_current_position, - ), - ft.OutlinedButton( - content="Get Last Known Position", - visible=not page.web, - on_click=handle_get_last_known_position, - ), - ft.OutlinedButton( - content="Is Location Service Enabled", - on_click=handle_location_service_enabled, - ), - ft.OutlinedButton( - content="Open Location Settings", - visible=not page.web, # (1)! - on_click=lambda e: page.show_dialog(location_settings_dlg), - ), - ft.OutlinedButton( - content="Open App Settings", - visible=not page.web, # (1)! - on_click=lambda e: page.show_dialog(app_settings_dlg), - ), - ], + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + wrap=True, + controls=[ + ft.OutlinedButton( + content="Request Permission", + on_click=handle_permission_request, + ), + ft.OutlinedButton( + content="Get Permission Status", + on_click=handle_get_permission_status, + ), + ft.OutlinedButton( + content="Get Current Position", + on_click=handle_get_current_position, + ), + ft.OutlinedButton( + content="Get Last Known Position", + visible=not page.web, + on_click=handle_get_last_known_position, + ), + ft.OutlinedButton( + content="Is Location Service Enabled", + on_click=handle_location_service_enabled, + ), + ft.OutlinedButton( + content="Open Location Settings", + visible=not page.web, # (1)! + on_click=lambda e: page.show_dialog( + location_settings_dlg + ), + ), + ft.OutlinedButton( + content="Open App Settings", + visible=not page.web, # (1)! + on_click=lambda e: page.show_dialog(app_settings_dlg), + ), + ], + ) + ], + ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/geolocator/example_1/pyproject.toml b/sdk/python/examples/services/geolocator/example_1/pyproject.toml new file mode 100644 index 0000000000..4092dee562 --- /dev/null +++ b/sdk/python/examples/services/geolocator/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-geolocator-example-1" +version = "1.0.0" +description = "Requests location permissions and exercises geolocator actions from one dashboard." +requires-python = ">=3.10" +keywords = ["geolocator", "example 1", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-geolocator"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Geolocator"] + +[tool.flet.metadata] +title = "Geolocator example" +controls = ["SafeArea", "Column", "Page", "AppBar", "Text", "GeolocatorPositionChangeEvent", "TextButton", "OutlinedButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["permission handling", "location actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/gyroscope/basic.py b/sdk/python/examples/services/gyroscope/basic/main.py similarity index 61% rename from sdk/python/examples/services/gyroscope/basic.py rename to sdk/python/examples/services/gyroscope/basic/main.py index a54c9d9b7e..9221e246cd 100644 --- a/sdk/python/examples/services/gyroscope/basic.py +++ b/sdk/python/examples/services/gyroscope/basic/main.py @@ -4,7 +4,6 @@ def main(page: ft.Page): def handle_reading(e: ft.GyroscopeReadingEvent): reading.value = f"x={e.x:.2f} rad/s, y={e.y:.2f} rad/s, z={e.z:.2f} rad/s" - page.update() def handle_error(e: ft.SensorErrorEvent): page.add(ft.Text(f"Gyroscope error: {e.message}")) @@ -18,9 +17,16 @@ def handle_error(e: ft.SensorErrorEvent): ) page.add( - ft.Text("Rotate your device to see gyroscope readings."), - reading := ft.Text("Waiting for data..."), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Rotate your device to see gyroscope readings."), + reading := ft.Text("Waiting for data..."), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/gyroscope/basic/pyproject.toml b/sdk/python/examples/services/gyroscope/basic/pyproject.toml new file mode 100644 index 0000000000..6d4b9c2ca3 --- /dev/null +++ b/sdk/python/examples/services/gyroscope/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-gyroscope-basic" +version = "1.0.0" +description = "Streams gyroscope rotation readings and reports sensor errors from supported devices." +requires-python = ">=3.10" +keywords = ["gyroscope", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Gyroscope"] + +[tool.flet.metadata] +title = "Basic gyroscope" +controls = ["SafeArea", "Column", "Page", "GyroscopeReadingEvent", "Text", "Gyroscope"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios", "web"] diff --git a/sdk/python/examples/services/haptic_feedback/basic.py b/sdk/python/examples/services/haptic_feedback/basic.py deleted file mode 100644 index 158586aac9..0000000000 --- a/sdk/python/examples/services/haptic_feedback/basic.py +++ /dev/null @@ -1,27 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - hf = ft.HapticFeedback() - - async def heavy_impact(): - await hf.heavy_impact() - - async def medium_impact(): - await hf.medium_impact() - - async def light_impact(): - await hf.light_impact() - - async def vibrate(): - await hf.vibrate() - - page.add( - ft.Button("Heavy impact", on_click=heavy_impact), - ft.Button("Medium impact", on_click=medium_impact), - ft.Button("Light impact", on_click=light_impact), - ft.Button("Vibrate", on_click=vibrate), - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/haptic_feedback/basic/main.py b/sdk/python/examples/services/haptic_feedback/basic/main.py new file mode 100644 index 0000000000..1c5654e46e --- /dev/null +++ b/sdk/python/examples/services/haptic_feedback/basic/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + hf = ft.HapticFeedback() + + async def heavy_impact(): + await hf.heavy_impact() + + async def medium_impact(): + await hf.medium_impact() + + async def light_impact(): + await hf.light_impact() + + async def vibrate(): + await hf.vibrate() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button("Heavy impact", on_click=heavy_impact), + ft.Button("Medium impact", on_click=medium_impact), + ft.Button("Light impact", on_click=light_impact), + ft.Button("Vibrate", on_click=vibrate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/haptic_feedback/basic/pyproject.toml b/sdk/python/examples/services/haptic_feedback/basic/pyproject.toml new file mode 100644 index 0000000000..740c7167ca --- /dev/null +++ b/sdk/python/examples/services/haptic_feedback/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-haptic-feedback-basic" +version = "1.0.0" +description = "Triggers heavy, medium, light, and vibration haptic feedback actions." +requires-python = ">=3.10" +keywords = ["haptic feedback", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/HapticFeedback"] + +[tool.flet.metadata] +title = "Basic haptic feedback" +controls = ["SafeArea", "Column", "Page", "HapticFeedback", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["haptic feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/magnetometer/basic.py b/sdk/python/examples/services/magnetometer/basic/main.py similarity index 62% rename from sdk/python/examples/services/magnetometer/basic.py rename to sdk/python/examples/services/magnetometer/basic/main.py index 5790dc85ae..06241d144e 100644 --- a/sdk/python/examples/services/magnetometer/basic.py +++ b/sdk/python/examples/services/magnetometer/basic/main.py @@ -4,7 +4,6 @@ def main(page: ft.Page): def handle_reading(e: ft.MagnetometerReadingEvent): reading.value = f"x={e.x:.2f} uT, y={e.y:.2f} uT, z={e.z:.2f} uT" - page.update() def handle_error(e: ft.SensorErrorEvent): page.add(ft.Text(f"Magnetometer error: {e.message}")) @@ -18,9 +17,16 @@ def handle_error(e: ft.SensorErrorEvent): ) page.add( - ft.Text("Monitor the ambient magnetic field (uT)."), - reading := ft.Text("Waiting for data..."), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Monitor the ambient magnetic field (uT)."), + reading := ft.Text("Waiting for data..."), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/magnetometer/basic/pyproject.toml b/sdk/python/examples/services/magnetometer/basic/pyproject.toml new file mode 100644 index 0000000000..835c5d923f --- /dev/null +++ b/sdk/python/examples/services/magnetometer/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-magnetometer-basic" +version = "1.0.0" +description = "Streams ambient magnetic field readings and reports magnetometer errors." +requires-python = ">=3.10" +keywords = ["magnetometer", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Magnetometer"] + +[tool.flet.metadata] +title = "Basic magnetometer" +controls = ["SafeArea", "Column", "Page", "MagnetometerReadingEvent", "Text", "Magnetometer"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/permission_handler/example_1.py b/sdk/python/examples/services/permission_handler/example_1/main.py similarity index 59% rename from sdk/python/examples/services/permission_handler/example_1.py rename to sdk/python/examples/services/permission_handler/example_1/main.py index 44188a3231..3903d1ba1a 100644 --- a/sdk/python/examples/services/permission_handler/example_1.py +++ b/sdk/python/examples/services/permission_handler/example_1/main.py @@ -23,12 +23,22 @@ async def open_app_settings(e: ft.Event[ft.OutlinedButton]): ph = fph.PermissionHandler() page.add( - ft.OutlinedButton("Open app settings", on_click=open_app_settings), - ft.OutlinedButton("Request Microphone permission", on_click=request_permission), - ft.OutlinedButton( - "Get Microphone permission status", on_click=get_permission_status - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton("Open app settings", on_click=open_app_settings), + ft.OutlinedButton( + "Request Microphone permission", on_click=request_permission + ), + ft.OutlinedButton( + "Get Microphone permission status", + on_click=get_permission_status, + ), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/permission_handler/example_1/pyproject.toml b/sdk/python/examples/services/permission_handler/example_1/pyproject.toml new file mode 100644 index 0000000000..5f13c388a1 --- /dev/null +++ b/sdk/python/examples/services/permission_handler/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-permission-handler-example-1" +version = "1.0.0" +description = "Requests microphone permission, reads its status, and opens app settings." +requires-python = ">=3.10" +keywords = ["permission handler", "example 1", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-permission-handler"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/PermissionHandler"] + +[tool.flet.metadata] +title = "Permission handler example" +controls = ["SafeArea", "Column", "Page", "AppBar", "Text", "OutlinedButton", "PermissionHandler"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["permission request", "settings shortcut"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["windows", "ios", "android", "web"] diff --git a/sdk/python/examples/services/screen_brightness/basic.py b/sdk/python/examples/services/screen_brightness/basic/main.py similarity index 62% rename from sdk/python/examples/services/screen_brightness/basic.py rename to sdk/python/examples/services/screen_brightness/basic/main.py index c89585ad4f..d02d36cfb3 100644 --- a/sdk/python/examples/services/screen_brightness/basic.py +++ b/sdk/python/examples/services/screen_brightness/basic/main.py @@ -68,31 +68,42 @@ async def on_application_change(e: ft.ScreenBrightnessChangeEvent): auto_reset_switch.on_change = toggle_auto_reset page.add( - ft.Column( - [ - info, - level, - ft.Row( - [ - ft.Button( - "Set application", on_click=set_application_brightness - ), - ft.Button("Set system", on_click=set_system_brightness), - ft.TextButton( - "Reset application", on_click=reset_application_brightness - ), - ], - wrap=True, - ), - animate_switch, - auto_reset_switch, - ft.Divider(), - system_change, - app_change, - ], - spacing=12, + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + info, + level, + ft.Row( + [ + ft.Button( + "Set application", + on_click=set_application_brightness, + ), + ft.Button( + "Set system", on_click=set_system_brightness + ), + ft.TextButton( + "Reset application", + on_click=reset_application_brightness, + ), + ], + wrap=True, + ), + animate_switch, + auto_reset_switch, + ft.Divider(), + system_change, + app_change, + ], + spacing=12, + ) + ], + ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/screen_brightness/basic/pyproject.toml b/sdk/python/examples/services/screen_brightness/basic/pyproject.toml new file mode 100644 index 0000000000..cb1b2bb5eb --- /dev/null +++ b/sdk/python/examples/services/screen_brightness/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-screen-brightness-basic" +version = "1.0.0" +description = "Reads and adjusts system and application brightness with live change notifications." +requires-python = ">=3.10" +keywords = ["screen brightness", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/ScreenBrightness"] + +[tool.flet.metadata] +title = "Basic screen brightness" +controls = ["SafeArea", "Column", "Page", "ScreenBrightness", "Text", "Slider", "Switch", "Row"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["brightness control", "change events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/secure_storage/basic.py b/sdk/python/examples/services/secure_storage/basic/main.py similarity index 58% rename from sdk/python/examples/services/secure_storage/basic.py rename to sdk/python/examples/services/secure_storage/basic/main.py index 6e65a34fba..178b664f94 100644 --- a/sdk/python/examples/services/secure_storage/basic.py +++ b/sdk/python/examples/services/secure_storage/basic/main.py @@ -31,26 +31,21 @@ def main(page: ft.Page): async def set_value(e): await storage.set(key.value, value.value) result.value = "Value saved" - page.update() async def get_value(e): result.value = await storage.get(key.value) - page.update() async def remove_value(e): await storage.remove(key.value) result.value = "Value removed" - page.update() async def clear_storage(e): await storage.clear() result.value = "Storage cleared" - page.update() async def contains_key(e): exists = await storage.contains_key(key.value) result.value = f"Key exists: {exists}" - page.update() async def get_availability(e): is_availability = await storage.get_availability() @@ -63,32 +58,41 @@ async def get_availability(e): ) ) ) - page.update() page.add( - ft.Column( - alignment=ft.MainAxisAlignment.CENTER, - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - spacing=10, - controls=[ - result, - key, - value, - ft.Row( - width=300, - wrap=True, - controls=[ - ft.Button("Set", on_click=set_value), - ft.Button("Get", on_click=get_value), - ft.Button("Contains key", on_click=contains_key), - ft.Button("Remove", on_click=remove_value), - ft.Button("Clear", on_click=clear_storage), - ft.Button("Check Data Availability", on_click=get_availability), - ], - ), - ], - ), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=10, + controls=[ + result, + key, + value, + ft.Row( + width=300, + wrap=True, + controls=[ + ft.Button("Set", on_click=set_value), + ft.Button("Get", on_click=get_value), + ft.Button("Contains key", on_click=contains_key), + ft.Button("Remove", on_click=remove_value), + ft.Button("Clear", on_click=clear_storage), + ft.Button( + "Check Data Availability", + on_click=get_availability, + ), + ], + ), + ], + ) + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/secure_storage/basic/pyproject.toml b/sdk/python/examples/services/secure_storage/basic/pyproject.toml new file mode 100644 index 0000000000..3edbb5372f --- /dev/null +++ b/sdk/python/examples/services/secure_storage/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-secure-storage-basic" +version = "1.0.0" +description = "Stores, reads, removes, and clears protected key-value entries in secure storage." +requires-python = ">=3.10" +keywords = ["secure storage", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-secure-storage"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/SecureStorage"] + +[tool.flet.metadata] +title = "Basic secure storage" +controls = ["SafeArea", "Column", "Page", "SecureStorage", "TextField", "Text", "Row", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["protected storage", "key-value operations"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/semantics_service/accessibility_features.py b/sdk/python/examples/services/semantics_service/accessibility_features/main.py similarity index 77% rename from sdk/python/examples/services/semantics_service/accessibility_features.py rename to sdk/python/examples/services/semantics_service/accessibility_features/main.py index 3c5fe50e12..768bf9f44b 100644 --- a/sdk/python/examples/services/semantics_service/accessibility_features.py +++ b/sdk/python/examples/services/semantics_service/accessibility_features/main.py @@ -25,9 +25,16 @@ async def refresh_features(e: ft.Event[ft.Button]): info.value = await get_features() page.add( - info := ft.Text(await get_features()), - ft.Button("Refresh features", on_click=refresh_features), + ft.SafeArea( + content=ft.Column( + controls=[ + info := ft.Text(await get_features()), + ft.Button("Refresh features", on_click=refresh_features), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/semantics_service/accessibility_features/pyproject.toml b/sdk/python/examples/services/semantics_service/accessibility_features/pyproject.toml new file mode 100644 index 0000000000..bd2f6a04da --- /dev/null +++ b/sdk/python/examples/services/semantics_service/accessibility_features/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-semantics-service-accessibility-features" +version = "1.0.0" +description = "Reads accessibility feature flags from SemanticsService and refreshes them on demand." +requires-python = ">=3.10" +keywords = ["semantics service", "accessibility features", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/SemanticsService"] + +[tool.flet.metadata] +title = "Accessibility features" +controls = ["SafeArea", "Column", "Page", "SemanticsService", "Button", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["accessibility features"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/shake_detector/basic.py b/sdk/python/examples/services/shake_detector/basic/main.py similarity index 60% rename from sdk/python/examples/services/shake_detector/basic.py rename to sdk/python/examples/services/shake_detector/basic/main.py index 09d0a63c89..eb4b47ecc5 100644 --- a/sdk/python/examples/services/shake_detector/basic.py +++ b/sdk/python/examples/services/shake_detector/basic/main.py @@ -11,7 +11,14 @@ def main(page: ft.Page): ) ) - page.add(ft.Text("Shake your device!")) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Text("Shake your device!")], + ), + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/shake_detector/basic/pyproject.toml b/sdk/python/examples/services/shake_detector/basic/pyproject.toml new file mode 100644 index 0000000000..f0efd2e0ef --- /dev/null +++ b/sdk/python/examples/services/shake_detector/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-shake-detector-basic" +version = "1.0.0" +description = "Detects shake gestures and appends a message each time a shake is recognized." +requires-python = ">=3.10" +keywords = ["shake detector", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/ShakeDetector"] + +[tool.flet.metadata] +title = "Basic shake detector" +controls = ["SafeArea", "Column", "Page", "ShakeDetector", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["shake detection"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/share/basic.py b/sdk/python/examples/services/share/basic/main.py similarity index 98% rename from sdk/python/examples/services/share/basic.py rename to sdk/python/examples/services/share/basic/main.py index f600389ccd..56a339d125 100644 --- a/sdk/python/examples/services/share/basic.py +++ b/sdk/python/examples/services/share/basic/main.py @@ -80,4 +80,5 @@ async def do_share_files_from_paths(): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/share/basic/pyproject.toml b/sdk/python/examples/services/share/basic/pyproject.toml new file mode 100644 index 0000000000..14f7b4d308 --- /dev/null +++ b/sdk/python/examples/services/share/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-share-basic" +version = "1.0.0" +description = "Shares text, links, and files while showing the raw share result status." +requires-python = ">=3.10" +keywords = ["share", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Share"] + +[tool.flet.metadata] +title = "Basic share" +controls = ["SafeArea", "Column", "Page", "Share", "Text", "Row", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["share sheet", "file sharing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/sharedpreferences/basic.py b/sdk/python/examples/services/sharedpreferences/basic.py deleted file mode 100644 index 4222b97cd2..0000000000 --- a/sdk/python/examples/services/sharedpreferences/basic.py +++ /dev/null @@ -1,37 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - async def set_value(): - await ft.SharedPreferences().set(store_key.value, store_value.value) - get_key.value = store_key.value - store_key.value = "" - store_value.value = "" - page.show_dialog(ft.SnackBar("Value saved to SharedPreferences")) - - async def get_value(): - contents = await ft.SharedPreferences().get(get_key.value) - page.add(ft.Text(f"SharedPreferences contents: {contents}")) - - page.add( - ft.Column( - [ - ft.Row( - [ - store_key := ft.TextField(label="Key"), - store_value := ft.TextField(label="Value"), - ft.Button("Set", on_click=set_value), - ] - ), - ft.Row( - [ - get_key := ft.TextField(label="Key"), - ft.Button("Get", on_click=get_value), - ] - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/sharedpreferences/basic/main.py b/sdk/python/examples/services/sharedpreferences/basic/main.py new file mode 100644 index 0000000000..89f93cb338 --- /dev/null +++ b/sdk/python/examples/services/sharedpreferences/basic/main.py @@ -0,0 +1,44 @@ +import flet as ft + + +async def main(page: ft.Page): + async def set_value(): + await ft.SharedPreferences().set(store_key.value, store_value.value) + get_key.value = store_key.value + store_key.value = "" + store_value.value = "" + page.show_dialog(ft.SnackBar("Value saved to SharedPreferences")) + + async def get_value(): + contents = await ft.SharedPreferences().get(get_key.value) + page.add(ft.Text(f"SharedPreferences contents: {contents}")) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + ft.Row( + [ + store_key := ft.TextField(label="Key"), + store_value := ft.TextField(label="Value"), + ft.Button("Set", on_click=set_value), + ] + ), + ft.Row( + [ + get_key := ft.TextField(label="Key"), + ft.Button("Get", on_click=get_value), + ] + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/sharedpreferences/basic/pyproject.toml b/sdk/python/examples/services/sharedpreferences/basic/pyproject.toml new file mode 100644 index 0000000000..16c3f3b86c --- /dev/null +++ b/sdk/python/examples/services/sharedpreferences/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-sharedpreferences-basic" +version = "1.0.0" +description = "Writes and reads plain SharedPreferences values using keyed inputs." +requires-python = ">=3.10" +keywords = ["sharedpreferences", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/SharedPreferences"] + +[tool.flet.metadata] +title = "Basic shared preferences" +controls = ["SafeArea", "Column", "Page", "SharedPreferences", "Text", "Row", "TextField", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["key-value storage"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/storagepaths/basic.py b/sdk/python/examples/services/storagepaths/basic/main.py similarity index 89% rename from sdk/python/examples/services/storagepaths/basic.py rename to sdk/python/examples/services/storagepaths/basic/main.py index d9ab1e06e3..2ceacefd62 100644 --- a/sdk/python/examples/services/storagepaths/basic.py +++ b/sdk/python/examples/services/storagepaths/basic/main.py @@ -49,7 +49,14 @@ async def main(page: ft.Page): ) ) - page.add(ft.Column(items, spacing=5)) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Column(items, spacing=5)], + ), + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/storagepaths/basic/pyproject.toml b/sdk/python/examples/services/storagepaths/basic/pyproject.toml new file mode 100644 index 0000000000..e17156a753 --- /dev/null +++ b/sdk/python/examples/services/storagepaths/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-storagepaths-basic" +version = "1.0.0" +description = "Lists storage path APIs and shows unsupported-path errors on the current platform." +requires-python = ">=3.10" +keywords = ["storagepaths", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Storagepaths"] + +[tool.flet.metadata] +title = "Basic storage paths" +controls = ["SafeArea", "Column", "Page", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["path discovery", "platform fallback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/urllauncher/basic.py b/sdk/python/examples/services/urllauncher/basic.py deleted file mode 100644 index 874cfa3551..0000000000 --- a/sdk/python/examples/services/urllauncher/basic.py +++ /dev/null @@ -1,81 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - url_launcher = ft.UrlLauncher() - - url = ft.TextField(label="URL to open", value="https://flet.dev", expand=True) - status = ft.Text() - - async def can_launch(): - can = await url_launcher.can_launch_url(url.value) - status.value = f"Can launch: {can}" - - async def launch_default(): - await url_launcher.launch_url(url.value) - - async def launch_in_app_webview(): - await url_launcher.launch_url( - url.value, - mode=ft.LaunchMode.IN_APP_WEB_VIEW, - web_view_configuration=ft.WebViewConfiguration( - enable_javascript=True, enable_dom_storage=True - ), - ) - - async def launch_in_app_browser_view(): - await url_launcher.launch_url( - url.value, - mode=ft.LaunchMode.IN_APP_BROWSER_VIEW, - browser_configuration=ft.BrowserConfiguration(show_title=True), - ) - - async def launch_external(): - await url_launcher.launch_url( - url.value, - mode=ft.LaunchMode.EXTERNAL_APPLICATION, - web_only_window_name="_blank", - ) - - async def launch_popup(): - await url_launcher.open_window( - url.value, title="Flet popup", width=480, height=640 - ) - - async def close_webview(_): - supported = await url_launcher.supports_close_for_launch_mode( - ft.LaunchMode.IN_APP_WEB_VIEW - ) - if supported: - await url_launcher.close_in_app_web_view() - else: - status.value = "Close in-app web view not supported on this platform" - - page.add( - ft.Column( - [ - url, - ft.Row( - [ - ft.Button("Launch URL", on_click=launch_default), - ft.Button( - "Launch in-app webview", on_click=launch_in_app_webview - ), - ft.Button( - "Launch in-app browser view", - on_click=launch_in_app_browser_view, - ), - ft.Button("Launch external/new tab", on_click=launch_external), - ft.Button("Open popup window (web)", on_click=launch_popup), - ft.Button("Can launch?", on_click=can_launch), - ft.Button("Close in-app webview", on_click=close_webview), - ], - wrap=True, - ), - status, - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/urllauncher/basic/main.py b/sdk/python/examples/services/urllauncher/basic/main.py new file mode 100644 index 0000000000..87a65e52e7 --- /dev/null +++ b/sdk/python/examples/services/urllauncher/basic/main.py @@ -0,0 +1,96 @@ +import flet as ft + + +async def main(page: ft.Page): + url_launcher = ft.UrlLauncher() + + url = ft.TextField(label="URL to open", value="https://flet.dev", expand=True) + status = ft.Text() + + async def can_launch(): + can = await url_launcher.can_launch_url(url.value) + status.value = f"Can launch: {can}" + + async def launch_default(): + await url_launcher.launch_url(url.value) + + async def launch_in_app_webview(): + await url_launcher.launch_url( + url.value, + mode=ft.LaunchMode.IN_APP_WEB_VIEW, + web_view_configuration=ft.WebViewConfiguration( + enable_javascript=True, enable_dom_storage=True + ), + ) + + async def launch_in_app_browser_view(): + await url_launcher.launch_url( + url.value, + mode=ft.LaunchMode.IN_APP_BROWSER_VIEW, + browser_configuration=ft.BrowserConfiguration(show_title=True), + ) + + async def launch_external(): + await url_launcher.launch_url( + url.value, + mode=ft.LaunchMode.EXTERNAL_APPLICATION, + web_only_window_name="_blank", + ) + + async def launch_popup(): + await url_launcher.open_window( + url.value, title="Flet popup", width=480, height=640 + ) + + async def close_webview(_): + supported = await url_launcher.supports_close_for_launch_mode( + ft.LaunchMode.IN_APP_WEB_VIEW + ) + if supported: + await url_launcher.close_in_app_web_view() + else: + status.value = "Close in-app web view not supported on this platform" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + url, + ft.Row( + [ + ft.Button("Launch URL", on_click=launch_default), + ft.Button( + "Launch in-app webview", + on_click=launch_in_app_webview, + ), + ft.Button( + "Launch in-app browser view", + on_click=launch_in_app_browser_view, + ), + ft.Button( + "Launch external/new tab", + on_click=launch_external, + ), + ft.Button( + "Open popup window (web)", on_click=launch_popup + ), + ft.Button("Can launch?", on_click=can_launch), + ft.Button( + "Close in-app webview", on_click=close_webview + ), + ], + wrap=True, + ), + status, + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/urllauncher/basic/pyproject.toml b/sdk/python/examples/services/urllauncher/basic/pyproject.toml new file mode 100644 index 0000000000..55cbfbbd63 --- /dev/null +++ b/sdk/python/examples/services/urllauncher/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-urllauncher-basic" +version = "1.0.0" +description = "Launches URLs in multiple modes including web view, browser view, and popup windows." +requires-python = ">=3.10" +keywords = ["urllauncher", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/UrlLauncher"] + +[tool.flet.metadata] +title = "Basic URL launcher" +controls = ["SafeArea", "Column", "Page", "UrlLauncher", "TextField", "Text", "LaunchMode", "WebViewConfiguration"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["URL launch modes", "popup window"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/user_accelerometer/basic.py b/sdk/python/examples/services/user_accelerometer/basic/main.py similarity index 55% rename from sdk/python/examples/services/user_accelerometer/basic.py rename to sdk/python/examples/services/user_accelerometer/basic/main.py index db6067e7e3..e95fd81062 100644 --- a/sdk/python/examples/services/user_accelerometer/basic.py +++ b/sdk/python/examples/services/user_accelerometer/basic/main.py @@ -4,7 +4,6 @@ def main(page: ft.Page): def handle_reading(e: ft.UserAccelerometerReadingEvent): reading.value = f"x={e.x:.2f} m/s^2, y={e.y:.2f} m/s^2, z={e.z:.2f} m/s^2" - page.update() def handle_error(e: ft.SensorErrorEvent): page.add(ft.Text(f"UserAccelerometer error: {e.message}")) @@ -18,12 +17,19 @@ def handle_error(e: ft.SensorErrorEvent): ) page.add( - ft.Text( - "Linear acceleration without gravity. " - "Keep the app running on a device with motion sensors." - ), - reading := ft.Text("Waiting for data..."), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Linear acceleration without gravity. " + "Keep the app running on a device with motion sensors." + ), + reading := ft.Text("Waiting for data..."), + ], + ), + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/user_accelerometer/basic/pyproject.toml b/sdk/python/examples/services/user_accelerometer/basic/pyproject.toml new file mode 100644 index 0000000000..42270d9aa1 --- /dev/null +++ b/sdk/python/examples/services/user_accelerometer/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-user-accelerometer-basic" +version = "1.0.0" +description = "Streams linear acceleration readings without gravity and reports sensor errors." +requires-python = ">=3.10" +keywords = ["user accelerometer", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/UserAccelerometer"] + +[tool.flet.metadata] +title = "Basic user accelerometer" +controls = ["SafeArea", "Column", "Page", "UserAccelerometerReadingEvent", "Text", "UserAccelerometer"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios", "web"] diff --git a/sdk/python/examples/services/wakelock/basic.py b/sdk/python/examples/services/wakelock/basic.py deleted file mode 100644 index 1adf678d6b..0000000000 --- a/sdk/python/examples/services/wakelock/basic.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft - - -async def main(page: ft.Page): - wakelock = ft.Wakelock() - - status = ft.Text() - - async def update_status(): - enabled = await wakelock.is_enabled() - status.value = f"Wakelock enabled: {enabled}" - - async def enable_lock(): - await wakelock.enable() - await update_status() - - async def disable_lock(): - await wakelock.disable() - await update_status() - - await update_status() - - page.add( - ft.Column( - [ - status, - ft.Row( - [ - ft.Button("Enable wakelock", on_click=enable_lock), - ft.Button("Disable wakelock", on_click=disable_lock), - ], - wrap=True, - ), - ], - ) - ) - - -ft.run(main) diff --git a/sdk/python/examples/services/wakelock/basic/main.py b/sdk/python/examples/services/wakelock/basic/main.py new file mode 100644 index 0000000000..bff1d937d5 --- /dev/null +++ b/sdk/python/examples/services/wakelock/basic/main.py @@ -0,0 +1,48 @@ +import flet as ft + + +async def main(page: ft.Page): + wakelock = ft.Wakelock() + + status = ft.Text() + + async def update_status(): + enabled = await wakelock.is_enabled() + status.value = f"Wakelock enabled: {enabled}" + + async def enable_lock(): + await wakelock.enable() + await update_status() + + async def disable_lock(): + await wakelock.disable() + await update_status() + + await update_status() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + status, + ft.Row( + [ + ft.Button("Enable wakelock", on_click=enable_lock), + ft.Button( + "Disable wakelock", on_click=disable_lock + ), + ], + wrap=True, + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/wakelock/basic/pyproject.toml b/sdk/python/examples/services/wakelock/basic/pyproject.toml new file mode 100644 index 0000000000..209319d073 --- /dev/null +++ b/sdk/python/examples/services/wakelock/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-wakelock-basic" +version = "1.0.0" +description = "Enables and disables wakelock while showing the current wakelock state." +requires-python = ">=3.10" +keywords = ["wakelock", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Services/Wakelock"] + +[tool.flet.metadata] +title = "Basic wakelock" +controls = ["SafeArea", "Column", "Page", "Wakelock", "Text", "Row", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["wakelock toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/audio_recorder/index.md b/sdk/python/packages/flet/docs/audio_recorder/index.md index 035aa9b6a0..d3d72a93fd 100644 --- a/sdk/python/packages/flet/docs/audio_recorder/index.md +++ b/sdk/python/packages/flet/docs/audio_recorder/index.md @@ -152,7 +152,7 @@ permissions = ["microphone"] ## Example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Description diff --git a/sdk/python/packages/flet/docs/flashlight/index.md b/sdk/python/packages/flet/docs/flashlight/index.md index 2c388330cd..ba00892439 100644 --- a/sdk/python/packages/flet/docs/flashlight/index.md +++ b/sdk/python/packages/flet/docs/flashlight/index.md @@ -34,7 +34,7 @@ pip install flet-flashlight # (1)! ## Example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Description diff --git a/sdk/python/packages/flet/docs/geolocator/index.md b/sdk/python/packages/flet/docs/geolocator/index.md index 87f9832fa0..e57488a8ed 100644 --- a/sdk/python/packages/flet/docs/geolocator/index.md +++ b/sdk/python/packages/flet/docs/geolocator/index.md @@ -145,7 +145,7 @@ permissions = ["location"] ## Example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Description diff --git a/sdk/python/packages/flet/docs/permission_handler/index.md b/sdk/python/packages/flet/docs/permission_handler/index.md index 105d0c9e69..7896720609 100644 --- a/sdk/python/packages/flet/docs/permission_handler/index.md +++ b/sdk/python/packages/flet/docs/permission_handler/index.md @@ -61,7 +61,7 @@ See: ## Example ```python ---8<-- "{{ examples }}/example_1.py" +--8<-- "{{ examples }}/example_1/main.py" ``` ## Description diff --git a/sdk/python/packages/flet/docs/secure_storage/index.md b/sdk/python/packages/flet/docs/secure_storage/index.md index a220c5313e..decb228612 100644 --- a/sdk/python/packages/flet/docs/secure_storage/index.md +++ b/sdk/python/packages/flet/docs/secure_storage/index.md @@ -47,7 +47,7 @@ pip install flet-secure-storage # (1)! ## Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` ## Description diff --git a/sdk/python/packages/flet/docs/services/barometer.md b/sdk/python/packages/flet/docs/services/barometer.md index dec579306d..ec8ff540c0 100644 --- a/sdk/python/packages/flet/docs/services/barometer.md +++ b/sdk/python/packages/flet/docs/services/barometer.md @@ -8,7 +8,7 @@ examples: ../../examples/services/barometer ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/battery.md b/sdk/python/packages/flet/docs/services/battery.md index 3384cfeb77..1b4f6bec37 100644 --- a/sdk/python/packages/flet/docs/services/battery.md +++ b/sdk/python/packages/flet/docs/services/battery.md @@ -8,7 +8,7 @@ examples: ../../examples/services/battery ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/browsercontextmenu.md b/sdk/python/packages/flet/docs/services/browsercontextmenu.md index a0d82b85b5..d57dc145ce 100644 --- a/sdk/python/packages/flet/docs/services/browsercontextmenu.md +++ b/sdk/python/packages/flet/docs/services/browsercontextmenu.md @@ -8,7 +8,7 @@ examples: ../../examples/services/browsercontextmenu ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/clipboard.md b/sdk/python/packages/flet/docs/services/clipboard.md index f3a60e7e04..82042d838b 100644 --- a/sdk/python/packages/flet/docs/services/clipboard.md +++ b/sdk/python/packages/flet/docs/services/clipboard.md @@ -10,19 +10,19 @@ examples: ../../examples/services/clipboard ### Text ```python ---8<-- "{{ examples }}/text.py" +--8<-- "{{ examples }}/text/main.py" ``` ### Images ```python ---8<-- "{{ examples }}/images.py" +--8<-- "{{ examples }}/images/main.py" ``` ### Files ```python ---8<-- "{{ examples }}/files.py" +--8<-- "{{ examples }}/files/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/connectivity.md b/sdk/python/packages/flet/docs/services/connectivity.md index 8de0f503ac..6ef4ddb49a 100644 --- a/sdk/python/packages/flet/docs/services/connectivity.md +++ b/sdk/python/packages/flet/docs/services/connectivity.md @@ -8,7 +8,7 @@ examples: ../../examples/services/connectivity ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/filepicker.md b/sdk/python/packages/flet/docs/services/filepicker.md index 501401d93f..1a72867874 100644 --- a/sdk/python/packages/flet/docs/services/filepicker.md +++ b/sdk/python/packages/flet/docs/services/filepicker.md @@ -90,7 +90,7 @@ ft.Image(src="/uploads/") ### Pick, save, and get directory paths ```python ---8<-- "{{ examples }}/pick_save_and_get_directory_path.py" +--8<-- "{{ examples }}/pick_save_and_get_directory_path/main.py" ``` {{ image(example_images + "/pick_save_and_get_directory_path.png", width="80%") }} @@ -102,7 +102,7 @@ The following example demonstrates multi-file [pick][flet.FilePicker.pick_files] and [upload][flet.FilePicker.upload] app. ```python ---8<-- "{{ examples }}/pick_and_upload.py" +--8<-- "{{ examples }}/pick_and_upload/main.py" ``` {{ image(example_images + "/pick_and_upload.png", width="80%") }} @@ -114,7 +114,7 @@ you need file contents directly, such as in web apps where [`FilePickerFile.path`][flet.FilePickerFile.path] is not available. ```python ---8<-- "{{ examples }}/pick_and_save_text_content.py" +--8<-- "{{ examples }}/pick_and_save_text_content/main.py" ``` diff --git a/sdk/python/packages/flet/docs/services/gyroscope.md b/sdk/python/packages/flet/docs/services/gyroscope.md index 3fe566142c..6500582a6b 100644 --- a/sdk/python/packages/flet/docs/services/gyroscope.md +++ b/sdk/python/packages/flet/docs/services/gyroscope.md @@ -8,7 +8,7 @@ examples: ../../examples/services/gyroscope ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/hapticfeedback.md b/sdk/python/packages/flet/docs/services/hapticfeedback.md index 2a43e26a0f..da034ad41c 100644 --- a/sdk/python/packages/flet/docs/services/hapticfeedback.md +++ b/sdk/python/packages/flet/docs/services/hapticfeedback.md @@ -10,7 +10,7 @@ examples: ../../examples/services/haptic_feedback ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/magnetometer.md b/sdk/python/packages/flet/docs/services/magnetometer.md index bb005ad90b..ddba403e53 100644 --- a/sdk/python/packages/flet/docs/services/magnetometer.md +++ b/sdk/python/packages/flet/docs/services/magnetometer.md @@ -8,7 +8,7 @@ examples: ../../examples/services/magnetometer ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/screenbrightness.md b/sdk/python/packages/flet/docs/services/screenbrightness.md index 236fb9b8ff..5abbf85b8b 100644 --- a/sdk/python/packages/flet/docs/services/screenbrightness.md +++ b/sdk/python/packages/flet/docs/services/screenbrightness.md @@ -8,7 +8,7 @@ examples: ../../examples/services/screen_brightness ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/semanticsservice.md b/sdk/python/packages/flet/docs/services/semanticsservice.md index 5eac64f5a5..0b3fd3a1d8 100644 --- a/sdk/python/packages/flet/docs/services/semanticsservice.md +++ b/sdk/python/packages/flet/docs/services/semanticsservice.md @@ -10,7 +10,7 @@ examples: ../../examples/services/semantics_service ### Retrieve accessibility features ```python ---8<-- "{{ examples }}/accessibility_features.py" +--8<-- "{{ examples }}/accessibility_features/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/shakedetector.md b/sdk/python/packages/flet/docs/services/shakedetector.md index 8a2759fe08..bedb4f009f 100644 --- a/sdk/python/packages/flet/docs/services/shakedetector.md +++ b/sdk/python/packages/flet/docs/services/shakedetector.md @@ -10,7 +10,7 @@ examples: ../../examples/services/shake_detector ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/share.md b/sdk/python/packages/flet/docs/services/share.md index 11f472ac3a..b0246baa49 100644 --- a/sdk/python/packages/flet/docs/services/share.md +++ b/sdk/python/packages/flet/docs/services/share.md @@ -8,7 +8,7 @@ examples: ../../examples/services/share ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/sharedpreferences.md b/sdk/python/packages/flet/docs/services/sharedpreferences.md index a3e4350229..727dd375d8 100644 --- a/sdk/python/packages/flet/docs/services/sharedpreferences.md +++ b/sdk/python/packages/flet/docs/services/sharedpreferences.md @@ -10,7 +10,7 @@ examples: ../../examples/services/sharedpreferences ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/storagepaths.md b/sdk/python/packages/flet/docs/services/storagepaths.md index 7166597d51..db0f6d8e41 100644 --- a/sdk/python/packages/flet/docs/services/storagepaths.md +++ b/sdk/python/packages/flet/docs/services/storagepaths.md @@ -10,7 +10,7 @@ examples: ../../examples/services/storagepaths ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/urllauncher.md b/sdk/python/packages/flet/docs/services/urllauncher.md index 691ce990c0..fea307f9e2 100644 --- a/sdk/python/packages/flet/docs/services/urllauncher.md +++ b/sdk/python/packages/flet/docs/services/urllauncher.md @@ -10,7 +10,7 @@ examples: ../../examples/services/urllauncher ### Basic Example ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/useraccelerometer.md b/sdk/python/packages/flet/docs/services/useraccelerometer.md index ab46a5cb3a..c81058a152 100644 --- a/sdk/python/packages/flet/docs/services/useraccelerometer.md +++ b/sdk/python/packages/flet/docs/services/useraccelerometer.md @@ -8,7 +8,7 @@ examples: ../../examples/services/user_accelerometer ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/docs/services/wakelock.md b/sdk/python/packages/flet/docs/services/wakelock.md index a232b62c33..56e6e474ca 100644 --- a/sdk/python/packages/flet/docs/services/wakelock.md +++ b/sdk/python/packages/flet/docs/services/wakelock.md @@ -8,7 +8,7 @@ examples: ../../examples/services/wakelock ## Examples ```python ---8<-- "{{ examples }}/basic.py" +--8<-- "{{ examples }}/basic/main.py" ``` {{ class_members(class_name) }} From 734498ed1de8fc746fdeb334076372a69b4424d9 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 10:08:36 -0700 Subject: [PATCH 85/96] Migrate authentication app examples --- .../main.py} | 13 +++++-- .../pyproject.toml | 26 ++++++++++++++ .../main.py} | 13 +++++-- .../github_login_same_page/pyproject.toml | 27 +++++++++++++++ .../main.py} | 13 +++++-- .../github_minimal/pyproject.toml | 26 ++++++++++++++ .../main.py} | 34 ++++++++++++------- .../github_repos_browser/pyproject.toml | 27 +++++++++++++++ .../main.py} | 13 +++++-- .../linkedin_login/pyproject.toml | 26 ++++++++++++++ .../flet/docs/cookbook/authentication.md | 4 +-- 11 files changed, 195 insertions(+), 27 deletions(-) rename sdk/python/examples/apps/authentication/{github_check_auth_results_and_toggle_ui.py => github_check_auth_results_and_toggle_ui/main.py} (84%) create mode 100644 sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/pyproject.toml rename sdk/python/examples/apps/authentication/{github_login_same_page.py => github_login_same_page/main.py} (81%) create mode 100644 sdk/python/examples/apps/authentication/github_login_same_page/pyproject.toml rename sdk/python/examples/apps/authentication/{github_minimal.py => github_minimal/main.py} (80%) create mode 100644 sdk/python/examples/apps/authentication/github_minimal/pyproject.toml rename sdk/python/examples/apps/authentication/{github_repos_browser.py => github_repos_browser/main.py} (83%) create mode 100644 sdk/python/examples/apps/authentication/github_repos_browser/pyproject.toml rename sdk/python/examples/apps/authentication/{linkedin_login.py => linkedin_login/main.py} (83%) create mode 100644 sdk/python/examples/apps/authentication/linkedin_login/pyproject.toml diff --git a/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui.py b/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/main.py similarity index 84% rename from sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui.py rename to sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/main.py index 0a8e080d12..e522d44aa7 100644 --- a/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui.py +++ b/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/main.py @@ -2,7 +2,7 @@ # Run this example with: # export GITHUB_CLIENT_ID= # export GITHUB_CLIENT_SECRET= -# flet run --web --port 8550 github_check_auth_results_and_toggle_ui.py +# flet run --web --port 8550 main.py # import os @@ -45,7 +45,14 @@ def toggle_login_buttons(): toggle_login_buttons() page.on_login = on_login page.on_logout = on_logout - page.add(login_button, logout_button) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[login_button, logout_button], + ) + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/pyproject.toml b/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/pyproject.toml new file mode 100644 index 0000000000..3966b375aa --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-authentication-github-check-auth-results-and-toggle-ui" +version = "1.0.0" +description = "Toggles GitHub sign-in and sign-out buttons based on authentication events." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "github", "oauth", "login", "web", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Authentication"] + +[tool.flet.metadata] +title = "GitHub auth button toggle" +controls = ["SafeArea", "Column", "Button", "GitHubOAuthProvider"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["oauth login", "oauth logout", "auth-aware UI"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/authentication/github_login_same_page.py b/sdk/python/examples/apps/authentication/github_login_same_page/main.py similarity index 81% rename from sdk/python/examples/apps/authentication/github_login_same_page.py rename to sdk/python/examples/apps/authentication/github_login_same_page/main.py index 3645ec1d6e..b7602104e6 100644 --- a/sdk/python/examples/apps/authentication/github_login_same_page.py +++ b/sdk/python/examples/apps/authentication/github_login_same_page/main.py @@ -2,7 +2,7 @@ # Run this example with: # export GITHUB_CLIENT_ID= # export GITHUB_CLIENT_SECRET= -# flet run --web --port 8550 github_login_same_page.py +# flet run --web --port 8550 main.py # import os @@ -39,7 +39,14 @@ async def on_login(e): page.add(ft.Text(f"User ID: {page.auth.user.id}")) page.on_login = on_login - page.add(ft.Button("Login with GitHub", on_click=login_click)) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Button("Login with GitHub", on_click=login_click)], + ) + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/github_login_same_page/pyproject.toml b/sdk/python/examples/apps/authentication/github_login_same_page/pyproject.toml new file mode 100644 index 0000000000..0645681806 --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_login_same_page/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "apps-authentication-github-login-same-page" +version = "1.0.0" +description = "Runs GitHub OAuth in the same browser tab and displays the authenticated user ID." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "github", "oauth", "redirect", "web", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Authentication"] + +[tool.flet.metadata] +title = "GitHub login in same page" +controls = ["SafeArea", "Column", "Button", "Text", "GitHubOAuthProvider", "UrlLauncher"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["oauth login", "same-tab redirect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["web"] diff --git a/sdk/python/examples/apps/authentication/github_minimal.py b/sdk/python/examples/apps/authentication/github_minimal/main.py similarity index 80% rename from sdk/python/examples/apps/authentication/github_minimal.py rename to sdk/python/examples/apps/authentication/github_minimal/main.py index 058c27cb1e..1c08ff2aed 100644 --- a/sdk/python/examples/apps/authentication/github_minimal.py +++ b/sdk/python/examples/apps/authentication/github_minimal/main.py @@ -2,7 +2,7 @@ # Run this example with: # export GITHUB_CLIENT_ID= # export GITHUB_CLIENT_SECRET= -# flet run --web --port 8550 github_minimal.py +# flet run --web --port 8550 main.py # import os @@ -37,7 +37,14 @@ async def on_login(e): ) page.on_login = on_login - page.add(ft.Button("Login with GitHub", on_click=login_click)) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Button("Login with GitHub", on_click=login_click)], + ) + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/github_minimal/pyproject.toml b/sdk/python/examples/apps/authentication/github_minimal/pyproject.toml new file mode 100644 index 0000000000..f46f8d54a3 --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_minimal/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-authentication-github-minimal" +version = "1.0.0" +description = "Shows a minimal GitHub OAuth login flow and prints the access token and user ID." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "github", "oauth", "login", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Authentication"] + +[tool.flet.metadata] +title = "Minimal GitHub login" +controls = ["SafeArea", "Column", "Button", "Text", "GitHubOAuthProvider"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["oauth login", "access token display"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/authentication/github_repos_browser.py b/sdk/python/examples/apps/authentication/github_repos_browser/main.py similarity index 83% rename from sdk/python/examples/apps/authentication/github_repos_browser.py rename to sdk/python/examples/apps/authentication/github_repos_browser/main.py index a11ee1a1e4..6b5c7a19dc 100644 --- a/sdk/python/examples/apps/authentication/github_repos_browser.py +++ b/sdk/python/examples/apps/authentication/github_repos_browser/main.py @@ -3,7 +3,7 @@ # export GITHUB_CLIENT_ID= # export GITHUB_CLIENT_SECRET= # export MY_APP_SECRET_KEY= -# flet run --web --port 8550 github_repos_browser.py +# flet run --web --port 8550 main.py # import json import logging @@ -25,26 +25,22 @@ def get_env_variable(name: str) -> str: async def main(page: ft.Page): - # encryption passphrase secret_key = get_env_variable("MY_APP_SECRET_KEY") - # configure provider provider = GitHubOAuthProvider( client_id=get_env_variable("GITHUB_CLIENT_ID"), client_secret=get_env_variable("GITHUB_CLIENT_SECRET"), redirect_url="http://127.0.0.1:8550/oauth_callback", ) - # client storage keys - AUTH_TOKEN_KEY = "myapp.auth_token" + auth_token_key = "myapp.auth_token" async def perform_login(e): login_button.disabled = True login_button.update() - # perform login saved_token = None - ejt = await ft.SharedPreferences().get(AUTH_TOKEN_KEY) + ejt = await ft.SharedPreferences().get(auth_token_key) if ejt: saved_token = decrypt(ejt, secret_key) if e is not None or saved_token is not None: @@ -64,15 +60,13 @@ async def on_login(e: ft.LoginEvent): assert page.auth - # save token in a client storage jt = (await page.auth.get_token()).to_json() ejt = encrypt(jt, secret_key) - await ft.SharedPreferences().set(AUTH_TOKEN_KEY, ejt) + await ft.SharedPreferences().set(auth_token_key, ejt) logged_user.value = f"Hello, {page.auth.user['name']}!" toggle_login_buttons() await list_github_repositories() - page.update() async def list_github_repositories(): repos_view.controls.clear() @@ -96,7 +90,7 @@ async def list_github_repositories(): ) async def logout_button_click(e): - await ft.SharedPreferences().remove(AUTH_TOKEN_KEY) + await ft.SharedPreferences().remove(auth_token_key) page.logout() async def on_logout(e): @@ -115,8 +109,22 @@ def toggle_login_buttons(): page.on_login = on_login page.on_logout = on_logout toggle_login_buttons() - page.add(ft.Row([logged_user, login_button, logout_button]), repos_view) + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Row( + controls=[logged_user, login_button, logout_button], + ), + repos_view, + ], + ), + ) + ) await perform_login(None) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/github_repos_browser/pyproject.toml b/sdk/python/examples/apps/authentication/github_repos_browser/pyproject.toml new file mode 100644 index 0000000000..87bf8f52da --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_repos_browser/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "apps-authentication-github-repos-browser" +version = "1.0.0" +description = "Logs in with GitHub, restores a saved token, and lists the signed-in user's repositories." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "github", "oauth", "repositories", "web", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "httpx"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Authentication"] + +[tool.flet.metadata] +title = "GitHub repos browser" +controls = ["SafeArea", "Column", "Row", "Text", "Button", "ListView", "ListTile", "GitHubOAuthProvider"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["oauth login", "saved token restore", "github api request"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["web"] diff --git a/sdk/python/examples/apps/authentication/linkedin_login.py b/sdk/python/examples/apps/authentication/linkedin_login/main.py similarity index 83% rename from sdk/python/examples/apps/authentication/linkedin_login.py rename to sdk/python/examples/apps/authentication/linkedin_login/main.py index b672735508..5c059b63ce 100644 --- a/sdk/python/examples/apps/authentication/linkedin_login.py +++ b/sdk/python/examples/apps/authentication/linkedin_login/main.py @@ -2,7 +2,7 @@ # Run this example with: # export LINKEDIN_CLIENT_ID= # export LINKEDIN_CLIENT_SECRET= -# flet run --web --port 8550 linkedin_login.py +# flet run --web --port 8550 main.py # import os @@ -42,7 +42,14 @@ async def on_login(e): ) page.on_login = on_login - page.add(ft.Button("Login with LinkedIn", on_click=login_click)) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Button("Login with LinkedIn", on_click=login_click)], + ) + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/linkedin_login/pyproject.toml b/sdk/python/examples/apps/authentication/linkedin_login/pyproject.toml new file mode 100644 index 0000000000..aab393c7db --- /dev/null +++ b/sdk/python/examples/apps/authentication/linkedin_login/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-authentication-linkedin-login" +version = "1.0.0" +description = "Authenticates with a custom LinkedIn OAuth provider and displays the token and user ID." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "linkedin", "oauth", "login", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Authentication"] + +[tool.flet.metadata] +title = "LinkedIn login" +controls = ["SafeArea", "Column", "Button", "Text", "OAuthProvider"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom oauth provider", "access token display"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/packages/flet/docs/cookbook/authentication.md b/sdk/python/packages/flet/docs/cookbook/authentication.md index f4787ead11..f65253c14c 100644 --- a/sdk/python/packages/flet/docs/cookbook/authentication.md +++ b/sdk/python/packages/flet/docs/cookbook/authentication.md @@ -340,7 +340,7 @@ if ejt: page.login(provider, saved_token=jt) ``` -[See complete app example](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/authentication/github_oauth_with_listing_repos.py). +[See complete app example](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/authentication/github_repos_browser/main.py). ## Signing out @@ -354,7 +354,7 @@ async def logout_button_click(e): page.logout() ``` -[See complete app example](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/authentication/github_oauth_with_listing_repos.py). +[See complete app example](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/authentication/github_repos_browser/main.py). ## Customizing authorization flow From 8def875f34b1764f1fc14911c6367f8f0a5ef866 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 10:14:40 -0700 Subject: [PATCH 86/96] Nest autocomplete searcher example under basic --- .../autocomplete_searcher/{ => basic}/main.py | 13 +++++++--- .../basic/pyproject.toml | 26 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) rename sdk/python/examples/apps/autocomplete_searcher/{ => basic}/main.py (81%) create mode 100644 sdk/python/examples/apps/autocomplete_searcher/basic/pyproject.toml diff --git a/sdk/python/examples/apps/autocomplete_searcher/main.py b/sdk/python/examples/apps/autocomplete_searcher/basic/main.py similarity index 81% rename from sdk/python/examples/apps/autocomplete_searcher/main.py rename to sdk/python/examples/apps/autocomplete_searcher/basic/main.py index a0fd627ca7..75fd7dda27 100644 --- a/sdk/python/examples/apps/autocomplete_searcher/main.py +++ b/sdk/python/examples/apps/autocomplete_searcher/basic/main.py @@ -38,7 +38,6 @@ def textbox_changed(string): if str_lower else [] ) - page.update() list_items = { name: ft.ListTile( @@ -51,7 +50,15 @@ def textbox_changed(string): text_field = ft.TextField(label="Search name:", on_change=textbox_changed) list_view = ft.ListView(expand=1, spacing=10, padding=20) - page.add(text_field, list_view) + page.add( + ft.SafeArea( + content=ft.Column( + expand=True, + controls=[text_field, list_view], + ) + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/autocomplete_searcher/basic/pyproject.toml b/sdk/python/examples/apps/autocomplete_searcher/basic/pyproject.toml new file mode 100644 index 0000000000..f914ce7d3e --- /dev/null +++ b/sdk/python/examples/apps/autocomplete_searcher/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-autocomplete-searcher-basic" +version = "1.0.0" +description = "Filters a list of names as the user types into an autocomplete-style search field." +requires-python = ">=3.10" +keywords = ["apps", "autocomplete", "search", "list filtering", "text field"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Search"] + +[tool.flet.metadata] +title = "Autocomplete searcher" +controls = ["SafeArea", "Column", "TextField", "ListView", "ListTile", "Text", "Icon"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["live filtering", "search suggestions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" From 4cc573c5aee4a83b0ebaa7c02ca90dd171e520a4 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 10:15:44 -0700 Subject: [PATCH 87/96] Remove unused controls gallery folder --- sdk/python/examples/apps/controls_gallery/README.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 sdk/python/examples/apps/controls_gallery/README.md diff --git a/sdk/python/examples/apps/controls_gallery/README.md b/sdk/python/examples/apps/controls_gallery/README.md deleted file mode 100644 index 48e191b88c..0000000000 --- a/sdk/python/examples/apps/controls_gallery/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Flet Gallery app - -Flet Gallery app has been moved to https://github.com/flet-dev/gallery. From 6675f1dbb6ce8a2e1d229690e9d20d97bd637a3b Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 10:24:34 -0700 Subject: [PATCH 88/96] Migrate counter app examples --- .../examples/apps/counter/accessible/main.py | 73 +++++++++++++++++++ .../apps/counter/accessible/pyproject.toml | 26 +++++++ .../examples/apps/counter/basic/main.py | 36 +++++++++ .../apps/counter/basic/pyproject.toml | 26 +++++++ sdk/python/examples/apps/counter/counter.py | 33 --------- .../apps/counter/counter_accessible.py | 50 ------------- .../examples/apps/counter/requirements.txt | 1 - .../examples/apps/counter/test_counter_app.py | 42 ----------- sdk/python/examples/publish-gallery.sh | 2 +- 9 files changed, 162 insertions(+), 127 deletions(-) create mode 100644 sdk/python/examples/apps/counter/accessible/main.py create mode 100644 sdk/python/examples/apps/counter/accessible/pyproject.toml create mode 100644 sdk/python/examples/apps/counter/basic/main.py create mode 100644 sdk/python/examples/apps/counter/basic/pyproject.toml delete mode 100644 sdk/python/examples/apps/counter/counter.py delete mode 100644 sdk/python/examples/apps/counter/counter_accessible.py delete mode 100644 sdk/python/examples/apps/counter/requirements.txt delete mode 100644 sdk/python/examples/apps/counter/test_counter_app.py diff --git a/sdk/python/examples/apps/counter/accessible/main.py b/sdk/python/examples/apps/counter/accessible/main.py new file mode 100644 index 0000000000..77fbed7129 --- /dev/null +++ b/sdk/python/examples/apps/counter/accessible/main.py @@ -0,0 +1,73 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Counter" + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + txt_number = ft.TextField( + value="0", + text_align=ft.TextAlign.RIGHT, + width=100, + label="Counter value", + ) + + def toggle_semantics_debugger(e): + page.show_semantics_debugger = not page.show_semantics_debugger + page.update() + + def minus_click(e): + txt_number.value = str(int(txt_number.value) - 1) + txt_number.label = f"Counter value, {txt_number.value}" + page.update() + + def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + txt_number.label = f"Counter value, {txt_number.value}" + page.update() + + page.on_keyboard_event = toggle_semantics_debugger + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Semantics( + label=( + "Press plus button to increase counter, " + "or minus button to decrease counter." + ), + hint_text=( + "Press CONTROL plus ALT plus S to show semantics debugger" + ), + button=True, + content=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.IconButton( + icon=ft.Icons.REMOVE, + tooltip="Decrease number", + on_click=minus_click, + ), + txt_number, + ft.IconButton( + icon=ft.Icons.ADD, + tooltip="Increase number", + on_click=plus_click, + ), + ], + ), + ), + ft.Text( + value=( + "Press CONTROL plus ALT plus S to show semantics debugger" + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/counter/accessible/pyproject.toml b/sdk/python/examples/apps/counter/accessible/pyproject.toml new file mode 100644 index 0000000000..2cc168af1c --- /dev/null +++ b/sdk/python/examples/apps/counter/accessible/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-counter-accessible" +version = "1.0.0" +description = "Accessible counter app with semantics labels and a keyboard shortcut for the semantics debugger." +requires-python = ">=3.10" +keywords = ["apps", "counter", "accessibility", "semantics", "keyboard"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Accessibility"] + +[tool.flet.metadata] +title = "Accessible counter" +controls = ["SafeArea", "Column", "Row", "IconButton", "TextField", "Semantics", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["accessible semantics", "keyboard shortcut", "counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/counter/basic/main.py b/sdk/python/examples/apps/counter/basic/main.py new file mode 100644 index 0000000000..c70e8b234e --- /dev/null +++ b/sdk/python/examples/apps/counter/basic/main.py @@ -0,0 +1,36 @@ +import flet as ft + +ft.context.disable_auto_update() + + +def main(page: ft.Page): + page.title = "Counter" + txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + + def minus_click(e): + txt_number.value = str(int(txt_number.value) - 1) + page.update() + + def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), + txt_number, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ] + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/counter/basic/pyproject.toml b/sdk/python/examples/apps/counter/basic/pyproject.toml new file mode 100644 index 0000000000..9b57164057 --- /dev/null +++ b/sdk/python/examples/apps/counter/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-counter-basic" +version = "1.0.0" +description = "Classic counter app with increment and decrement buttons around a numeric text field." +requires-python = ">=3.10" +keywords = ["apps", "counter", "buttons", "text field", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Basic"] + +[tool.flet.metadata] +title = "Basic counter" +controls = ["SafeArea", "Column", "Row", "IconButton", "TextField"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/counter/counter.py b/sdk/python/examples/apps/counter/counter.py deleted file mode 100644 index d8f2926d60..0000000000 --- a/sdk/python/examples/apps/counter/counter.py +++ /dev/null @@ -1,33 +0,0 @@ -import flet as ft - -ft.context.disable_auto_update() - - -def main(page: ft.Page): - page.title = "Flet counter example" - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) - - def minus_click(e): - txt_number.value = str(int(txt_number.value) - 1) - page.update() - - def plus_click(e): - txt_number.value = str(int(txt_number.value) + 1) - page.update() - - page.add( - ft.Row( - [ - ft.IconButton(ft.Icons.REMOVE, on_click=minus_click, key="decrement"), - txt_number, - ft.IconButton(ft.Icons.ADD, on_click=plus_click), - ], - alignment=ft.MainAxisAlignment.CENTER, - ) - ) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/apps/counter/counter_accessible.py b/sdk/python/examples/apps/counter/counter_accessible.py deleted file mode 100644 index f0ab036cb3..0000000000 --- a/sdk/python/examples/apps/counter/counter_accessible.py +++ /dev/null @@ -1,50 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Flet counter example" - page.vertical_alignment = ft.MainAxisAlignment.CENTER - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.spacing = 50 - - def on_keyboard(e: ft.KeyboardEvent): - print(e) - if e.key == "S" and e.ctrl: - page.show_semantics_debugger = not page.show_semantics_debugger - page.update() - - page.on_keyboard_event = on_keyboard - - txt_number = ft.TextField( - label="Number", value="0", text_align=ft.TextAlign.RIGHT, width=100 - ) - sem = ft.Semantics(txt_number, label="Current number: 0") - - def button_click(e): - txt_number.value = str( - int(txt_number.value) + (1 if e.control.data == "+" else -1) - ) - sem.label = f"Current number: {txt_number.value}" - page.update() - - page.add( - ft.Row( - [ - ft.IconButton( - ft.Icons.REMOVE, - tooltip="Decrement", - on_click=button_click, - data="-", - ), - sem, - ft.IconButton( - ft.Icons.ADD, tooltip="Increment", on_click=button_click, data="+" - ), - ], - alignment=ft.MainAxisAlignment.CENTER, - ), - ft.Text("Press CTRL+S to toggle semantics debugger"), - ) - - -ft.run(main) diff --git a/sdk/python/examples/apps/counter/requirements.txt b/sdk/python/examples/apps/counter/requirements.txt deleted file mode 100644 index 9f5592458b..0000000000 --- a/sdk/python/examples/apps/counter/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet>=0.25.1 diff --git a/sdk/python/examples/apps/counter/test_counter_app.py b/sdk/python/examples/apps/counter/test_counter_app.py deleted file mode 100644 index e42d777d81..0000000000 --- a/sdk/python/examples/apps/counter/test_counter_app.py +++ /dev/null @@ -1,42 +0,0 @@ -from pathlib import Path - -import counter as app -import flet as ft -import flet.testing as ftt -import pytest -import pytest_asyncio - - -@pytest_asyncio.fixture(scope="module") -async def flet_app(request): - flet_app = ftt.FletTestApp( - flutter_app_dir=(Path(__file__).parent / "../../../../../client").resolve(), - flet_app_main=app.main, - test_path=request.fspath, - ) - await flet_app.start() - yield flet_app - await flet_app.teardown() - - -@pytest.mark.asyncio(loop_scope="module") -async def test_app(flet_app: ftt.FletTestApp): - tester = flet_app.tester - await tester.pump_and_settle() - zero_text = await tester.find_by_text("0") - assert zero_text.count == 1 - - # tap increment button - increment_btn = await tester.find_by_icon(ft.Icons.ADD) - assert increment_btn.count == 1 - await tester.tap(increment_btn) - await tester.pump_and_settle() - assert (await tester.find_by_text("1")).count == 1 - - # tap decrement button - decrement_button = await tester.find_by_key("decrement") - assert decrement_button.count == 1 - await tester.tap(decrement_button) - await tester.tap(decrement_button) - await tester.pump_and_settle() - assert (await tester.find_by_text("-1")).count == 1 diff --git a/sdk/python/examples/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh index 592eb87a5f..34817b020d 100644 --- a/sdk/python/examples/publish-gallery.sh +++ b/sdk/python/examples/publish-gallery.sh @@ -6,7 +6,7 @@ flet publish tutorials/calculator/calc.py --distpath $DIST_PATH/calculator --bas flet publish tutorials/solitaire_declarative/solitaire-final/main.py --distpath $DIST_PATH/solitaire --base-url solitaire --assets assets --app-name "Solitaire" --app-description "Learn how to handle gestures and position controls on a page." flet publish apps/trolli-declarative/src/main.py --distpath $DIST_PATH/trolli --base-url trolli --assets assets --route-url-strategy "hash" --app-name "Trolli" --app-description "A clone of Trello." flet publish apps/routing_navigation/home_store.py --distpath $DIST_PATH/simple_routing --base-url simple_routing --route-url-strategy "hash" --app-name "Flet routing example" --app-description "An example of routing in Flet." -flet publish apps/counter/counter.py --distpath $DIST_PATH/counter --base-url counter --app-name "Counter" --app-description "Counter to get an idea of Flet." +flet publish apps/counter/basic/main.py --distpath $DIST_PATH/counter --base-url counter --app-name "Counter" --app-description "Counter to get an idea of Flet." flet publish apps/flet_animation/main.py --distpath $DIST_PATH/flet_animation --base-url flet_animation --app-name "Flet animation" --app-description "An example of implicit animations in Flet." flet publish apps/greeter/greeter.py --distpath $DIST_PATH/greeter --base-url greeter --app-name "Greeter" --app-description "A basic example of interactive forms in Flet." flet publish apps/hello_world/hello.py --distpath $DIST_PATH/hello_world --base-url hello_world --app-name "Hello, world!" --app-description "A very minimal example of Flet app." From 5b2c3105faabdc5b703b037eaf9077760409b757 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 10:30:35 -0700 Subject: [PATCH 89/96] Normalize app examples metadata --- .../examples/apps/counter_test_ios/Dockerfile | 4 +-- .../examples/apps/counter_test_ios/main.py | 10 ++++--- .../apps/counter_test_ios/pyproject.toml | 26 +++++++++++++++++++ .../apps/counter_test_ios/requirements.txt | 1 - .../main.py} | 15 ++++++++--- .../custom_buttons/pyproject.toml | 26 +++++++++++++++++++ 6 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 sdk/python/examples/apps/counter_test_ios/pyproject.toml delete mode 100644 sdk/python/examples/apps/counter_test_ios/requirements.txt rename sdk/python/examples/apps/custom_controls/{custom_buttons.py => custom_buttons/main.py} (76%) create mode 100644 sdk/python/examples/apps/custom_controls/custom_buttons/pyproject.toml diff --git a/sdk/python/examples/apps/counter_test_ios/Dockerfile b/sdk/python/examples/apps/counter_test_ios/Dockerfile index 2fe01b9780..5bf082ae12 100644 --- a/sdk/python/examples/apps/counter_test_ios/Dockerfile +++ b/sdk/python/examples/apps/counter_test_ios/Dockerfile @@ -2,8 +2,8 @@ FROM python:3-alpine WORKDIR /app -COPY requirements.txt ./ -RUN pip install --no-cache-dir -r requirements.txt +COPY pyproject.toml ./ +RUN pip install --no-cache-dir . COPY . . diff --git a/sdk/python/examples/apps/counter_test_ios/main.py b/sdk/python/examples/apps/counter_test_ios/main.py index c8c4748a43..8dc1980490 100644 --- a/sdk/python/examples/apps/counter_test_ios/main.py +++ b/sdk/python/examples/apps/counter_test_ios/main.py @@ -7,6 +7,7 @@ class State: def main(page: ft.Page): state = State() + counter = ft.Text("0", size=50) def add_click(e): state.counter += 1 @@ -18,13 +19,14 @@ def add_click(e): ) page.add( ft.SafeArea( - ft.Container( - counter := ft.Text("0", size=50), + expand=True, + content=ft.Container( alignment=ft.Alignment.CENTER, + content=counter, ), - expand=True, ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/counter_test_ios/pyproject.toml b/sdk/python/examples/apps/counter_test_ios/pyproject.toml new file mode 100644 index 0000000000..492ce3b348 --- /dev/null +++ b/sdk/python/examples/apps/counter_test_ios/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-counter-test-ios" +version = "1.0.0" +description = "Minimal floating-action-button counter app used for testing Flet on mobile devices." +requires-python = ">=3.10" +keywords = ["apps", "counter", "mobile", "floating action button", "ios"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Basic"] + +[tool.flet.metadata] +title = "Counter test iOS" +controls = ["SafeArea", "Container", "Text", "FloatingActionButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["counter updates", "mobile testing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/counter_test_ios/requirements.txt b/sdk/python/examples/apps/counter_test_ios/requirements.txt deleted file mode 100644 index 3a0e96024e..0000000000 --- a/sdk/python/examples/apps/counter_test_ios/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet>=0.80.0 diff --git a/sdk/python/examples/apps/custom_controls/custom_buttons.py b/sdk/python/examples/apps/custom_controls/custom_buttons/main.py similarity index 76% rename from sdk/python/examples/apps/custom_controls/custom_buttons.py rename to sdk/python/examples/apps/custom_controls/custom_buttons/main.py index d7037edb37..ae42752145 100644 --- a/sdk/python/examples/apps/custom_controls/custom_buttons.py +++ b/sdk/python/examples/apps/custom_controls/custom_buttons/main.py @@ -36,10 +36,17 @@ def init(self): self.icon = ft.Icons.HEADPHONES page.add( - ft.Row([MyButton(content="1")]), - ft.Row([MyButton2(content="2")]), - ft.Row([MyButton3(content="3")]), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row(controls=[MyButton(content="1")]), + ft.Row(controls=[MyButton2(content="2")]), + ft.Row(controls=[MyButton3(content="3")]), + ] + ) + ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/custom_controls/custom_buttons/pyproject.toml b/sdk/python/examples/apps/custom_controls/custom_buttons/pyproject.toml new file mode 100644 index 0000000000..d402f8a39b --- /dev/null +++ b/sdk/python/examples/apps/custom_controls/custom_buttons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-custom-controls-custom-buttons" +version = "1.0.0" +description = "Shows three ways to define reusable custom button controls with predefined styling." +requires-python = ">=3.10" +keywords = ["apps", "custom controls", "buttons", "control decorator", "dataclass"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Custom controls"] + +[tool.flet.metadata] +title = "Custom buttons" +controls = ["SafeArea", "Column", "Row", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom controls", "button styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" From 26562780b4c7612e39fa29e5fb1fd53bafca02d4 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 11:16:38 -0700 Subject: [PATCH 90/96] Migrate declarative app examples --- .../main.py} | 31 ++++-- .../component_dialog/pyproject.toml | 26 +++++ .../{counter.py => counter/main.py} | 13 ++- .../apps/declarative/counter/pyproject.toml | 26 +++++ .../apps/declarative/counter_minimal.py | 16 --- .../apps/declarative/counter_minimal/main.py | 23 ++++ .../counter_minimal/pyproject.toml | 26 +++++ .../declarative/drag_and_drop_containers.py | 89 --------------- .../drag_and_drop_containers/main.py | 96 ++++++++++++++++ .../drag_and_drop_containers/pyproject.toml | 26 +++++ .../main.py} | 33 +++--- .../drag_and_drop_ordering/pyproject.toml | 26 +++++ .../examples/apps/declarative/edit_form.py | 59 ---------- .../apps/declarative/edit_form/main.py | 68 ++++++++++++ .../apps/declarative/edit_form/pyproject.toml | 26 +++++ .../{minesweeper.py => minesweeper/main.py} | 65 ++++++----- .../declarative/minesweeper/pyproject.toml | 26 +++++ .../apps/declarative/minimal_reactive.py | 7 -- .../apps/declarative/minimal_reactive/main.py | 14 +++ .../minimal_reactive/pyproject.toml | 26 +++++ .../{progress_bar.py => progress_bar/main.py} | 19 +++- .../declarative/progress_bar/pyproject.toml | 26 +++++ .../main.py} | 47 +++++--- .../routing_two_pages/pyproject.toml | 26 +++++ .../apps/declarative/set_state_with_list.py | 36 ------ .../declarative/set_state_with_list/main.py | 43 +++++++ .../set_state_with_list/pyproject.toml | 26 +++++ .../{shape_drawer.py => shape_drawer/main.py} | 37 +++--- .../declarative/shape_drawer/pyproject.toml | 26 +++++ .../{sunflower.py => sunflower/main.py} | 11 +- .../apps/declarative/sunflower/pyproject.toml | 26 +++++ .../{tic_tac_toe.py => tic_tac_toe/main.py} | 21 ++-- .../declarative/tic_tac_toe/pyproject.toml | 26 +++++ .../declarative/{todo.py => todo/main.py} | 105 ++++++++++-------- .../apps/declarative/todo/pyproject.toml | 26 +++++ .../declarative/uncontrolled_textfield.py | 41 ------- .../uncontrolled_textfield/main.py | 50 +++++++++ .../uncontrolled_textfield/pyproject.toml | 26 +++++ 38 files changed, 943 insertions(+), 397 deletions(-) rename sdk/python/examples/apps/declarative/{component_dialog.py => component_dialog/main.py} (81%) create mode 100644 sdk/python/examples/apps/declarative/component_dialog/pyproject.toml rename sdk/python/examples/apps/declarative/{counter.py => counter/main.py} (67%) create mode 100644 sdk/python/examples/apps/declarative/counter/pyproject.toml delete mode 100644 sdk/python/examples/apps/declarative/counter_minimal.py create mode 100644 sdk/python/examples/apps/declarative/counter_minimal/main.py create mode 100644 sdk/python/examples/apps/declarative/counter_minimal/pyproject.toml delete mode 100644 sdk/python/examples/apps/declarative/drag_and_drop_containers.py create mode 100644 sdk/python/examples/apps/declarative/drag_and_drop_containers/main.py create mode 100644 sdk/python/examples/apps/declarative/drag_and_drop_containers/pyproject.toml rename sdk/python/examples/apps/declarative/{drag_and_drop_ordering.py => drag_and_drop_ordering/main.py} (94%) create mode 100644 sdk/python/examples/apps/declarative/drag_and_drop_ordering/pyproject.toml delete mode 100644 sdk/python/examples/apps/declarative/edit_form.py create mode 100644 sdk/python/examples/apps/declarative/edit_form/main.py create mode 100644 sdk/python/examples/apps/declarative/edit_form/pyproject.toml rename sdk/python/examples/apps/declarative/{minesweeper.py => minesweeper/main.py} (89%) create mode 100644 sdk/python/examples/apps/declarative/minesweeper/pyproject.toml delete mode 100644 sdk/python/examples/apps/declarative/minimal_reactive.py create mode 100644 sdk/python/examples/apps/declarative/minimal_reactive/main.py create mode 100644 sdk/python/examples/apps/declarative/minimal_reactive/pyproject.toml rename sdk/python/examples/apps/declarative/{progress_bar.py => progress_bar/main.py} (54%) create mode 100644 sdk/python/examples/apps/declarative/progress_bar/pyproject.toml rename sdk/python/examples/apps/declarative/{routing_two_pages.py => routing_two_pages/main.py} (69%) create mode 100644 sdk/python/examples/apps/declarative/routing_two_pages/pyproject.toml delete mode 100644 sdk/python/examples/apps/declarative/set_state_with_list.py create mode 100644 sdk/python/examples/apps/declarative/set_state_with_list/main.py create mode 100644 sdk/python/examples/apps/declarative/set_state_with_list/pyproject.toml rename sdk/python/examples/apps/declarative/{shape_drawer.py => shape_drawer/main.py} (75%) create mode 100644 sdk/python/examples/apps/declarative/shape_drawer/pyproject.toml rename sdk/python/examples/apps/declarative/{sunflower.py => sunflower/main.py} (96%) create mode 100644 sdk/python/examples/apps/declarative/sunflower/pyproject.toml rename sdk/python/examples/apps/declarative/{tic_tac_toe.py => tic_tac_toe/main.py} (87%) create mode 100644 sdk/python/examples/apps/declarative/tic_tac_toe/pyproject.toml rename sdk/python/examples/apps/declarative/{todo.py => todo/main.py} (64%) create mode 100644 sdk/python/examples/apps/declarative/todo/pyproject.toml delete mode 100644 sdk/python/examples/apps/declarative/uncontrolled_textfield.py create mode 100644 sdk/python/examples/apps/declarative/uncontrolled_textfield/main.py create mode 100644 sdk/python/examples/apps/declarative/uncontrolled_textfield/pyproject.toml diff --git a/sdk/python/examples/apps/declarative/component_dialog.py b/sdk/python/examples/apps/declarative/component_dialog/main.py similarity index 81% rename from sdk/python/examples/apps/declarative/component_dialog.py rename to sdk/python/examples/apps/declarative/component_dialog/main.py index 2aa5df9638..8f9c720677 100644 --- a/sdk/python/examples/apps/declarative/component_dialog.py +++ b/sdk/python/examples/apps/declarative/component_dialog/main.py @@ -73,18 +73,25 @@ def App(): ) ) - return ft.Container( - padding=20, - content=ft.Column( - controls=[ - ft.Text("Main App", size=22, weight=ft.FontWeight.BOLD), - ft.ElevatedButton( - "Open User Panel", - on_click=open_user_dialog, - ), - ] - ), + return ft.SafeArea( + content=ft.Container( + padding=20, + content=ft.Column( + controls=[ + ft.Text("Main App", size=22, weight=ft.FontWeight.BOLD), + ft.Button( + "Open User Panel", + on_click=open_user_dialog, + ), + ] + ), + ) ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/component_dialog/pyproject.toml b/sdk/python/examples/apps/declarative/component_dialog/pyproject.toml new file mode 100644 index 0000000000..f2ce37e917 --- /dev/null +++ b/sdk/python/examples/apps/declarative/component_dialog/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-component-dialog" +version = "1.0.0" +description = "Opens a declarative alert dialog that loads user data asynchronously before rendering it." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "dialog", "async", "httpx"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "httpx"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Component dialog" +controls = ["SafeArea", "Container", "Column", "Text", "ElevatedButton", "AlertDialog", "ProgressRing"] +layout_pattern = "center-stage" +complexity = "intermediate" +features = ["dialog management", "async", "data loading"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/counter.py b/sdk/python/examples/apps/declarative/counter/main.py similarity index 67% rename from sdk/python/examples/apps/declarative/counter.py rename to sdk/python/examples/apps/declarative/counter/main.py index 6431490953..ed12ccd2fb 100644 --- a/sdk/python/examples/apps/declarative/counter.py +++ b/sdk/python/examples/apps/declarative/counter/main.py @@ -11,14 +11,19 @@ def App(): ), controls=[ ft.SafeArea( - ft.Container( - ft.Text(value=f"{count}", size=50), + expand=True, + content=ft.Container( alignment=ft.Alignment.CENTER, + content=ft.Text(value=f"{count}", size=50), ), - expand=True, ) ], ) -ft.run(lambda page: page.render_views(App)) +def main(page: ft.Page): + page.render_views(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/counter/pyproject.toml b/sdk/python/examples/apps/declarative/counter/pyproject.toml new file mode 100644 index 0000000000..80f7fee15d --- /dev/null +++ b/sdk/python/examples/apps/declarative/counter/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-counter" +version = "1.0.0" +description = "Declarative counter app that updates a centered value from a floating action button." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "counter", "floating action button", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Declarative counter" +controls = ["View", "SafeArea", "Container", "Text", "FloatingActionButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/counter_minimal.py b/sdk/python/examples/apps/declarative/counter_minimal.py deleted file mode 100644 index 59129d8124..0000000000 --- a/sdk/python/examples/apps/declarative/counter_minimal.py +++ /dev/null @@ -1,16 +0,0 @@ -import flet as ft - - -@ft.component -def App(): - count, set_count = ft.use_state(0) - - return ft.Row( - controls=[ - ft.Text(value=f"{count}"), - ft.Button("Add", on_click=lambda: set_count(count + 1)), - ], - ) - - -ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/counter_minimal/main.py b/sdk/python/examples/apps/declarative/counter_minimal/main.py new file mode 100644 index 0000000000..453f218e81 --- /dev/null +++ b/sdk/python/examples/apps/declarative/counter_minimal/main.py @@ -0,0 +1,23 @@ +import flet as ft + + +@ft.component +def App(): + count, set_count = ft.use_state(0) + + return ft.SafeArea( + content=ft.Row( + controls=[ + ft.Text(value=f"{count}"), + ft.Button("Add", on_click=lambda: set_count(count + 1)), + ], + ) + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/counter_minimal/pyproject.toml b/sdk/python/examples/apps/declarative/counter_minimal/pyproject.toml new file mode 100644 index 0000000000..a5174dbe89 --- /dev/null +++ b/sdk/python/examples/apps/declarative/counter_minimal/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-counter-minimal" +version = "1.0.0" +description = "Small declarative counter showing the minimum state hook pattern for updating text." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "counter", "minimal", "state hooks"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Counter minimal" +controls = ["SafeArea", "Row", "Text", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_containers.py b/sdk/python/examples/apps/declarative/drag_and_drop_containers.py deleted file mode 100644 index 4861fab64b..0000000000 --- a/sdk/python/examples/apps/declarative/drag_and_drop_containers.py +++ /dev/null @@ -1,89 +0,0 @@ -from dataclasses import dataclass - -import flet as ft - - -@dataclass -@ft.observable -class TargetState: - bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 - is_drag_over: bool = False - - -@ft.component -def App(): - target, _ = ft.use_state(lambda: TargetState()) - - def on_will_accept(e: ft.DragWillAcceptEvent): - target.is_drag_over = True - - def on_accept(e: ft.DragTargetEvent): - target.bgcolor = e.src.data - target.is_drag_over = False - - def on_leave(e: ft.DragTargetLeaveEvent): - target.is_drag_over = False - - return ft.Row( - controls=[ - ft.Column( - controls=[ - ft.Draggable( - group="color", - data=ft.Colors.CYAN, - content=ft.Container( - width=50, - height=50, - bgcolor=ft.Colors.CYAN, - border_radius=5, - ), - content_feedback=ft.Container( - width=20, - height=20, - bgcolor=ft.Colors.CYAN, - border_radius=3, - ), - ), - ft.Draggable( - group="color", - data=ft.Colors.YELLOW, - content=ft.Container( - width=50, - height=50, - bgcolor=ft.Colors.YELLOW, - border_radius=5, - ), - ), - ft.Draggable( - group="color", - data=ft.Colors.GREEN, - content=ft.Container( - width=50, - height=50, - bgcolor=ft.Colors.GREEN, - border_radius=5, - ), - ), - ] - ), - ft.Container(width=100), - ft.DragTarget( - group="color", - on_will_accept=on_will_accept, - on_accept=on_accept, - on_leave=on_leave, - content=ft.Container( - width=50, - height=50, - bgcolor=target.bgcolor, - border=ft.Border.all(2, ft.Colors.BLACK45) - if target.is_drag_over - else None, - border_radius=5, - ), - ), - ] - ) - - -ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_containers/main.py b/sdk/python/examples/apps/declarative/drag_and_drop_containers/main.py new file mode 100644 index 0000000000..773b307d42 --- /dev/null +++ b/sdk/python/examples/apps/declarative/drag_and_drop_containers/main.py @@ -0,0 +1,96 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +@ft.observable +class TargetState: + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + is_drag_over: bool = False + + +@ft.component +def App(): + target, _ = ft.use_state(lambda: TargetState()) + + def on_will_accept(e: ft.DragWillAcceptEvent): + target.is_drag_over = True + + def on_accept(e: ft.DragTargetEvent): + target.bgcolor = e.src.data + target.is_drag_over = False + + def on_leave(e: ft.DragTargetLeaveEvent): + target.is_drag_over = False + + return ft.SafeArea( + content=ft.Row( + controls=[ + ft.Column( + controls=[ + ft.Draggable( + group="color", + data=ft.Colors.CYAN, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN, + border_radius=5, + ), + content_feedback=ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.CYAN, + border_radius=3, + ), + ), + ft.Draggable( + group="color", + data=ft.Colors.YELLOW, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.YELLOW, + border_radius=5, + ), + ), + ft.Draggable( + group="color", + data=ft.Colors.GREEN, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.GREEN, + border_radius=5, + ), + ), + ] + ), + ft.Container(width=100), + ft.DragTarget( + group="color", + on_will_accept=on_will_accept, + on_accept=on_accept, + on_leave=on_leave, + content=ft.Container( + width=50, + height=50, + bgcolor=target.bgcolor, + border=ft.Border.all(2, ft.Colors.BLACK_45) + if target.is_drag_over + else None, + border_radius=5, + ), + ), + ] + ) + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_containers/pyproject.toml b/sdk/python/examples/apps/declarative/drag_and_drop_containers/pyproject.toml new file mode 100644 index 0000000000..fc218d0acf --- /dev/null +++ b/sdk/python/examples/apps/declarative/drag_and_drop_containers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-drag-and-drop-containers" +version = "1.0.0" +description = "Drag colored squares onto a target container to update its background color declaratively." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "drag and drop", "containers", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Drag and drop containers" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "Container"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["drag and drop", "live state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_ordering.py b/sdk/python/examples/apps/declarative/drag_and_drop_ordering/main.py similarity index 94% rename from sdk/python/examples/apps/declarative/drag_and_drop_ordering.py rename to sdk/python/examples/apps/declarative/drag_and_drop_ordering/main.py index cb37788abb..65a6241639 100644 --- a/sdk/python/examples/apps/declarative/drag_and_drop_ordering.py +++ b/sdk/python/examples/apps/declarative/drag_and_drop_ordering/main.py @@ -73,7 +73,7 @@ def on_accept(e: ft.DragTargetEvent): horizontal_alignment=ft.CrossAxisAlignment.CENTER, controls=[ ft.Divider( - color=ft.Colors.BLACK38, + color=ft.Colors.BLACK_38, thickness=2, height=2, radius=2, @@ -133,7 +133,7 @@ def on_add_item(self): intrinsic_height=True, controls=[ ft.VerticalDivider( - color=ft.Colors.BLACK54, + color=ft.Colors.BLACK_54, width=2, thickness=2, radius=2, @@ -159,9 +159,9 @@ def on_add_item(self): on_accept=on_group_accept, on_leave=lambda: set_is_group_over(False), content=ft.Container( - border=ft.Border.all(2, ft.Colors.BLACK12) + border=ft.Border.all(2, ft.Colors.BLACK_12) if not is_group_over - else ft.Border.all(2, ft.Colors.BLACK38), + else ft.Border.all(2, ft.Colors.BLACK_38), border_radius=ft.BorderRadius.all(15), bgcolor=group.color, padding=ft.Padding.all(20), @@ -196,7 +196,7 @@ def on_add_item(self): for item in group.items ], ft.Divider( - color=ft.Colors.BLACK38, + color=ft.Colors.BLACK_38, thickness=2, height=2, radius=2, @@ -245,14 +245,21 @@ def on_mounted(): ft.on_mounted(on_mounted) - return ft.Row( - spacing=4, - vertical_alignment=ft.CrossAxisAlignment.START, - controls=[ - GroupView(group, move_group=app.move_group, key=group.title) - for group in app.groups - ], + return ft.SafeArea( + content=ft.Row( + spacing=4, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + GroupView(group, move_group=app.move_group, key=group.title) + for group in app.groups + ], + ) ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_ordering/pyproject.toml b/sdk/python/examples/apps/declarative/drag_and_drop_ordering/pyproject.toml new file mode 100644 index 0000000000..017dc3b594 --- /dev/null +++ b/sdk/python/examples/apps/declarative/drag_and_drop_ordering/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-drag-and-drop-ordering" +version = "1.0.0" +description = "Reorders groups and items declaratively with nested drag-and-drop targets." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "drag and drop", "reordering", "kanban"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Drag and drop ordering" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "TextField", "TextButton"] +layout_pattern = "dashboard" +complexity = "intermediate" +features = ["drag and drop", "reordering", "nested state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/edit_form.py b/sdk/python/examples/apps/declarative/edit_form.py deleted file mode 100644 index 2ce0b07518..0000000000 --- a/sdk/python/examples/apps/declarative/edit_form.py +++ /dev/null @@ -1,59 +0,0 @@ -from dataclasses import dataclass -from typing import cast - -import flet as ft - - -@dataclass -@ft.observable -class Form: - first_name: str = "" - last_name: str = "" - - def set_first_name(self, value): - self.first_name = value - - def set_last_name(self, value): - self.last_name = value - - async def submit(self, e: ft.Event[ft.Button]): - e.page.show_dialog( - ft.AlertDialog( - title="Hello", - content=ft.Text(f"{self.first_name} {self.last_name}!"), - ) - ) - - async def reset(self): - self.first_name = "" - self.last_name = "" - - -@ft.component -def App(): - form, _ = ft.use_state(Form()) - - return [ - ft.TextField( - label="First name", - value=form.first_name, - on_change=lambda e: form.set_first_name(e.control.value), - ), - ft.TextField( - label="Last name", - value=form.last_name, - on_change=lambda e: form.set_last_name(e.control.value), - ), - ft.Row( - cast( - list[ft.Control], - [ - ft.FilledButton("Submit", on_click=form.submit), - ft.FilledTonalButton("Reset", on_click=form.reset), - ], - ) - ), - ] - - -ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/edit_form/main.py b/sdk/python/examples/apps/declarative/edit_form/main.py new file mode 100644 index 0000000000..5e4ed8663d --- /dev/null +++ b/sdk/python/examples/apps/declarative/edit_form/main.py @@ -0,0 +1,68 @@ +from dataclasses import dataclass +from typing import cast + +import flet as ft + + +@dataclass +@ft.observable +class Form: + first_name: str = "" + last_name: str = "" + + def set_first_name(self, value): + self.first_name = value + + def set_last_name(self, value): + self.last_name = value + + async def submit(self, e: ft.Event[ft.Button]): + e.page.show_dialog( + ft.AlertDialog( + title="Hello", + content=ft.Text(f"{self.first_name} {self.last_name}!"), + ) + ) + + async def reset(self): + self.first_name = "" + self.last_name = "" + + +@ft.component +def App(): + form, _ = ft.use_state(Form()) + + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + label="First name", + value=form.first_name, + on_change=lambda e: form.set_first_name(e.control.value), + ), + ft.TextField( + label="Last name", + value=form.last_name, + on_change=lambda e: form.set_last_name(e.control.value), + ), + ft.Row( + cast( + list[ft.Control], + [ + ft.FilledButton("Submit", on_click=form.submit), + ft.FilledTonalButton("Reset", on_click=form.reset), + ], + ) + ), + ] + ) + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/edit_form/pyproject.toml b/sdk/python/examples/apps/declarative/edit_form/pyproject.toml new file mode 100644 index 0000000000..5b78f63975 --- /dev/null +++ b/sdk/python/examples/apps/declarative/edit_form/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-edit-form" +version = "1.0.0" +description = "Edits a small form declaratively and submits or resets the fields through observable state." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "form", "text fields", "observable state", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Edit form" +controls = ["SafeArea", "Column", "Row", "TextField", "FilledButton", "FilledTonalButton", "AlertDialog"] +layout_pattern = "form" +complexity = "basic" +features = ["form editing", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/minesweeper.py b/sdk/python/examples/apps/declarative/minesweeper/main.py similarity index 89% rename from sdk/python/examples/apps/declarative/minesweeper.py rename to sdk/python/examples/apps/declarative/minesweeper/main.py index 2954fbdd2e..b34102162b 100644 --- a/sdk/python/examples/apps/declarative/minesweeper.py +++ b/sdk/python/examples/apps/declarative/minesweeper/main.py @@ -10,8 +10,8 @@ # ----------- Visual constants ---------- SQUARE_SIZE = 30 -LIGHT = ft.Colors.WHITE70 -DARK = ft.Colors.BLACK38 +LIGHT = ft.Colors.WHITE_70 +DARK = ft.Colors.BLACK_38 BEVEL_RAISED = ft.Border( bottom=ft.BorderSide(4, DARK), @@ -314,34 +314,39 @@ def on_right_pan_start(e): expand=True, ) - return ft.Container( - content=ft.Column( - controls=[ - ft.Container( - content=top_menu, - foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), - padding=10, - ), - ft.Container( - content=board, - # alignment=ft.Alignment.TOP_CENTER, - # content=ft.Text("sdfsdfsfd"), - foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), - padding=5, - height=SQUARE_SIZE * game.rows + 10, - width=SQUARE_SIZE * game.cols + 10, - ), - ], - alignment=ft.MainAxisAlignment.START, - horizontal_alignment=ft.CrossAxisAlignment.START, - spacing=10, - ), - bgcolor=ft.Colors.GREY_400, - foreground_decoration=ft.BoxDecoration(border=BEVEL_RAISED), - width=SQUARE_SIZE * (game.cols + 1), - height=SQUARE_SIZE * (game.rows + 1) + 100, - padding=10, + return ft.SafeArea( + content=ft.Container( + content=ft.Column( + controls=[ + ft.Container( + content=top_menu, + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + padding=10, + ), + ft.Container( + content=board, + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + padding=5, + height=SQUARE_SIZE * game.rows + 10, + width=SQUARE_SIZE * game.cols + 10, + ), + ], + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.START, + spacing=10, + ), + bgcolor=ft.Colors.GREY_400, + foreground_decoration=ft.BoxDecoration(border=BEVEL_RAISED), + width=SQUARE_SIZE * (game.cols + 1), + height=SQUARE_SIZE * (game.rows + 1) + 100, + padding=10, + ) ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/minesweeper/pyproject.toml b/sdk/python/examples/apps/declarative/minesweeper/pyproject.toml new file mode 100644 index 0000000000..2ed8861e09 --- /dev/null +++ b/sdk/python/examples/apps/declarative/minesweeper/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-minesweeper" +version = "1.0.0" +description = "Implements a declarative Minesweeper board with timer, flagging, and win-loss state." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "minesweeper", "game", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Games", "Apps/Declarative"] + +[tool.flet.metadata] +title = "Minesweeper" +controls = ["SafeArea", "Container", "Column", "Row", "GestureDetector", "Stack", "Text"] +layout_pattern = "center-stage" +complexity = "advanced" +features = ["game state", "async", "timer", "gesture input"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/minimal_reactive.py b/sdk/python/examples/apps/declarative/minimal_reactive.py deleted file mode 100644 index bf735bee4e..0000000000 --- a/sdk/python/examples/apps/declarative/minimal_reactive.py +++ /dev/null @@ -1,7 +0,0 @@ -import flet - -flet.run( - lambda page: page.render( - lambda: flet.Text("Hello, world!"), - ), -) diff --git a/sdk/python/examples/apps/declarative/minimal_reactive/main.py b/sdk/python/examples/apps/declarative/minimal_reactive/main.py new file mode 100644 index 0000000000..e5ab5b87c6 --- /dev/null +++ b/sdk/python/examples/apps/declarative/minimal_reactive/main.py @@ -0,0 +1,14 @@ +import flet as ft + + +@ft.component +def App(): + return ft.SafeArea(content=ft.Text("Hello, world!")) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/minimal_reactive/pyproject.toml b/sdk/python/examples/apps/declarative/minimal_reactive/pyproject.toml new file mode 100644 index 0000000000..d0a1ce8fdc --- /dev/null +++ b/sdk/python/examples/apps/declarative/minimal_reactive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-minimal-reactive" +version = "1.0.0" +description = "Renders a minimal declarative component to show the smallest reactive app structure." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "minimal", "reactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Minimal reactive" +controls = ["SafeArea", "Text"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["reactive rendering"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/progress_bar.py b/sdk/python/examples/apps/declarative/progress_bar/main.py similarity index 54% rename from sdk/python/examples/apps/declarative/progress_bar.py rename to sdk/python/examples/apps/declarative/progress_bar/main.py index 5f2ea833a2..7c4f6feda4 100644 --- a/sdk/python/examples/apps/declarative/progress_bar.py +++ b/sdk/python/examples/apps/declarative/progress_bar/main.py @@ -20,10 +20,19 @@ async def start_counter(self): def App(): state, _ = ft.use_state(AppState(counter=0)) - return [ - ft.ProgressBar(state.counter), - ft.Button("Run!", on_click=state.start_counter), - ] + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.ProgressBar(state.counter), + ft.Button("Run!", on_click=state.start_counter), + ] + ) + ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/progress_bar/pyproject.toml b/sdk/python/examples/apps/declarative/progress_bar/pyproject.toml new file mode 100644 index 0000000000..e5051ed77e --- /dev/null +++ b/sdk/python/examples/apps/declarative/progress_bar/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-progress-bar" +version = "1.0.0" +description = "Runs an async counter that fills a progress bar over time in a declarative app." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "progress bar", "async", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Progress bar" +controls = ["SafeArea", "Column", "ProgressBar", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["async", "progress updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/routing_two_pages.py b/sdk/python/examples/apps/declarative/routing_two_pages/main.py similarity index 69% rename from sdk/python/examples/apps/declarative/routing_two_pages.py rename to sdk/python/examples/apps/declarative/routing_two_pages/main.py index a109a16bb3..da2701bca3 100644 --- a/sdk/python/examples/apps/declarative/routing_two_pages.py +++ b/sdk/python/examples/apps/declarative/routing_two_pages/main.py @@ -96,16 +96,22 @@ def update_theme_mode(): route="/", appbar=AppBar(), controls=[ - ft.Button( - "Visit Store", - on_click=lambda _: asyncio.create_task( - ft.context.page.push_route("/store") - ), - ), - ft.Button( - "Do something", - on_click=lambda _: asyncio.create_task( - ft.context.page.push_route("/do-something") + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Visit Store", + on_click=lambda _: asyncio.create_task( + ft.context.page.push_route("/store") + ), + ), + ft.Button( + "Do something", + on_click=lambda _: asyncio.create_task( + ft.context.page.push_route("/do-something") + ), + ), + ] ), ), ], @@ -116,10 +122,16 @@ def update_theme_mode(): route="/store", appbar=AppBar(), controls=[ - ft.Button( - "Go Home", - on_click=lambda _: asyncio.create_task( - ft.context.page.push_route("/") + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Go Home", + on_click=lambda _: asyncio.create_task( + ft.context.page.push_route("/") + ), + ), + ] ), ), ], @@ -132,4 +144,9 @@ def update_theme_mode(): ) -ft.run(lambda page: page.render_views(RoutingExample)) +def main(page: ft.Page): + page.render_views(RoutingExample) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/routing_two_pages/pyproject.toml b/sdk/python/examples/apps/declarative/routing_two_pages/pyproject.toml new file mode 100644 index 0000000000..f8e72bb542 --- /dev/null +++ b/sdk/python/examples/apps/declarative/routing_two_pages/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-routing-two-pages" +version = "1.0.0" +description = "Demonstrates declarative view routing with theme context shared across two pages." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "routing", "views", "context", "theme"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative", "Apps/Navigation"] + +[tool.flet.metadata] +title = "Routing two pages" +controls = ["View", "SafeArea", "Column", "Button", "AppBar", "Switch"] +layout_pattern = "list-detail" +complexity = "intermediate" +features = ["routing", "context", "theme switching"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/set_state_with_list.py b/sdk/python/examples/apps/declarative/set_state_with_list.py deleted file mode 100644 index 9e10fdc132..0000000000 --- a/sdk/python/examples/apps/declarative/set_state_with_list.py +++ /dev/null @@ -1,36 +0,0 @@ -import asyncio - -import flet as ft - - -@ft.component -def App(): - items, set_items = ft.use_state(list(range(60))) - - async def auto_scroll(e): - for i in range(60, 120): - await asyncio.sleep(1) - set_items(lambda cur, i=i: cur + [i]) - print(f"Scrolling to line {i}") - - return ft.Column( - controls=[ - ft.ListView( - spacing=10, - padding=20, - auto_scroll=True, - height=300, - controls=[ - ft.Text( - key=i, - value=f"Line {i + 1}", - ) - for i in items - ], - ), - ft.OutlinedButton("Start auto-scrolling", on_click=auto_scroll), - ] - ) - - -ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/set_state_with_list/main.py b/sdk/python/examples/apps/declarative/set_state_with_list/main.py new file mode 100644 index 0000000000..46fbf4863b --- /dev/null +++ b/sdk/python/examples/apps/declarative/set_state_with_list/main.py @@ -0,0 +1,43 @@ +import asyncio + +import flet as ft + + +@ft.component +def App(): + items, set_items = ft.use_state(list(range(60))) + + async def auto_scroll(e): + for i in range(60, 120): + await asyncio.sleep(1) + set_items(lambda cur, i=i: cur + [i]) + print(f"Scrolling to line {i}") + + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.ListView( + spacing=10, + padding=20, + auto_scroll=True, + height=300, + controls=[ + ft.Text( + key=i, + value=f"Line {i + 1}", + ) + for i in items + ], + ), + ft.OutlinedButton("Start auto-scrolling", on_click=auto_scroll), + ] + ) + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/set_state_with_list/pyproject.toml b/sdk/python/examples/apps/declarative/set_state_with_list/pyproject.toml new file mode 100644 index 0000000000..61251f50c9 --- /dev/null +++ b/sdk/python/examples/apps/declarative/set_state_with_list/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-set-state-with-list" +version = "1.0.0" +description = "Appends rows to a scrolling list over time to demonstrate list state updates." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "list view", "auto scroll", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Set state with list" +controls = ["SafeArea", "Column", "ListView", "Text", "OutlinedButton"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["async", "auto scroll", "list state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/shape_drawer.py b/sdk/python/examples/apps/declarative/shape_drawer/main.py similarity index 75% rename from sdk/python/examples/apps/declarative/shape_drawer.py rename to sdk/python/examples/apps/declarative/shape_drawer/main.py index 8ec8dcdfdb..47db6728bf 100644 --- a/sdk/python/examples/apps/declarative/shape_drawer.py +++ b/sdk/python/examples/apps/declarative/shape_drawer/main.py @@ -83,22 +83,29 @@ def handle_secondary_tap_down(e: ft.TapEvent): # add new polygon state.polygons.append(Polygon()) - return ft.GestureDetector( - on_tap_down=handle_tap_down, - on_secondary_tap_down=handle_secondary_tap_down, - on_hover=handle_hover, - content=ft.Container( - content=canvas.Canvas( - width=float("inf"), - height=float("inf"), - shapes=[PolygonView(polygon) for polygon in state.polygons], + return ft.SafeArea( + content=ft.GestureDetector( + on_tap_down=handle_tap_down, + on_secondary_tap_down=handle_secondary_tap_down, + on_hover=handle_hover, + content=ft.Container( + content=canvas.Canvas( + width=float("inf"), + height=float("inf"), + shapes=[PolygonView(polygon) for polygon in state.polygons], + ), + width=500, + height=500, + bgcolor=ft.Colors.GREY_300, + alignment=ft.Alignment.TOP_LEFT, ), - width=500, - height=500, - bgcolor=ft.Colors.GREY_300, - alignment=ft.Alignment.TOP_LEFT, - ), + ) ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/shape_drawer/pyproject.toml b/sdk/python/examples/apps/declarative/shape_drawer/pyproject.toml new file mode 100644 index 0000000000..0769d7090e --- /dev/null +++ b/sdk/python/examples/apps/declarative/shape_drawer/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-shape-drawer" +version = "1.0.0" +description = "Draws polygons on a canvas declaratively in response to tap and hover gestures." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "canvas", "drawing", "gestures"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative", "Apps/Canvas"] + +[tool.flet.metadata] +title = "Shape drawer" +controls = ["SafeArea", "GestureDetector", "Container", "Canvas"] +layout_pattern = "center-stage" +complexity = "intermediate" +features = ["canvas drawing", "gesture input"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/sunflower.py b/sdk/python/examples/apps/declarative/sunflower/main.py similarity index 96% rename from sdk/python/examples/apps/declarative/sunflower.py rename to sdk/python/examples/apps/declarative/sunflower/main.py index f90183e0b0..7d52027e06 100644 --- a/sdk/python/examples/apps/declarative/sunflower.py +++ b/sdk/python/examples/apps/declarative/sunflower/main.py @@ -79,7 +79,8 @@ def Sunflower(): appbar=ft.AppBar(title=ft.Text("Sunflower")), controls=[ ft.SafeArea( - ft.Column( + expand=True, + content=ft.Column( horizontal_alignment=ft.CrossAxisAlignment.CENTER, expand=True, controls=[ @@ -118,10 +119,14 @@ def Sunflower(): ), ], ), - expand=True, ) ], ) -ft.run(lambda page: page.render_views(Sunflower)) +def main(page: ft.Page): + page.render_views(Sunflower) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/sunflower/pyproject.toml b/sdk/python/examples/apps/declarative/sunflower/pyproject.toml new file mode 100644 index 0000000000..d15f6c0d77 --- /dev/null +++ b/sdk/python/examples/apps/declarative/sunflower/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-sunflower" +version = "1.0.0" +description = "Animates a sunflower seed pattern with a slider that recomputes declarative layout." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "animation", "slider", "visualization"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative", "Apps/Visualization"] + +[tool.flet.metadata] +title = "Sunflower" +controls = ["View", "SafeArea", "Column", "Stack", "Slider", "Text", "AppBar"] +layout_pattern = "center-stage" +complexity = "intermediate" +features = ["animation", "data visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/tic_tac_toe.py b/sdk/python/examples/apps/declarative/tic_tac_toe/main.py similarity index 87% rename from sdk/python/examples/apps/declarative/tic_tac_toe.py rename to sdk/python/examples/apps/declarative/tic_tac_toe/main.py index 507ced114c..0e5e8a6648 100644 --- a/sdk/python/examples/apps/declarative/tic_tac_toe.py +++ b/sdk/python/examples/apps/declarative/tic_tac_toe/main.py @@ -75,12 +75,14 @@ def jump_to(move: int): for move, _ in enumerate(history) ] - return ft.Row( - [ - Board(x_is_next, history[current_move], handle_play), - ft.Column(moves), - ], - vertical_alignment=ft.CrossAxisAlignment.START, + return ft.SafeArea( + content=ft.Row( + [ + Board(x_is_next, history[current_move], handle_play), + ft.Column(moves), + ], + vertical_alignment=ft.CrossAxisAlignment.START, + ) ) @@ -102,4 +104,9 @@ def calculate_winner(squares: list[str]): return None -ft.run(lambda page: page.render(Game)) +def main(page: ft.Page): + page.render(Game) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/tic_tac_toe/pyproject.toml b/sdk/python/examples/apps/declarative/tic_tac_toe/pyproject.toml new file mode 100644 index 0000000000..8febc29c38 --- /dev/null +++ b/sdk/python/examples/apps/declarative/tic_tac_toe/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-tic-tac-toe" +version = "1.0.0" +description = "Plays tic-tac-toe declaratively with move history and winner detection." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "game", "tic tac toe", "history"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Games", "Apps/Declarative"] + +[tool.flet.metadata] +title = "Tic tac toe" +controls = ["SafeArea", "Row", "Column", "Button", "Icon", "Text", "TextButton"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["game state", "move history"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/todo.py b/sdk/python/examples/apps/declarative/todo/main.py similarity index 64% rename from sdk/python/examples/apps/declarative/todo.py rename to sdk/python/examples/apps/declarative/todo/main.py index 9dc8bebb99..c24ca7b659 100644 --- a/sdk/python/examples/apps/declarative/todo.py +++ b/sdk/python/examples/apps/declarative/todo/main.py @@ -81,51 +81,61 @@ async def add_task(): return ft.View( scroll=ft.ScrollMode.AUTO, controls=[ - ft.Column( - [ - Header(), - ft.Row( - controls=[ - ft.TextField( - ref=new_task_field, - hint_text="What needs to be done?", - on_submit=add_task, - value=new_task_name, - on_change=lambda e: set_new_task_name(e.control.value), - autofocus=True, - expand=True, - ), - ft.FloatingActionButton( - icon=ft.Icons.ADD, - on_click=add_task, - ), - ], - ), - ft.Column( - spacing=25, - controls=[ - ft.Tabs( - selected_index=state.statuses.index(state.status), - length=len(state.statuses), - on_change=state.status_changed, - content=ft.TabBar( - scrollable=False, - tabs=[ft.Tab(label=tab) for tab in state.statuses], + ft.SafeArea( + content=ft.Column( + [ + Header(), + ft.Row( + controls=[ + ft.TextField( + ref=new_task_field, + hint_text="What needs to be done?", + on_submit=add_task, + value=new_task_name, + on_change=lambda e: set_new_task_name( + e.control.value + ), + autofocus=True, + expand=True, ), - ), - ft.Column( - [ - TaskItemView(task, state.delete_task, key=task.id) - for task in state.get_tasks() - ] - ), - Footer( - active_tasks_number=state.active_tasks_number, - clear_completed=state.clear_completed, - ), - ], - ), - ] + ft.FloatingActionButton( + icon=ft.Icons.ADD, + on_click=add_task, + ), + ], + ), + ft.Column( + spacing=25, + controls=[ + ft.Tabs( + selected_index=state.statuses.index(state.status), + length=len(state.statuses), + on_change=state.status_changed, + content=ft.TabBar( + scrollable=False, + tabs=[ + ft.Tab(label=tab) for tab in state.statuses + ], + ), + ), + ft.Column( + [ + TaskItemView( + task, + state.delete_task, + key=task.id, + ) + for task in state.get_tasks() + ] + ), + Footer( + active_tasks_number=state.active_tasks_number, + clear_completed=state.clear_completed, + ), + ], + ), + ] + ) ) ], ) @@ -220,4 +230,9 @@ def Footer(active_tasks_number: int, clear_completed): ) -ft.run(lambda page: page.render_views(TodoAppView)) +def main(page: ft.Page): + page.render_views(TodoAppView) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/todo/pyproject.toml b/sdk/python/examples/apps/declarative/todo/pyproject.toml new file mode 100644 index 0000000000..eb860555f6 --- /dev/null +++ b/sdk/python/examples/apps/declarative/todo/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-todo" +version = "1.0.0" +description = "Tracks, filters, edits, and clears tasks in a declarative to-do application." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "todo", "tabs", "forms"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative", "Apps/Productivity"] + +[tool.flet.metadata] +title = "To-do" +controls = ["View", "SafeArea", "Column", "Row", "TextField", "Tabs", "Checkbox", "IconButton", "FloatingActionButton"] +layout_pattern = "form" +complexity = "intermediate" +features = ["task filtering", "editing", "list state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/uncontrolled_textfield.py b/sdk/python/examples/apps/declarative/uncontrolled_textfield.py deleted file mode 100644 index 329750e491..0000000000 --- a/sdk/python/examples/apps/declarative/uncontrolled_textfield.py +++ /dev/null @@ -1,41 +0,0 @@ -import random -from typing import cast - -import flet as ft - - -@ft.component -def App(): - state, set_state = ft.use_state("") - - async def submit(e: ft.Event[ft.Button]): - e.page.show_dialog( - ft.AlertDialog( - title="Hello", - content=ft.Text(f"{first_name.value} {last_name.value}!"), - ) - ) - - def reset(): - set_state("reset" + str(random.randint(1, 1000))) - - return [ - first_name := ft.TextField( - label="First name", - ), - last_name := ft.TextField( - label="Last name", - ), - ft.Row( - cast( - list[ft.Control], - [ - ft.FilledButton("Submit", on_click=submit), - ft.FilledTonalButton("Reset", on_click=reset), - ], - ) - ), - ] - - -ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/uncontrolled_textfield/main.py b/sdk/python/examples/apps/declarative/uncontrolled_textfield/main.py new file mode 100644 index 0000000000..41df167b20 --- /dev/null +++ b/sdk/python/examples/apps/declarative/uncontrolled_textfield/main.py @@ -0,0 +1,50 @@ +import random +from typing import cast + +import flet as ft + + +@ft.component +def App(): + state, set_state = ft.use_state("") + + async def submit(e: ft.Event[ft.Button]): + e.page.show_dialog( + ft.AlertDialog( + title="Hello", + content=ft.Text(f"{first_name.value} {last_name.value}!"), + ) + ) + + def reset(): + set_state("reset" + str(random.randint(1, 1000))) + + return ft.SafeArea( + content=ft.Column( + controls=[ + first_name := ft.TextField( + label="First name", + ), + last_name := ft.TextField( + label="Last name", + ), + ft.Row( + cast( + list[ft.Control], + [ + ft.FilledButton("Submit", on_click=submit), + ft.FilledTonalButton("Reset", on_click=reset), + ], + ) + ), + ] + ) + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/uncontrolled_textfield/pyproject.toml b/sdk/python/examples/apps/declarative/uncontrolled_textfield/pyproject.toml new file mode 100644 index 0000000000..55f7fd3bbf --- /dev/null +++ b/sdk/python/examples/apps/declarative/uncontrolled_textfield/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-uncontrolled-textfield" +version = "1.0.0" +description = "Shows how uncontrolled text fields behave in a declarative form with submit and reset actions." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "textfield", "form", "uncontrolled"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative"] + +[tool.flet.metadata] +title = "Uncontrolled textfield" +controls = ["SafeArea", "Column", "Row", "TextField", "FilledButton", "FilledTonalButton", "AlertDialog"] +layout_pattern = "form" +complexity = "basic" +features = ["form submission", "uncontrolled inputs"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" From 1da0819aa31983e7c3d833238710247c248e1044 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 15:40:42 -0700 Subject: [PATCH 91/96] Normalize app example projects --- .../examples/apps/flet_animation/main.py | 12 ++++- .../apps/flet_animation/pyproject.toml | 26 +++++++++++ .../apps/flet_animation/requirements.txt | 1 - .../examples/apps/greeter/basic/main.py | 30 +++++++++++++ .../apps/greeter/basic/pyproject.toml | 26 +++++++++++ sdk/python/examples/apps/greeter/greeter.py | 19 -------- .../examples/apps/greeter/requirements.txt | 1 - .../examples/apps/hello_world/basic/main.py | 9 ++++ .../apps/hello_world/basic/pyproject.toml | 26 +++++++++++ sdk/python/examples/apps/hello_world/hello.py | 8 ---- .../apps/hello_world/requirements.txt | 1 - .../examples/apps/icons_browser/Dockerfile | 12 ----- .../examples/apps/icons_browser/README.md | 13 ------ .../examples/apps/icons_browser/fly.toml | 40 ----------------- .../examples/apps/icons_browser/main.py | 44 ++++++++++--------- .../apps/icons_browser/pyproject.toml | 26 +++++++++++ .../apps/icons_browser/requirements.txt | 1 - sdk/python/examples/publish-gallery.sh | 4 +- 18 files changed, 179 insertions(+), 120 deletions(-) create mode 100644 sdk/python/examples/apps/flet_animation/pyproject.toml delete mode 100644 sdk/python/examples/apps/flet_animation/requirements.txt create mode 100644 sdk/python/examples/apps/greeter/basic/main.py create mode 100644 sdk/python/examples/apps/greeter/basic/pyproject.toml delete mode 100644 sdk/python/examples/apps/greeter/greeter.py delete mode 100644 sdk/python/examples/apps/greeter/requirements.txt create mode 100644 sdk/python/examples/apps/hello_world/basic/main.py create mode 100644 sdk/python/examples/apps/hello_world/basic/pyproject.toml delete mode 100644 sdk/python/examples/apps/hello_world/hello.py delete mode 100644 sdk/python/examples/apps/hello_world/requirements.txt delete mode 100644 sdk/python/examples/apps/icons_browser/Dockerfile delete mode 100644 sdk/python/examples/apps/icons_browser/README.md delete mode 100644 sdk/python/examples/apps/icons_browser/fly.toml create mode 100644 sdk/python/examples/apps/icons_browser/pyproject.toml delete mode 100644 sdk/python/examples/apps/icons_browser/requirements.txt diff --git a/sdk/python/examples/apps/flet_animation/main.py b/sdk/python/examples/apps/flet_animation/main.py index 7a1c80301a..e8a756732a 100644 --- a/sdk/python/examples/apps/flet_animation/main.py +++ b/sdk/python/examples/apps/flet_animation/main.py @@ -134,7 +134,15 @@ def assemble(e): page.horizontal_alignment = ft.CrossAxisAlignment.CENTER page.vertical_alignment = ft.MainAxisAlignment.CENTER page.spacing = 30 - page.add(canvas, go_button, again_button) + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[canvas, go_button, again_button], + ) + ) + ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/flet_animation/pyproject.toml b/sdk/python/examples/apps/flet_animation/pyproject.toml new file mode 100644 index 0000000000..0fd77a3a3f --- /dev/null +++ b/sdk/python/examples/apps/flet_animation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-flet-animation" +version = "1.0.0" +description = "Animates scattered blocks into the FLET logo with randomized colors, size, and rotation." +requires-python = ">=3.10" +keywords = ["apps", "animation", "logo", "stack", "implicit animations"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Animation"] + +[tool.flet.metadata] +title = "Flet animation" +controls = ["SafeArea", "Column", "Stack", "Container", "Button"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["implicit animations", "randomized layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/flet_animation/requirements.txt b/sdk/python/examples/apps/flet_animation/requirements.txt deleted file mode 100644 index 9f5592458b..0000000000 --- a/sdk/python/examples/apps/flet_animation/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet>=0.25.1 diff --git a/sdk/python/examples/apps/greeter/basic/main.py b/sdk/python/examples/apps/greeter/basic/main.py new file mode 100644 index 0000000000..645930807f --- /dev/null +++ b/sdk/python/examples/apps/greeter/basic/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + greeting = ft.Text() + txt_name = ft.TextField(label="Your name") + + def btn_click(e): + if not txt_name.value: + txt_name.error_text = "Please enter your name" + greeting.value = "" + else: + txt_name.error_text = None + greeting.value = f"Hello, {txt_name.value}!" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + txt_name, + ft.Button("Say hello!", on_click=btn_click), + greeting, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/greeter/basic/pyproject.toml b/sdk/python/examples/apps/greeter/basic/pyproject.toml new file mode 100644 index 0000000000..37d0d9c705 --- /dev/null +++ b/sdk/python/examples/apps/greeter/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-greeter-basic" +version = "1.0.0" +description = "Prompts for a name and greets the user while validating an empty text field." +requires-python = ">=3.10" +keywords = ["apps", "greeter", "form", "text field", "validation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Basic"] + +[tool.flet.metadata] +title = "Basic greeter" +controls = ["SafeArea", "Column", "TextField", "Button", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["form validation", "text updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/greeter/greeter.py b/sdk/python/examples/apps/greeter/greeter.py deleted file mode 100644 index 1fec7b5da5..0000000000 --- a/sdk/python/examples/apps/greeter/greeter.py +++ /dev/null @@ -1,19 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - def btn_click(e): - if not txt_name.value: - txt_name.error_text = "Please enter your name" - page.update() - else: - name = txt_name.value - page.clean() - page.add(ft.Text(f"Hello, {name}!")) - - txt_name = ft.TextField(label="Your name") - - page.add(txt_name, ft.Button("Say hello!", on_click=btn_click)) - - -ft.run(main) diff --git a/sdk/python/examples/apps/greeter/requirements.txt b/sdk/python/examples/apps/greeter/requirements.txt deleted file mode 100644 index 9f5592458b..0000000000 --- a/sdk/python/examples/apps/greeter/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet>=0.25.1 diff --git a/sdk/python/examples/apps/hello_world/basic/main.py b/sdk/python/examples/apps/hello_world/basic/main.py new file mode 100644 index 0000000000..4c60595784 --- /dev/null +++ b/sdk/python/examples/apps/hello_world/basic/main.py @@ -0,0 +1,9 @@ +import flet as ft + + +def main(page: ft.Page): + page.add(ft.SafeArea(content=ft.Text("Hello, world!"))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/hello_world/basic/pyproject.toml b/sdk/python/examples/apps/hello_world/basic/pyproject.toml new file mode 100644 index 0000000000..e5d35f22e1 --- /dev/null +++ b/sdk/python/examples/apps/hello_world/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-hello-world-basic" +version = "1.0.0" +description = "Minimal app that renders a single hello-world text message." +requires-python = ">=3.10" +keywords = ["apps", "hello world", "minimal", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Basic"] + +[tool.flet.metadata] +title = "Hello world" +controls = ["SafeArea", "Text"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["minimal app"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/hello_world/hello.py b/sdk/python/examples/apps/hello_world/hello.py deleted file mode 100644 index c1f0bb7215..0000000000 --- a/sdk/python/examples/apps/hello_world/hello.py +++ /dev/null @@ -1,8 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add(ft.Text("Hello, world!")) - - -ft.run(main) diff --git a/sdk/python/examples/apps/hello_world/requirements.txt b/sdk/python/examples/apps/hello_world/requirements.txt deleted file mode 100644 index 9f5592458b..0000000000 --- a/sdk/python/examples/apps/hello_world/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet>=0.25.1 diff --git a/sdk/python/examples/apps/icons_browser/Dockerfile b/sdk/python/examples/apps/icons_browser/Dockerfile deleted file mode 100644 index 2fe01b9780..0000000000 --- a/sdk/python/examples/apps/icons_browser/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM python:3-alpine - -WORKDIR /app - -COPY requirements.txt ./ -RUN pip install --no-cache-dir -r requirements.txt - -COPY . . - -EXPOSE 8080 - -CMD ["python", "./main.py"] diff --git a/sdk/python/examples/apps/icons_browser/README.md b/sdk/python/examples/apps/icons_browser/README.md deleted file mode 100644 index 636a05e423..0000000000 --- a/sdk/python/examples/apps/icons_browser/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Flet Icons Browser with deployment to Fly.io - -Deploy: - - flyctl deploy - -Check deployment: - - flyctl status - -Re-deploy: - - flyctl deploy --no-cache diff --git a/sdk/python/examples/apps/icons_browser/fly.toml b/sdk/python/examples/apps/icons_browser/fly.toml deleted file mode 100644 index 2809ceb716..0000000000 --- a/sdk/python/examples/apps/icons_browser/fly.toml +++ /dev/null @@ -1,40 +0,0 @@ -app = "flet-icons-browser" - -kill_signal = "SIGINT" -kill_timeout = 5 -processes = [] - -[env] - FLET_SERVER_PORT = "8080" - FLET_FORCE_WEB_SERVER = "true" - -[experimental] - allowed_public_ports = [] - auto_rollback = true - -[[services]] - http_checks = [] - internal_port = 8080 - processes = ["app"] - protocol = "tcp" - script_checks = [] - - [services.concurrency] - hard_limit = 25 - soft_limit = 20 - type = "connections" - - [[services.ports]] - force_https = true - handlers = ["http"] - port = 80 - - [[services.ports]] - handlers = ["tls", "http"] - port = 443 - - [[services.tcp_checks]] - grace_period = "1s" - interval = "15s" - restart_limit = 0 - timeout = "2s" diff --git a/sdk/python/examples/apps/icons_browser/main.py b/sdk/python/examples/apps/icons_browser/main.py index 577cc99100..836f24860f 100644 --- a/sdk/python/examples/apps/icons_browser/main.py +++ b/sdk/python/examples/apps/icons_browser/main.py @@ -147,30 +147,34 @@ async def display_icons(search_term: str): def main(page: ft.Page): page.title = "Flet icons browser" page.add( - ft.Tabs( - selected_index=0, - length=2, + ft.SafeArea( expand=True, - content=ft.Column( + content=ft.Tabs( + selected_index=0, + length=2, expand=True, - controls=[ - ft.TabBar( - tabs=[ - ft.Tab(label="Material"), - ft.Tab(label="Cupertino"), - ] - ), - ft.TabBarView( - expand=True, - controls=[ - IconBrowser(ft.Icons, expand=True), - IconBrowser(ft.CupertinoIcons, expand=True), - ], - ), - ], + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label="Material"), + ft.Tab(label="Cupertino"), + ] + ), + ft.TabBarView( + expand=True, + controls=[ + IconBrowser(ft.Icons, expand=True), + IconBrowser(ft.CupertinoIcons, expand=True), + ], + ), + ], + ), ), ) ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/icons_browser/pyproject.toml b/sdk/python/examples/apps/icons_browser/pyproject.toml new file mode 100644 index 0000000000..d1f9c37b6a --- /dev/null +++ b/sdk/python/examples/apps/icons_browser/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-icons-browser" +version = "1.0.0" +description = "Searches Material and Cupertino icon sets and copies selected icon constants to the clipboard." +requires-python = ">=3.10" +keywords = ["apps", "icons", "search", "clipboard", "tabs", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Search"] + +[tool.flet.metadata] +title = "Icons browser" +controls = ["SafeArea", "Tabs", "TabBar", "TabBarView", "TextField", "IconButton", "GridView", "TextButton", "SnackBar"] +layout_pattern = "list-detail" +complexity = "intermediate" +features = ["icon search", "clipboard copy", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/icons_browser/requirements.txt b/sdk/python/examples/apps/icons_browser/requirements.txt deleted file mode 100644 index 3a0e96024e..0000000000 --- a/sdk/python/examples/apps/icons_browser/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet>=0.80.0 diff --git a/sdk/python/examples/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh index 34817b020d..ee5db8699c 100644 --- a/sdk/python/examples/publish-gallery.sh +++ b/sdk/python/examples/publish-gallery.sh @@ -8,5 +8,5 @@ flet publish apps/trolli-declarative/src/main.py --distpath $DIST_PATH/trolli -- flet publish apps/routing_navigation/home_store.py --distpath $DIST_PATH/simple_routing --base-url simple_routing --route-url-strategy "hash" --app-name "Flet routing example" --app-description "An example of routing in Flet." flet publish apps/counter/basic/main.py --distpath $DIST_PATH/counter --base-url counter --app-name "Counter" --app-description "Counter to get an idea of Flet." flet publish apps/flet_animation/main.py --distpath $DIST_PATH/flet_animation --base-url flet_animation --app-name "Flet animation" --app-description "An example of implicit animations in Flet." -flet publish apps/greeter/greeter.py --distpath $DIST_PATH/greeter --base-url greeter --app-name "Greeter" --app-description "A basic example of interactive forms in Flet." -flet publish apps/hello_world/hello.py --distpath $DIST_PATH/hello_world --base-url hello_world --app-name "Hello, world!" --app-description "A very minimal example of Flet app." +flet publish apps/greeter/basic/main.py --distpath $DIST_PATH/greeter --base-url greeter --app-name "Greeter" --app-description "A basic example of interactive forms in Flet." +flet publish apps/hello_world/basic/main.py --distpath $DIST_PATH/hello_world --base-url hello_world --app-name "Hello, world!" --app-description "A very minimal example of Flet app." From 52c54369e924b6b90f49a5a7bf086100333e3e03 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 15:52:01 -0700 Subject: [PATCH 92/96] Migrate routing navigation examples --- .../apps/routing_navigation/__init__.py | 0 .../building_views_on_route_change.py | 73 --------- .../building_views_on_route_change/main.py | 94 ++++++++++++ .../pyproject.toml | 26 ++++ .../routing_navigation/drawer_navigation.py | 109 ------------- .../drawer_navigation/main.py | 143 ++++++++++++++++++ .../drawer_navigation/pyproject.toml | 26 ++++ .../apps/routing_navigation/home_store.py | 56 ------- .../routing_navigation/home_store/main.py | 74 +++++++++ .../home_store/pyproject.toml | 26 ++++ .../main.py} | 2 +- .../initial_route/pyproject.toml | 26 ++++ .../main.py} | 19 ++- .../pop_view_confirm/pyproject.toml | 26 ++++ .../routing_navigation/route_change_event.py | 15 -- .../route_change_event/main.py | 16 ++ .../route_change_event/pyproject.toml | 26 ++++ sdk/python/examples/publish-gallery.sh | 2 +- .../docs/cookbook/navigation-and-routing.md | 10 +- 19 files changed, 505 insertions(+), 264 deletions(-) delete mode 100644 sdk/python/examples/apps/routing_navigation/__init__.py delete mode 100644 sdk/python/examples/apps/routing_navigation/building_views_on_route_change.py create mode 100644 sdk/python/examples/apps/routing_navigation/building_views_on_route_change/main.py create mode 100644 sdk/python/examples/apps/routing_navigation/building_views_on_route_change/pyproject.toml delete mode 100644 sdk/python/examples/apps/routing_navigation/drawer_navigation.py create mode 100644 sdk/python/examples/apps/routing_navigation/drawer_navigation/main.py create mode 100644 sdk/python/examples/apps/routing_navigation/drawer_navigation/pyproject.toml delete mode 100644 sdk/python/examples/apps/routing_navigation/home_store.py create mode 100644 sdk/python/examples/apps/routing_navigation/home_store/main.py create mode 100644 sdk/python/examples/apps/routing_navigation/home_store/pyproject.toml rename sdk/python/examples/apps/routing_navigation/{initial_route.py => initial_route/main.py} (54%) create mode 100644 sdk/python/examples/apps/routing_navigation/initial_route/pyproject.toml rename sdk/python/examples/apps/routing_navigation/{pop_view_confirm.py => pop_view_confirm/main.py} (78%) create mode 100644 sdk/python/examples/apps/routing_navigation/pop_view_confirm/pyproject.toml delete mode 100644 sdk/python/examples/apps/routing_navigation/route_change_event.py create mode 100644 sdk/python/examples/apps/routing_navigation/route_change_event/main.py create mode 100644 sdk/python/examples/apps/routing_navigation/route_change_event/pyproject.toml diff --git a/sdk/python/examples/apps/routing_navigation/__init__.py b/sdk/python/examples/apps/routing_navigation/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/python/examples/apps/routing_navigation/building_views_on_route_change.py b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change.py deleted file mode 100644 index 455cd7f38b..0000000000 --- a/sdk/python/examples/apps/routing_navigation/building_views_on_route_change.py +++ /dev/null @@ -1,73 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Routes Example" - - print("Initial route:", page.route) - - async def open_mail_settings(e): - await page.push_route("/settings/mail") - - async def open_settings(e): - await page.push_route("/settings") - - def route_change(): - print("Route change:", page.route) - page.views.clear() - page.views.append( - ft.View( - route="/", - controls=[ - ft.AppBar(title=ft.Text("Flet app")), - ft.Button("Go to settings", on_click=open_settings), - ], - ) - ) - if page.route == "/settings" or page.route == "/settings/mail": - page.views.append( - ft.View( - route="/settings", - controls=[ - ft.AppBar( - title=ft.Text("Settings"), - bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, - ), - ft.Text("Settings!", theme_style=ft.TextThemeStyle.BODY_MEDIUM), - ft.Button( - content="Go to mail settings", - on_click=open_mail_settings, - ), - ], - ) - ) - if page.route == "/settings/mail": - page.views.append( - ft.View( - route="/settings/mail", - controls=[ - ft.AppBar( - title=ft.Text("Mail Settings"), - bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, - ), - ft.Text("Mail settings!"), - ], - ) - ) - page.update() - - async def view_pop(e): - if e.view is not None: - print("View pop:", e.view) - page.views.remove(e.view) - top_view = page.views[-1] - await page.push_route(top_view.route) - - page.on_route_change = route_change - page.on_view_pop = view_pop - - route_change() - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/main.py b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/main.py new file mode 100644 index 0000000000..1831fb8f40 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/main.py @@ -0,0 +1,94 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Routes Example" + + print("Initial route:", page.route) + + async def open_mail_settings(e): + await page.push_route("/settings/mail") + + async def open_settings(e): + await page.push_route("/settings") + + def route_change(): + print("Route change:", page.route) + page.views.clear() + page.views.append( + ft.View( + route="/", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar(title=ft.Text("Flet app")), + ft.Button("Go to settings", on_click=open_settings), + ] + ) + ) + ], + ) + ) + if page.route == "/settings" or page.route == "/settings/mail": + page.views.append( + ft.View( + route="/settings", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Settings"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + ), + ft.Text( + "Settings!", + theme_style=ft.TextThemeStyle.BODY_MEDIUM, + ), + ft.Button( + content="Go to mail settings", + on_click=open_mail_settings, + ), + ] + ) + ) + ], + ) + ) + if page.route == "/settings/mail": + page.views.append( + ft.View( + route="/settings/mail", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Mail Settings"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + ), + ft.Text("Mail settings!"), + ] + ) + ) + ], + ) + ) + page.update() + + async def view_pop(e): + if e.view is not None: + print("View pop:", e.view) + page.views.remove(e.view) + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + + route_change() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/pyproject.toml b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/pyproject.toml new file mode 100644 index 0000000000..812e8b12c6 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-building-views-on-route-change" +version = "1.0.0" +description = "Builds a navigation stack from the current route and handles nested settings routes." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation", "views", "route change"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Navigation"] + +[tool.flet.metadata] +title = "Building views on route change" +controls = ["View", "SafeArea", "Column", "AppBar", "Button", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["routing", "nested routes", "back navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/drawer_navigation.py b/sdk/python/examples/apps/routing_navigation/drawer_navigation.py deleted file mode 100644 index cc85713e93..0000000000 --- a/sdk/python/examples/apps/routing_navigation/drawer_navigation.py +++ /dev/null @@ -1,109 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.title = "Drawer navigation" - - async def handle_change(e): - if e.control.selected_index == 0: - await page.push_route("/") - elif e.control.selected_index == 1: - await page.push_route("/store") - elif e.control.selected_index == 2: - await page.push_route("/about") - - def create_drawer(selected_index=0): - return ft.NavigationDrawer( - selected_index=selected_index, - on_change=handle_change, - controls=[ - ft.Container(height=12), - ft.NavigationDrawerDestination( - label="Home", - icon=ft.Icons.HOME_OUTLINED, - selected_icon=ft.Icon(ft.Icons.HOME), - ), - ft.Divider(thickness=2), - ft.NavigationDrawerDestination( - label="Store", - icon=ft.Icon(ft.Icons.STORE_OUTLINED), - selected_icon=ft.Icon(ft.Icons.STORE), - ), - ft.NavigationDrawerDestination( - label="About", - icon=ft.Icon(ft.Icons.PHONE_OUTLINED), - selected_icon=ft.Icons.PHONE, - ), - ], - ) - - async def show_drawer(): - await page.show_drawer() - - def route_change(route): - page.views.clear() - page.views.append( - ft.View( - route="/", - controls=[ - ft.AppBar( - title=ft.Text("Home", expand=True), - bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, - leading=ft.IconButton(ft.Icons.MENU, on_click=show_drawer), - ), - ft.Text("Welcome to Home Page"), - ], - drawer=create_drawer(selected_index=0) - if page.route == "/" - else None, # add drawer only if home page is shown - ) - ) - - if page.route == "/store": - page.views.append( - ft.View( - route="/store", - controls=[ - ft.AppBar( - title=ft.Text("Store", expand=True), - bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, - leading=ft.IconButton(ft.Icons.MENU, on_click=show_drawer), - automatically_imply_leading=False, - ), - ft.Text("Welcome to Store Page"), - ft.Button("Go About", on_click=lambda _: page.go("/about")), - ], - drawer=create_drawer(selected_index=1), - ) - ) - - if page.route == "/about": - page.views.append( - ft.View( - route="/about", - controls=[ - ft.AppBar( - title=ft.Text("About", expand=True), - bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, - leading=ft.IconButton(ft.Icons.MENU, on_click=show_drawer), - automatically_imply_leading=False, - ), - ft.Text("Welcome to About Page"), - ft.Button("Go Store", on_click=lambda _: page.go("/store")), - ], - drawer=create_drawer(selected_index=2), - ) - ) - - async def view_pop(view): - page.views.pop() - top_view = page.views[-1] - await page.push_route(top_view.route) - - page.on_route_change = route_change - page.on_view_pop = view_pop - route_change(page.route) - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/drawer_navigation/main.py b/sdk/python/examples/apps/routing_navigation/drawer_navigation/main.py new file mode 100644 index 0000000000..a378907d3a --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/drawer_navigation/main.py @@ -0,0 +1,143 @@ +import asyncio + +import flet as ft + + +def main(page: ft.Page): + page.title = "Drawer navigation" + + async def handle_change(e): + if e.control.selected_index == 0: + await page.push_route("/") + elif e.control.selected_index == 1: + await page.push_route("/store") + elif e.control.selected_index == 2: + await page.push_route("/about") + + def create_drawer(selected_index=0): + return ft.NavigationDrawer( + selected_index=selected_index, + on_change=handle_change, + controls=[ + ft.Container(height=12), + ft.NavigationDrawerDestination( + label="Home", + icon=ft.Icons.HOME_OUTLINED, + selected_icon=ft.Icon(ft.Icons.HOME), + ), + ft.Divider(thickness=2), + ft.NavigationDrawerDestination( + label="Store", + icon=ft.Icon(ft.Icons.STORE_OUTLINED), + selected_icon=ft.Icon(ft.Icons.STORE), + ), + ft.NavigationDrawerDestination( + label="About", + icon=ft.Icon(ft.Icons.PHONE_OUTLINED), + selected_icon=ft.Icons.PHONE, + ), + ], + ) + + async def show_drawer(): + await page.show_drawer() + + def route_change(route): + page.views.clear() + page.views.append( + ft.View( + route="/", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Home", expand=True), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + leading=ft.IconButton( + ft.Icons.MENU, on_click=show_drawer + ), + ), + ft.Text("Welcome to Home Page"), + ] + ) + ) + ], + drawer=create_drawer(selected_index=0) if page.route == "/" else None, + ) + ) + + if page.route == "/store": + page.views.append( + ft.View( + route="/store", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Store", expand=True), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + leading=ft.IconButton( + ft.Icons.MENU, on_click=show_drawer + ), + automatically_imply_leading=False, + ), + ft.Text("Welcome to Store Page"), + ft.Button( + "Go About", + on_click=lambda _: asyncio.create_task( + page.push_route("/about") + ), + ), + ] + ) + ) + ], + drawer=create_drawer(selected_index=1), + ) + ) + + if page.route == "/about": + page.views.append( + ft.View( + route="/about", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("About", expand=True), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + leading=ft.IconButton( + ft.Icons.MENU, on_click=show_drawer + ), + automatically_imply_leading=False, + ), + ft.Text("Welcome to About Page"), + ft.Button( + "Go Store", + on_click=lambda _: asyncio.create_task( + page.push_route("/store") + ), + ), + ] + ) + ) + ], + drawer=create_drawer(selected_index=2), + ) + ) + + async def view_pop(view): + page.views.pop() + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + route_change(page.route) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/drawer_navigation/pyproject.toml b/sdk/python/examples/apps/routing_navigation/drawer_navigation/pyproject.toml new file mode 100644 index 0000000000..854b6c7fa6 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/drawer_navigation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-drawer-navigation" +version = "1.0.0" +description = "Connects a navigation drawer to route changes across home, store, and about views." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation drawer", "views", "destinations"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Navigation"] + +[tool.flet.metadata] +title = "Drawer navigation" +controls = ["View", "SafeArea", "Column", "AppBar", "NavigationDrawer", "NavigationDrawerDestination", "Button", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["routing", "drawer navigation", "back navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/home_store.py b/sdk/python/examples/apps/routing_navigation/home_store.py deleted file mode 100644 index 32d368d9be..0000000000 --- a/sdk/python/examples/apps/routing_navigation/home_store.py +++ /dev/null @@ -1,56 +0,0 @@ -import asyncio - -import flet as ft - - -def main(page: ft.Page): - page.title = "Routes Example" - - def route_change(): - page.views.clear() - page.views.append( - ft.View( - route="/", - controls=[ - ft.AppBar( - title=ft.Text("Flet app"), bgcolor=ft.Colors.SURFACE_BRIGHT - ), - ft.Button( - "Visit Store", - on_click=lambda: asyncio.create_task(page.push_route("/store")), - ), - ], - ) - ) - if page.route == "/store": - page.views.append( - ft.View( - route="/store", - controls=[ - ft.AppBar( - title=ft.Text("Store"), bgcolor=ft.Colors.SURFACE_BRIGHT - ), - ft.Button( - "Go Home", - on_click=lambda: asyncio.create_task(page.push_route("/")), - ), - ], - ) - ) - page.update() - - async def view_pop(e): - if e.view is not None: - print("View pop:", e.view) - page.views.remove(e.view) - top_view = page.views[-1] - await page.push_route(top_view.route) - - page.on_route_change = route_change - page.on_view_pop = view_pop - - route_change() - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/home_store/main.py b/sdk/python/examples/apps/routing_navigation/home_store/main.py new file mode 100644 index 0000000000..8d673c6a90 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/home_store/main.py @@ -0,0 +1,74 @@ +import asyncio + +import flet as ft + + +def main(page: ft.Page): + page.title = "Routes Example" + + def route_change(): + page.views.clear() + page.views.append( + ft.View( + route="/", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Flet app"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + ft.Button( + "Visit Store", + on_click=lambda: asyncio.create_task( + page.push_route("/store") + ), + ), + ] + ) + ) + ], + ) + ) + if page.route == "/store": + page.views.append( + ft.View( + route="/store", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Store"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + ft.Button( + "Go Home", + on_click=lambda: asyncio.create_task( + page.push_route("/") + ), + ), + ] + ) + ) + ], + ) + ) + page.update() + + async def view_pop(e): + if e.view is not None: + print("View pop:", e.view) + page.views.remove(e.view) + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + + route_change() + + +if __name__ == "__main__": + ft.run(main, route_url_strategy="hash") diff --git a/sdk/python/examples/apps/routing_navigation/home_store/pyproject.toml b/sdk/python/examples/apps/routing_navigation/home_store/pyproject.toml new file mode 100644 index 0000000000..6af76600d3 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/home_store/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-home-store" +version = "1.0.0" +description = "Shows a minimal route-driven home and store flow using view stack navigation." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation", "home", "store", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Navigation"] + +[tool.flet.metadata] +title = "Home store" +controls = ["View", "SafeArea", "Column", "AppBar", "Button"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["routing", "view stack", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/initial_route.py b/sdk/python/examples/apps/routing_navigation/initial_route/main.py similarity index 54% rename from sdk/python/examples/apps/routing_navigation/initial_route.py rename to sdk/python/examples/apps/routing_navigation/initial_route/main.py index d8e4b49ab9..40dfb1a96a 100644 --- a/sdk/python/examples/apps/routing_navigation/initial_route.py +++ b/sdk/python/examples/apps/routing_navigation/initial_route/main.py @@ -2,7 +2,7 @@ def main(page: ft.Page): - page.add(ft.Text(f"Initial route: {page.route}")) + page.add(ft.SafeArea(content=ft.Text(f"Initial route: {page.route}"))) if __name__ == "__main__": diff --git a/sdk/python/examples/apps/routing_navigation/initial_route/pyproject.toml b/sdk/python/examples/apps/routing_navigation/initial_route/pyproject.toml new file mode 100644 index 0000000000..2070722e02 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/initial_route/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-initial-route" +version = "1.0.0" +description = "Displays the initial route string passed into a Flet app." +requires-python = ">=3.10" +keywords = ["apps", "routing", "route", "text", "minimal"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Navigation"] + +[tool.flet.metadata] +title = "Initial route" +controls = ["SafeArea", "Text"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["routing basics"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/pop_view_confirm.py b/sdk/python/examples/apps/routing_navigation/pop_view_confirm/main.py similarity index 78% rename from sdk/python/examples/apps/routing_navigation/pop_view_confirm.py rename to sdk/python/examples/apps/routing_navigation/pop_view_confirm/main.py index dfe8fca43d..d4a0b096ff 100644 --- a/sdk/python/examples/apps/routing_navigation/pop_view_confirm.py +++ b/sdk/python/examples/apps/routing_navigation/pop_view_confirm/main.py @@ -28,9 +28,15 @@ class MainView(ft.View): def __init__(self, path): super().__init__( route=path, - appbar=ft.AppBar(title=ft.Text("Flet app")), controls=[ - ft.Button("Go to store", on_click=self.open_store), + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar(title=ft.Text("Flet app")), + ft.Button("Go to store", on_click=self.open_store), + ] + ) + ) ], ) @@ -42,7 +48,13 @@ class PermissionView(ft.View): def __init__(self, path): super().__init__( route=path, - appbar=ft.AppBar(title=ft.Text(f"{path} View")), + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ft.AppBar(title=ft.Text(f"{path} View"))] + ) + ) + ], can_pop=False, on_confirm_pop=self.ask_pop_permission, ) @@ -74,7 +86,6 @@ async def on_dlg_no(e): ) self.page.show_dialog(dlg_modal) - # await self.confirm_pop(True) if __name__ == "__main__": diff --git a/sdk/python/examples/apps/routing_navigation/pop_view_confirm/pyproject.toml b/sdk/python/examples/apps/routing_navigation/pop_view_confirm/pyproject.toml new file mode 100644 index 0000000000..191984d07f --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/pop_view_confirm/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-pop-view-confirm" +version = "1.0.0" +description = "Confirms whether a view is allowed to pop before returning from the store route." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation", "confirmation dialog", "view pop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Navigation"] + +[tool.flet.metadata] +title = "Pop view confirm" +controls = ["View", "SafeArea", "Column", "AppBar", "Button", "AlertDialog", "TextButton", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["routing", "confirmation dialog", "back navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/route_change_event.py b/sdk/python/examples/apps/routing_navigation/route_change_event.py deleted file mode 100644 index 80fc71f9e3..0000000000 --- a/sdk/python/examples/apps/routing_navigation/route_change_event.py +++ /dev/null @@ -1,15 +0,0 @@ -import flet as ft - - -def main(page: ft.Page): - page.add(ft.Text(f"Initial route: {page.route}")) - - def route_change(e): - page.add(ft.Text(f"New route: {e.route}")) - - page.on_route_change = route_change - page.update() - - -if __name__ == "__main__": - ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/route_change_event/main.py b/sdk/python/examples/apps/routing_navigation/route_change_event/main.py new file mode 100644 index 0000000000..c18bfb0cda --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/route_change_event/main.py @@ -0,0 +1,16 @@ +import flet as ft + + +def main(page: ft.Page): + route_log = ft.Column(controls=[ft.Text(f"Initial route: {page.route}")]) + page.add(ft.SafeArea(content=route_log)) + + def route_change(e): + route_log.controls.append(ft.Text(f"New route: {e.route}")) + + page.on_route_change = route_change + page.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/route_change_event/pyproject.toml b/sdk/python/examples/apps/routing_navigation/route_change_event/pyproject.toml new file mode 100644 index 0000000000..6721e3f80b --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/route_change_event/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-route-change-event" +version = "1.0.0" +description = "Logs each route change by appending the new route string to the page." +requires-python = ">=3.10" +keywords = ["apps", "routing", "events", "route change", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Navigation"] + +[tool.flet.metadata] +title = "Route change event" +controls = ["SafeArea", "Text"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["routing basics", "route change event"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh index ee5db8699c..4b4febc979 100644 --- a/sdk/python/examples/publish-gallery.sh +++ b/sdk/python/examples/publish-gallery.sh @@ -5,7 +5,7 @@ flet publish apps/icons_browser/main.py --distpath $DIST_PATH/icons_browser --ba flet publish tutorials/calculator/calc.py --distpath $DIST_PATH/calculator --base-url calculator --app-name "Calculator" --app-description "A simple calculator app written in Flet." flet publish tutorials/solitaire_declarative/solitaire-final/main.py --distpath $DIST_PATH/solitaire --base-url solitaire --assets assets --app-name "Solitaire" --app-description "Learn how to handle gestures and position controls on a page." flet publish apps/trolli-declarative/src/main.py --distpath $DIST_PATH/trolli --base-url trolli --assets assets --route-url-strategy "hash" --app-name "Trolli" --app-description "A clone of Trello." -flet publish apps/routing_navigation/home_store.py --distpath $DIST_PATH/simple_routing --base-url simple_routing --route-url-strategy "hash" --app-name "Flet routing example" --app-description "An example of routing in Flet." +flet publish apps/routing_navigation/home_store/main.py --distpath $DIST_PATH/simple_routing --base-url simple_routing --route-url-strategy "hash" --app-name "Flet routing example" --app-description "An example of routing in Flet." flet publish apps/counter/basic/main.py --distpath $DIST_PATH/counter --base-url counter --app-name "Counter" --app-description "Counter to get an idea of Flet." flet publish apps/flet_animation/main.py --distpath $DIST_PATH/flet_animation --base-url flet_animation --app-name "Flet animation" --app-description "An example of implicit animations in Flet." flet publish apps/greeter/basic/main.py --distpath $DIST_PATH/greeter --base-url greeter --app-name "Greeter" --app-description "A basic example of interactive forms in Flet." diff --git a/sdk/python/packages/flet/docs/cookbook/navigation-and-routing.md b/sdk/python/packages/flet/docs/cookbook/navigation-and-routing.md index 2d355933af..a2525c9c56 100644 --- a/sdk/python/packages/flet/docs/cookbook/navigation-and-routing.md +++ b/sdk/python/packages/flet/docs/cookbook/navigation-and-routing.md @@ -20,7 +20,7 @@ A reliable setup uses a single source of truth: derive [`page.views`][flet.Page. The default route is `/` when no route is provided. ```python ---8<-- "../../examples/apps/routing_navigation/initial_route.py" +--8<-- "../../examples/apps/routing_navigation/initial_route/main.py" ``` All routes should start with `/`, for example `/store`, `/products/42`, `/settings/mail`. @@ -32,7 +32,7 @@ Whenever route changes (URL edit, browser Back/Forward, or app navigation), Use this event as the place where you decide which views must exist for the current route. ```python ---8<-- "../../examples/apps/routing_navigation/route_change_event.py" +--8<-- "../../examples/apps/routing_navigation/route_change_event/main.py" ``` ## Building views from route @@ -52,7 +52,7 @@ The pattern below is the baseline for most apps: /// ```python ---8<-- "../../examples/apps/routing_navigation/building_views_on_route_change.py" +--8<-- "../../examples/apps/routing_navigation/building_views_on_route_change/main.py" ``` ## Programmatic navigation @@ -72,7 +72,7 @@ For flows requiring confirmation (for example, unsaved changes), disable automat and confirm manually with [`View.can_pop`][flet.View.can_pop] + [`View.on_confirm_pop`][flet.View.on_confirm_pop]. ```python ---8<-- "../../examples/apps/routing_navigation/pop_view_confirm.py" +--8<-- "../../examples/apps/routing_navigation/pop_view_confirm/main.py" ``` ## Navigation UI patterns @@ -81,7 +81,7 @@ Routing composes well with navigation controls such as drawer, rail, and tabs. This example shows route-driven drawer navigation with multiple top-level destinations: ```python ---8<-- "../../examples/apps/routing_navigation/drawer_navigation.py" +--8<-- "../../examples/apps/routing_navigation/drawer_navigation/main.py" ``` ## Route templates (parameterized routes) From e0bd6c084d4bdc3bc9d75ecc5a9835ca901143f1 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 15:56:37 -0700 Subject: [PATCH 93/96] Migrate timer app examples --- .../{declarative.py => declarative/main.py} | 42 ++++--------------- .../apps/timer/declarative/pyproject.toml | 26 ++++++++++++ .../{imperative.py => imperative/main.py} | 34 ++++----------- .../apps/timer/imperative/pyproject.toml | 26 ++++++++++++ 4 files changed, 66 insertions(+), 62 deletions(-) rename sdk/python/examples/apps/timer/{declarative.py => declarative/main.py} (73%) create mode 100644 sdk/python/examples/apps/timer/declarative/pyproject.toml rename sdk/python/examples/apps/timer/{imperative.py => imperative/main.py} (77%) create mode 100644 sdk/python/examples/apps/timer/imperative/pyproject.toml diff --git a/sdk/python/examples/apps/timer/declarative.py b/sdk/python/examples/apps/timer/declarative/main.py similarity index 73% rename from sdk/python/examples/apps/timer/declarative.py rename to sdk/python/examples/apps/timer/declarative/main.py index b160e0dd9d..19853b2adf 100644 --- a/sdk/python/examples/apps/timer/declarative.py +++ b/sdk/python/examples/apps/timer/declarative/main.py @@ -16,67 +16,41 @@ def format_hhmmss(seconds: int) -> str: @ft.observable @dataclass class TimerState: - """ - Declarative timer state. - - This class is the single source of truth for the UI. - Any mutation of its public fields automatically triggers a re-render. - """ - running: bool = False paused: bool = False - elapsed: int = 0 # seconds shown in UI + elapsed: int = 0 - # Internals - _base_elapsed: int = 0 # accumulated time before the current run - _started_at: float = 0.0 # wall-clock start time - _task: asyncio.Task | None = None # background ticker task + _base_elapsed: int = 0 + _started_at: float = 0.0 + _task: asyncio.Task | None = None async def _ticker(self): - """ - Background task that updates elapsed time once per second - while the timer is running. - """ while self.running: if not self.paused: self.elapsed = self._base_elapsed + int(time.time() - self._started_at) await asyncio.sleep(1) - - # Task cleanup when stopped self._task = None def toggle(self): - """ - Toggle button handler: - - stopped → start - - running → pause - - paused → resume - """ - # stopped → start if not self.running: self.running = True self.paused = False self._base_elapsed = self.elapsed self._started_at = time.time() - - # Ensure only one ticker task runs if self._task is None or self._task.done(): self._task = asyncio.create_task(self._ticker()) return - # running → pause if not self.paused: self._base_elapsed += int(time.time() - self._started_at) self.elapsed = self._base_elapsed self.paused = True return - # paused → resume self.paused = False self._started_at = time.time() def stop(self): - """Stop the timer and reset all state.""" self.running = False self.paused = False self.elapsed = 0 @@ -88,12 +62,11 @@ def stop(self): def App(): state, _ = ft.use_state(TimerState()) - # Button appearance derived entirely from state label = "Pause" if state.running and not state.paused else "Start" icon = ft.Icons.PAUSE if state.running and not state.paused else ft.Icons.PLAY_ARROW return ft.SafeArea( - ft.Column( + content=ft.Column( spacing=20, horizontal_alignment=ft.CrossAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.CENTER, @@ -125,11 +98,10 @@ def App(): def main(page: ft.Page): - """Application entry point.""" page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.render(App) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/timer/declarative/pyproject.toml b/sdk/python/examples/apps/timer/declarative/pyproject.toml new file mode 100644 index 0000000000..b8b3fc5f63 --- /dev/null +++ b/sdk/python/examples/apps/timer/declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-timer-declarative" +version = "1.0.0" +description = "Declarative stopwatch example driven by observable timer state and async ticking." +requires-python = ">=3.10" +keywords = ["apps", "timer", "declarative", "stopwatch", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Time"] + +[tool.flet.metadata] +title = "Declarative timer" +controls = ["SafeArea", "Column", "Row", "Text", "FilledButton", "TextButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["async", "timer controls", "observable state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/timer/imperative.py b/sdk/python/examples/apps/timer/imperative/main.py similarity index 77% rename from sdk/python/examples/apps/timer/imperative.py rename to sdk/python/examples/apps/timer/imperative/main.py index 46254fbdb1..1db6e6adab 100644 --- a/sdk/python/examples/apps/timer/imperative.py +++ b/sdk/python/examples/apps/timer/imperative/main.py @@ -16,18 +16,16 @@ def main(page: ft.Page): page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - # State variables running = False paused = False - elapsed = 0 # seconds shown in the UI - base_elapsed = 0 # accumulated time before the current run - started_at = 0.0 # wall-clock start timestamp + elapsed = 0 + base_elapsed = 0 + started_at = 0.0 def sync_ui(): - """Synchronize UI controls with current state variables.""" + nonlocal elapsed timer.value = format_hhmmss(elapsed) - # Toggle button switches appearance based on state if running and not paused: toggle_btn.text = "Pause" toggle_btn.icon = ft.Icons.PAUSE @@ -35,16 +33,10 @@ def sync_ui(): toggle_btn.text = "Start" toggle_btn.icon = ft.Icons.PLAY_ARROW - # Stop button only enabled when there is something to stop/reset stop_btn.disabled = (not running) and (elapsed == 0) - page.update() async def ticker(): - """ - Background task that updates elapsed time once per second - while the timer is running. - """ nonlocal elapsed while running: if not paused: @@ -54,27 +46,17 @@ async def ticker(): await asyncio.sleep(1) def handle_toggle(): - """ - Toggle button handler: - - stopped → start - - running → pause - - paused → resume - """ nonlocal running, paused, elapsed, base_elapsed, started_at - # stopped → start if not running: running = True paused = False base_elapsed = elapsed started_at = time.time() - - # Start background ticker task page.run_task(ticker) sync_ui() return - # running → pause if not paused: base_elapsed += int(time.time() - started_at) elapsed = base_elapsed @@ -82,13 +64,11 @@ def handle_toggle(): sync_ui() return - # paused → resume paused = False started_at = time.time() sync_ui() def handle_stop(): - """Stop the timer and reset it to 00:00:00.""" nonlocal running, paused, elapsed, base_elapsed, started_at running = False paused = False @@ -99,7 +79,7 @@ def handle_stop(): page.add( ft.SafeArea( - ft.Column( + content=ft.Column( spacing=20, horizontal_alignment=ft.CrossAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.CENTER, @@ -126,8 +106,8 @@ def handle_stop(): ) ) - # Initial UI sync sync_ui() -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/timer/imperative/pyproject.toml b/sdk/python/examples/apps/timer/imperative/pyproject.toml new file mode 100644 index 0000000000..b2f0f1cd1e --- /dev/null +++ b/sdk/python/examples/apps/timer/imperative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-timer-imperative" +version = "1.0.0" +description = "Imperative stopwatch example with start, pause, resume, and stop controls." +requires-python = ">=3.10" +keywords = ["apps", "timer", "imperative", "stopwatch", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Time"] + +[tool.flet.metadata] +title = "Imperative timer" +controls = ["SafeArea", "Column", "Row", "Text", "FilledButton", "TextButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["async", "timer controls"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" From b1181dd0f0b9fe130622fb5c023a9823a26e79c4 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 15:59:56 -0700 Subject: [PATCH 94/96] Normalize todo app example --- sdk/python/examples/apps/todo/Dockerfile | 12 ------ .../apps/todo/{todo.py => basic/main.py} | 8 ++-- .../examples/apps/todo/basic/pyproject.toml | 26 ++++++++++++ sdk/python/examples/apps/todo/fly.toml | 40 ------------------- .../examples/apps/todo/requirements.txt | 1 - sdk/python/examples/publish-gallery.sh | 2 +- .../packages/flet/docs/tutorials/todo.md | 2 +- 7 files changed, 31 insertions(+), 60 deletions(-) delete mode 100644 sdk/python/examples/apps/todo/Dockerfile rename sdk/python/examples/apps/todo/{todo.py => basic/main.py} (97%) create mode 100644 sdk/python/examples/apps/todo/basic/pyproject.toml delete mode 100644 sdk/python/examples/apps/todo/fly.toml delete mode 100644 sdk/python/examples/apps/todo/requirements.txt diff --git a/sdk/python/examples/apps/todo/Dockerfile b/sdk/python/examples/apps/todo/Dockerfile deleted file mode 100644 index 28e8fb638c..0000000000 --- a/sdk/python/examples/apps/todo/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM python:3-alpine - -WORKDIR /app - -COPY requirements.txt ./ -RUN pip install --no-cache-dir -r requirements.txt - -COPY . . - -EXPOSE 8080 - -CMD ["python", "./todo.py"] diff --git a/sdk/python/examples/apps/todo/todo.py b/sdk/python/examples/apps/todo/basic/main.py similarity index 97% rename from sdk/python/examples/apps/todo/todo.py rename to sdk/python/examples/apps/todo/basic/main.py index 05cf7f7b19..39c6ec80ce 100644 --- a/sdk/python/examples/apps/todo/todo.py +++ b/sdk/python/examples/apps/todo/basic/main.py @@ -71,7 +71,6 @@ def delete_clicked(self, e): class TodoApp(ft.Column): - # application's root control is a Column containing all other controls def build(self): self.new_task = ft.TextField( hint_text="What needs to be done?", on_submit=self.add_clicked, expand=True @@ -162,9 +161,8 @@ def main(page: ft.Page): page.title = "ToDo App" page.horizontal_alignment = ft.CrossAxisAlignment.CENTER page.scroll = ft.ScrollMode.ADAPTIVE + page.add(ft.SafeArea(content=TodoApp())) - # create app control and add it to the page - page.add(TodoApp()) - -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/todo/basic/pyproject.toml b/sdk/python/examples/apps/todo/basic/pyproject.toml new file mode 100644 index 0000000000..812157e33e --- /dev/null +++ b/sdk/python/examples/apps/todo/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-todo-basic" +version = "1.0.0" +description = "Classic to-do app with add, edit, delete, and filter interactions inspired by TodoMVC." +requires-python = ">=3.10" +keywords = ["apps", "todo", "tasks", "tabs", "forms"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Productivity"] + +[tool.flet.metadata] +title = "Basic to-do" +controls = ["SafeArea", "Column", "Row", "TextField", "Tabs", "TabBar", "Checkbox", "IconButton", "FloatingActionButton", "OutlinedButton", "Text"] +layout_pattern = "form" +complexity = "intermediate" +features = ["task editing", "task filtering", "list state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/todo/fly.toml b/sdk/python/examples/apps/todo/fly.toml deleted file mode 100644 index 7a3b63726f..0000000000 --- a/sdk/python/examples/apps/todo/fly.toml +++ /dev/null @@ -1,40 +0,0 @@ -app = "flet-todo" - -kill_signal = "SIGINT" -kill_timeout = 5 -processes = [] - -[env] - FLET_SERVER_PORT = "8080" - FLET_FORCE_WEB_SERVER = "true" - -[experimental] - allowed_public_ports = [] - auto_rollback = true - -[[services]] - http_checks = [] - internal_port = 8080 - processes = ["app"] - protocol = "tcp" - script_checks = [] - - [services.concurrency] - hard_limit = 25 - soft_limit = 20 - type = "connections" - - [[services.ports]] - force_https = true - handlers = ["http"] - port = 80 - - [[services.ports]] - handlers = ["tls", "http"] - port = 443 - - [[services.tcp_checks]] - grace_period = "1s" - interval = "15s" - restart_limit = 0 - timeout = "2s" diff --git a/sdk/python/examples/apps/todo/requirements.txt b/sdk/python/examples/apps/todo/requirements.txt deleted file mode 100644 index 9f5592458b..0000000000 --- a/sdk/python/examples/apps/todo/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet>=0.25.1 diff --git a/sdk/python/examples/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh index 4b4febc979..6450e1eac6 100644 --- a/sdk/python/examples/publish-gallery.sh +++ b/sdk/python/examples/publish-gallery.sh @@ -1,6 +1,6 @@ flet --version DIST_PATH=$PWD/dist -flet publish apps/todo/todo.py --distpath $DIST_PATH/todo --base-url todo --app-name "Flet To-Do" --app-description "A classic To-Do app inspired by TodoMVC project." +flet publish apps/todo/basic/main.py --distpath $DIST_PATH/todo --base-url todo --app-name "Flet To-Do" --app-description "A classic To-Do app inspired by TodoMVC project." flet publish apps/icons_browser/main.py --distpath $DIST_PATH/icons_browser --base-url icons_browser --app-name "Flet Icons Browser" --app-description "Quickly search through icons collection to use in your app." flet publish tutorials/calculator/calc.py --distpath $DIST_PATH/calculator --base-url calculator --app-name "Calculator" --app-description "A simple calculator app written in Flet." flet publish tutorials/solitaire_declarative/solitaire-final/main.py --distpath $DIST_PATH/solitaire --base-url solitaire --assets assets --app-name "Solitaire" --app-description "Learn how to handle gestures and position controls on a page." diff --git a/sdk/python/packages/flet/docs/tutorials/todo.md b/sdk/python/packages/flet/docs/tutorials/todo.md index 8b7b9b1815..7a588820ec 100644 --- a/sdk/python/packages/flet/docs/tutorials/todo.md +++ b/sdk/python/packages/flet/docs/tutorials/todo.md @@ -6,7 +6,7 @@ examples: ../../examples/tutorials/todo In this tutorial we will show you, step-by-step, how to create a To-Do app in Python using Flet framework and then publish it as a desktop, mobile or web app. The app is a single-file console program of just -[163 lines (formatted!) of Python code](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/todo/todo.py), +[163 lines (formatted!) of Python code](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/todo/basic/main.py), yet it is a multi-platform application with rich, responsive UI: {{ image("../examples/tutorials/todo/media/complete-demo-web.gif", width="80%") }} From 7938de5303fd25508be104cb4f0993cddd3c7e1a Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 16:04:09 -0700 Subject: [PATCH 95/96] Reorganize timer app examples --- .../apps/{timer/declarative => declarative/timer}/main.py | 0 .../declarative => declarative/timer}/pyproject.toml | 6 +++--- .../examples/apps/timer/{imperative => basic}/main.py | 0 .../apps/timer/{imperative => basic}/pyproject.toml | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) rename sdk/python/examples/apps/{timer/declarative => declarative/timer}/main.py (100%) rename sdk/python/examples/apps/{timer/declarative => declarative/timer}/pyproject.toml (82%) rename sdk/python/examples/apps/timer/{imperative => basic}/main.py (100%) rename sdk/python/examples/apps/timer/{imperative => basic}/pyproject.toml (71%) diff --git a/sdk/python/examples/apps/timer/declarative/main.py b/sdk/python/examples/apps/declarative/timer/main.py similarity index 100% rename from sdk/python/examples/apps/timer/declarative/main.py rename to sdk/python/examples/apps/declarative/timer/main.py diff --git a/sdk/python/examples/apps/timer/declarative/pyproject.toml b/sdk/python/examples/apps/declarative/timer/pyproject.toml similarity index 82% rename from sdk/python/examples/apps/timer/declarative/pyproject.toml rename to sdk/python/examples/apps/declarative/timer/pyproject.toml index b8b3fc5f63..cdba54d9ad 100644 --- a/sdk/python/examples/apps/timer/declarative/pyproject.toml +++ b/sdk/python/examples/apps/declarative/timer/pyproject.toml @@ -1,9 +1,9 @@ [project] -name = "apps-timer-declarative" +name = "apps-declarative-timer" version = "1.0.0" description = "Declarative stopwatch example driven by observable timer state and async ticking." requires-python = ">=3.10" -keywords = ["apps", "timer", "declarative", "stopwatch", "async"] +keywords = ["apps", "declarative", "timer", "stopwatch", "async"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] dependencies = ["flet"] @@ -11,7 +11,7 @@ dependencies = ["flet"] dev = ["flet-cli", "flet-desktop", "flet-web"] [tool.flet.gallery] -categories = ["Apps/Time"] +categories = ["Apps/Declarative", "Apps/Time"] [tool.flet.metadata] title = "Declarative timer" diff --git a/sdk/python/examples/apps/timer/imperative/main.py b/sdk/python/examples/apps/timer/basic/main.py similarity index 100% rename from sdk/python/examples/apps/timer/imperative/main.py rename to sdk/python/examples/apps/timer/basic/main.py diff --git a/sdk/python/examples/apps/timer/imperative/pyproject.toml b/sdk/python/examples/apps/timer/basic/pyproject.toml similarity index 71% rename from sdk/python/examples/apps/timer/imperative/pyproject.toml rename to sdk/python/examples/apps/timer/basic/pyproject.toml index b2f0f1cd1e..5bbd2875d6 100644 --- a/sdk/python/examples/apps/timer/imperative/pyproject.toml +++ b/sdk/python/examples/apps/timer/basic/pyproject.toml @@ -1,9 +1,9 @@ [project] -name = "apps-timer-imperative" +name = "apps-timer-basic" version = "1.0.0" -description = "Imperative stopwatch example with start, pause, resume, and stop controls." +description = "Stopwatch example with start, pause, resume, and stop controls." requires-python = ">=3.10" -keywords = ["apps", "timer", "imperative", "stopwatch", "async"] +keywords = ["apps", "timer", "stopwatch", "async"] authors = [{ name = "Flet team", email = "hello@flet.dev" }] dependencies = ["flet"] @@ -14,7 +14,7 @@ dev = ["flet-cli", "flet-desktop", "flet-web"] categories = ["Apps/Time"] [tool.flet.metadata] -title = "Imperative timer" +title = "Basic timer" controls = ["SafeArea", "Column", "Row", "Text", "FilledButton", "TextButton"] layout_pattern = "center-stage" complexity = "basic" From 200aa0c43d975d4d008f433cb6597d2bcd385141 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Sun, 29 Mar 2026 16:17:13 -0700 Subject: [PATCH 96/96] Normalize trolli and mind queue examples --- .../trolli}/assets/Pacifico-Regular.ttf | Bin .../trolli}/components/__init__.py | 1 - .../trolli}/components/app_bar.py | 3 +- .../trolli}/components/board.py | 3 +- .../trolli}/components/board_list.py | 3 +- .../trolli}/components/boards.py | 3 +- .../trolli}/components/card.py | 4 +- .../trolli}/components/dialogs.py | 8 +- .../trolli}/components/sidebar.py | 9 +- .../src => declarative/trolli}/main.py | 97 +++--- .../src => declarative/trolli}/models.py | 2 +- .../apps/declarative/trolli/pyproject.toml | 26 ++ .../apps/trolli-declarative/.gitignore | 129 -------- .../apps/trolli-declarative/pyproject.toml | 28 -- sdk/python/examples/apps/trolli/.gitignore | 129 -------- sdk/python/examples/apps/trolli/DockerFile | 9 - sdk/python/examples/apps/trolli/README.md | 5 - .../apps/trolli/assets/Pacifico-Regular.ttf | Bin 315408 -> 0 bytes sdk/python/examples/apps/trolli/fly.toml | 40 --- .../examples/apps/trolli/pyproject.toml | 28 -- .../examples/apps/trolli/requirements.txt | 2 - .../examples/apps/trolli/src/app_layout.py | 177 ----------- sdk/python/examples/apps/trolli/src/board.py | 152 ---------- .../examples/apps/trolli/src/board_list.py | 276 ------------------ .../examples/apps/trolli/src/data_store.py | 66 ----- sdk/python/examples/apps/trolli/src/item.py | 80 ----- sdk/python/examples/apps/trolli/src/main.py | 189 ------------ .../examples/apps/trolli/src/memory_store.py | 68 ----- .../examples/apps/trolli/src/sidebar.py | 141 --------- sdk/python/examples/apps/trolli/src/user.py | 4 - .../examples/community/mind_queue/README.md | 2 +- .../community/mind_queue/assets/data.json | 64 ++++ .../examples/community/mind_queue/data.json | 137 --------- .../examples/community/mind_queue/main.py | 32 +- .../community/mind_queue/pyproject.toml | 26 ++ sdk/python/examples/publish-gallery.sh | 2 +- 36 files changed, 204 insertions(+), 1741 deletions(-) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/assets/Pacifico-Regular.ttf (100%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/components/__init__.py (99%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/components/app_bar.py (99%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/components/board.py (99%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/components/board_list.py (99%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/components/boards.py (99%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/components/card.py (100%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/components/dialogs.py (100%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/components/sidebar.py (97%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/main.py (67%) rename sdk/python/examples/apps/{trolli-declarative/src => declarative/trolli}/models.py (98%) create mode 100644 sdk/python/examples/apps/declarative/trolli/pyproject.toml delete mode 100644 sdk/python/examples/apps/trolli-declarative/.gitignore delete mode 100644 sdk/python/examples/apps/trolli-declarative/pyproject.toml delete mode 100644 sdk/python/examples/apps/trolli/.gitignore delete mode 100644 sdk/python/examples/apps/trolli/DockerFile delete mode 100644 sdk/python/examples/apps/trolli/README.md delete mode 100644 sdk/python/examples/apps/trolli/assets/Pacifico-Regular.ttf delete mode 100644 sdk/python/examples/apps/trolli/fly.toml delete mode 100644 sdk/python/examples/apps/trolli/pyproject.toml delete mode 100644 sdk/python/examples/apps/trolli/requirements.txt delete mode 100644 sdk/python/examples/apps/trolli/src/app_layout.py delete mode 100644 sdk/python/examples/apps/trolli/src/board.py delete mode 100644 sdk/python/examples/apps/trolli/src/board_list.py delete mode 100644 sdk/python/examples/apps/trolli/src/data_store.py delete mode 100644 sdk/python/examples/apps/trolli/src/item.py delete mode 100644 sdk/python/examples/apps/trolli/src/main.py delete mode 100644 sdk/python/examples/apps/trolli/src/memory_store.py delete mode 100644 sdk/python/examples/apps/trolli/src/sidebar.py delete mode 100644 sdk/python/examples/apps/trolli/src/user.py create mode 100644 sdk/python/examples/community/mind_queue/assets/data.json delete mode 100644 sdk/python/examples/community/mind_queue/data.json create mode 100644 sdk/python/examples/community/mind_queue/pyproject.toml diff --git a/sdk/python/examples/apps/trolli-declarative/src/assets/Pacifico-Regular.ttf b/sdk/python/examples/apps/declarative/trolli/assets/Pacifico-Regular.ttf similarity index 100% rename from sdk/python/examples/apps/trolli-declarative/src/assets/Pacifico-Regular.ttf rename to sdk/python/examples/apps/declarative/trolli/assets/Pacifico-Regular.ttf diff --git a/sdk/python/examples/apps/trolli-declarative/src/components/__init__.py b/sdk/python/examples/apps/declarative/trolli/components/__init__.py similarity index 99% rename from sdk/python/examples/apps/trolli-declarative/src/components/__init__.py rename to sdk/python/examples/apps/declarative/trolli/components/__init__.py index 2696d2187b..5ee7e0bd85 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/components/__init__.py +++ b/sdk/python/examples/apps/declarative/trolli/components/__init__.py @@ -9,4 +9,3 @@ "Sidebar", "TrolliAppBar", ] - diff --git a/sdk/python/examples/apps/trolli-declarative/src/components/app_bar.py b/sdk/python/examples/apps/declarative/trolli/components/app_bar.py similarity index 99% rename from sdk/python/examples/apps/trolli-declarative/src/components/app_bar.py rename to sdk/python/examples/apps/declarative/trolli/components/app_bar.py index 7a0f0cb0a7..d1ec9585d3 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/components/app_bar.py +++ b/sdk/python/examples/apps/declarative/trolli/components/app_bar.py @@ -1,8 +1,9 @@ from __future__ import annotations +from models import TrolliState + import flet as ft -from models import TrolliState from .dialogs import show_login_dialog, show_settings_dialog diff --git a/sdk/python/examples/apps/trolli-declarative/src/components/board.py b/sdk/python/examples/apps/declarative/trolli/components/board.py similarity index 99% rename from sdk/python/examples/apps/trolli-declarative/src/components/board.py rename to sdk/python/examples/apps/declarative/trolli/components/board.py index d99f8a25e4..8024ad5b1c 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/components/board.py +++ b/sdk/python/examples/apps/declarative/trolli/components/board.py @@ -1,8 +1,9 @@ from __future__ import annotations +from models import Board + import flet as ft -from models import Board from .board_list import BoardListView from .dialogs import show_new_list_dialog diff --git a/sdk/python/examples/apps/trolli-declarative/src/components/board_list.py b/sdk/python/examples/apps/declarative/trolli/components/board_list.py similarity index 99% rename from sdk/python/examples/apps/trolli-declarative/src/components/board_list.py rename to sdk/python/examples/apps/declarative/trolli/components/board_list.py index 1c00cb8950..0863c0a983 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/components/board_list.py +++ b/sdk/python/examples/apps/declarative/trolli/components/board_list.py @@ -1,8 +1,9 @@ # from __future__ import annotations +from models import BoardList + import flet as ft -from models import BoardList from .card import CardView diff --git a/sdk/python/examples/apps/trolli-declarative/src/components/boards.py b/sdk/python/examples/apps/declarative/trolli/components/boards.py similarity index 99% rename from sdk/python/examples/apps/trolli-declarative/src/components/boards.py rename to sdk/python/examples/apps/declarative/trolli/components/boards.py index cf1a3c5496..8229269b50 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/components/boards.py +++ b/sdk/python/examples/apps/declarative/trolli/components/boards.py @@ -1,8 +1,9 @@ import asyncio +from models import TrolliState + import flet as ft -from models import TrolliState from .dialogs import show_new_board_dialog diff --git a/sdk/python/examples/apps/trolli-declarative/src/components/card.py b/sdk/python/examples/apps/declarative/trolli/components/card.py similarity index 100% rename from sdk/python/examples/apps/trolli-declarative/src/components/card.py rename to sdk/python/examples/apps/declarative/trolli/components/card.py index f7eee11a14..77811cbdce 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/components/card.py +++ b/sdk/python/examples/apps/declarative/trolli/components/card.py @@ -1,7 +1,7 @@ -import flet as ft - from models import Card +import flet as ft + @ft.component def CardView(card: Card): diff --git a/sdk/python/examples/apps/trolli-declarative/src/components/dialogs.py b/sdk/python/examples/apps/declarative/trolli/components/dialogs.py similarity index 100% rename from sdk/python/examples/apps/trolli-declarative/src/components/dialogs.py rename to sdk/python/examples/apps/declarative/trolli/components/dialogs.py index 60c4f38880..9db842bb2c 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/components/dialogs.py +++ b/sdk/python/examples/apps/declarative/trolli/components/dialogs.py @@ -1,13 +1,13 @@ from __future__ import annotations -import asyncio -from typing import cast +import asyncio from dataclasses import dataclass - -import flet as ft +from typing import cast from models import Board, TrolliState +import flet as ft + @dataclass(frozen=True) class _ColorOption: diff --git a/sdk/python/examples/apps/trolli-declarative/src/components/sidebar.py b/sdk/python/examples/apps/declarative/trolli/components/sidebar.py similarity index 97% rename from sdk/python/examples/apps/trolli-declarative/src/components/sidebar.py rename to sdk/python/examples/apps/declarative/trolli/components/sidebar.py index 3145b6ff63..e6292d5e1a 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/components/sidebar.py +++ b/sdk/python/examples/apps/declarative/trolli/components/sidebar.py @@ -1,10 +1,11 @@ from __future__ import annotations -import asyncio -import flet as ft +import asyncio from models import TrolliState +import flet as ft + @ft.component def Sidebar(app: TrolliState): @@ -17,7 +18,9 @@ def Sidebar(app: TrolliState): top_index = ( 0 if app.active_screen == "boards" - else 1 if app.active_screen == "members" else None + else 1 + if app.active_screen == "members" + else None ) def top_nav_change(e: ft.Event[ft.NavigationRail]): diff --git a/sdk/python/examples/apps/trolli-declarative/src/main.py b/sdk/python/examples/apps/declarative/trolli/main.py similarity index 67% rename from sdk/python/examples/apps/trolli-declarative/src/main.py rename to sdk/python/examples/apps/declarative/trolli/main.py index 31e93aca0b..870b516b5e 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/main.py +++ b/sdk/python/examples/apps/declarative/trolli/main.py @@ -48,41 +48,36 @@ def parse_board_id_from_route(route: str) -> Optional[int]: return None def route_change(e: ft.RouteChangeEvent): - # Keep route as a single source of truth for navigation-related UI (e.g. sidebar selection). + # Keep route as the single source of truth for navigation-related UI. app.route = e.route - # deal with bad or incomplete routes first if e.route.startswith("/board/"): board_id = parse_board_id_from_route(e.route) if board_id is None or app.get_board_by_id(board_id) is None: asyncio.create_task(ft.context.page.push_route("/boards")) - # ft.context.page.go("/boards") app.active_screen = "boards" app.current_board_id = None app.route = "/boards" return - match e.route: - # trigger re-render by changing active_screen - case "/" | "/boards": - app.active_screen = "boards" - app.current_board_id = None - case "/members": - app.active_screen = "members" - app.current_board_id = None - case "/settings": - app.active_screen = "settings" - app.current_board_id = None - case name if name.startswith("/board/"): - app.active_screen = "board" - app.current_board_id = board_id - case _: - asyncio.create_task(ft.context.page.push_route("/boards")) - # ft.context.page.go("/boards") - app.active_screen = "boards" - app.current_board_id = None - app.route = "/boards" - return + if e.route in ("/", "/boards"): + app.active_screen = "boards" + app.current_board_id = None + elif e.route == "/members": + app.active_screen = "members" + app.current_board_id = None + elif e.route == "/settings": + app.active_screen = "settings" + app.current_board_id = None + elif e.route.startswith("/board/"): + app.active_screen = "board" + app.current_board_id = board_id + else: + asyncio.create_task(ft.context.page.push_route("/boards")) + app.active_screen = "boards" + app.current_board_id = None + app.route = "/boards" + return ft.context.page.on_route_change = route_change @@ -103,30 +98,27 @@ def toggle_sidebar(_: ft.Event[ft.IconButton]): board_id = parse_board_id_from_route(app.route) board = app.get_board_by_id(board_id) if board_id is not None else None - content: ft.Control - match app.active_screen: - case "boards": - content = BoardsView(app) - case "members": - content = ft.Text("Members view placeholder", align=ft.Alignment.CENTER) - case "settings": - content = ft.Text("Settings view placeholder", align=ft.Alignment.CENTER) - case "board": - board = ( - app.get_board_by_id(app.current_board_id) - if app.current_board_id - else None - ) - content = BoardView(board) if board else BoardsView(app) - - return ft.Column( + if app.active_screen == "boards": + content: ft.Control = BoardsView(app) + elif app.active_screen == "members": + content = ft.Text("Members view placeholder", align=ft.Alignment.CENTER) + elif app.active_screen == "settings": + content = ft.Text("Settings view placeholder", align=ft.Alignment.CENTER) + else: + board = ( + app.get_board_by_id(app.current_board_id) if app.current_board_id else None + ) + content = BoardView(board) if board else BoardsView(app) + + return ft.SafeArea( expand=True, - spacing=0, - controls=[ - TrolliAppBar(app), - ft.SafeArea( - expand=True, - content=ft.Row( + content=ft.Column( + expand=True, + spacing=0, + controls=[ + TrolliAppBar(app), + ft.Row( + expand=True, vertical_alignment=ft.CrossAxisAlignment.START, controls=[ Sidebar(app), @@ -151,9 +143,14 @@ def toggle_sidebar(_: ft.Event[ft.IconButton]): ), ], ), - ), - ], + ], + ), ) -ft.run(lambda page: page.render(App)) +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main, route_url_strategy="hash") diff --git a/sdk/python/examples/apps/trolli-declarative/src/models.py b/sdk/python/examples/apps/declarative/trolli/models.py similarity index 98% rename from sdk/python/examples/apps/trolli-declarative/src/models.py rename to sdk/python/examples/apps/declarative/trolli/models.py index 4c478413f1..0dbc6e31de 100644 --- a/sdk/python/examples/apps/trolli-declarative/src/models.py +++ b/sdk/python/examples/apps/declarative/trolli/models.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Optional, Literal +from typing import Literal, Optional import flet as ft diff --git a/sdk/python/examples/apps/declarative/trolli/pyproject.toml b/sdk/python/examples/apps/declarative/trolli/pyproject.toml new file mode 100644 index 0000000000..100de87539 --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-trolli" +version = "1.0.0" +description = "Declarative Trello-style board app with draggable lists, cards, dialogs, and route-based navigation." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "kanban", "drag and drop", "routing", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Apps/Declarative", "Apps/Productivity"] + +[tool.flet.metadata] +title = "Trolli" +controls = ["SafeArea", "Column", "Row", "Stack", "AppBar", "NavigationRail", "Draggable", "DragTarget", "TextField", "AlertDialog"] +layout_pattern = "dashboard" +complexity = "advanced" +features = ["drag and drop", "routing", "dialogs", "async", "kanban board"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/trolli-declarative/.gitignore b/sdk/python/examples/apps/trolli-declarative/.gitignore deleted file mode 100644 index b6e47617de..0000000000 --- a/sdk/python/examples/apps/trolli-declarative/.gitignore +++ /dev/null @@ -1,129 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -.python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ diff --git a/sdk/python/examples/apps/trolli-declarative/pyproject.toml b/sdk/python/examples/apps/trolli-declarative/pyproject.toml deleted file mode 100644 index 515d227d91..0000000000 --- a/sdk/python/examples/apps/trolli-declarative/pyproject.toml +++ /dev/null @@ -1,28 +0,0 @@ -[project] -name = "trolli-declarative-codex" -version = "0.1.0" -description = "" -readme = "README.md" -requires-python = ">=3.13" -dependencies = [ - "flet==0.81.0" -] - - -[tool.flet] -# org name in reverse domain name notation, e.g. "com.mycompany". -# Combined with project.name to build bundle ID for iOS and Android apps -org = "com.mycompany" - -# project display name that is used as an app title on Android and iOS home screens, -# shown in window titles and about app dialogs on desktop. -product = "trolli-declarative-codex" - -# company name to display in about app dialogs -company = "Flet" - -# copyright text to display in about app dialogs -copyright = "Copyright (C) 2024 by Flet" - -[tool.flet.app] -path = "src" diff --git a/sdk/python/examples/apps/trolli/.gitignore b/sdk/python/examples/apps/trolli/.gitignore deleted file mode 100644 index b6e47617de..0000000000 --- a/sdk/python/examples/apps/trolli/.gitignore +++ /dev/null @@ -1,129 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -.python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ diff --git a/sdk/python/examples/apps/trolli/DockerFile b/sdk/python/examples/apps/trolli/DockerFile deleted file mode 100644 index 80fb9be08b..0000000000 --- a/sdk/python/examples/apps/trolli/DockerFile +++ /dev/null @@ -1,9 +0,0 @@ -FROM python:3-alpine - -COPY . . - -RUN pip install --no-cache-dir -r requirements.txt - -EXPOSE 8080 - -CMD ["python", "./src/main.py"] diff --git a/sdk/python/examples/apps/trolli/README.md b/sdk/python/examples/apps/trolli/README.md deleted file mode 100644 index 57bba596fe..0000000000 --- a/sdk/python/examples/apps/trolli/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# flet-trello-clone -A clone of trello built with Flet. - - -Live demo [here](https://flet-trolli.fly.dev/) diff --git a/sdk/python/examples/apps/trolli/assets/Pacifico-Regular.ttf b/sdk/python/examples/apps/trolli/assets/Pacifico-Regular.ttf deleted file mode 100644 index e7def95d3f44c82086f6e74d93fc0aadac7c454a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 315408 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