From 657e8199f05d20f3b9fae504f9f0be5cb6985697 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 30 Dec 2025 12:48:17 -0800 Subject: [PATCH 1/7] Refactor icons browser to use async and ft namespace Replaces direct Flet imports with 'import flet as ft' and updates all references accordingly. Refactors event handlers to use async functions, updates UI control usage to the ft namespace, and improves clipboard and snackbar handling. Increases batch size for icon display and adds UI update delays for better responsiveness. --- .../examples/apps/icons_browser/main.py | 111 ++++++++---------- 1 file changed, 50 insertions(+), 61 deletions(-) diff --git a/sdk/python/examples/apps/icons_browser/main.py b/sdk/python/examples/apps/icons_browser/main.py index bc5fc95a0d..9cebadb003 100644 --- a/sdk/python/examples/apps/icons_browser/main.py +++ b/sdk/python/examples/apps/icons_browser/main.py @@ -1,30 +1,13 @@ -import os +import asyncio from itertools import islice -import flet -from flet import ( - Colors, - Column, - Container, - GridView, - Icon, - IconButton, - Icons, - Page, - Row, - SnackBar, - Text, - TextButton, - TextField, - alignment, -) +import flet as ft # logging.basicConfig(level=logging.INFO) +ft.context.disable_auto_update() -os.environ["FLET_WS_MAX_MESSAGE_SIZE"] = "8000000" - -class IconBrowser(Container): +class IconBrowser(ft.Container): def __init__(self, expand=False, height=500): super().__init__() if expand: @@ -39,26 +22,24 @@ def batches(iterable, batch_size): yield batch # fetch all icon constants from icons.py module - icons_list = [] - list_started = False - for icon in Icons: - icons_list.append(icon.name) + icons_list = list(ft.Icons) + + async def search_click(): + await display_icons(search_txt.value) - search_txt = TextField( + search_txt = ft.TextField( expand=1, - hint_text="Enter keyword and press search button. To view all icons enter *", + hint_text="Enter keyword and press search button. " + "To view all icons enter *", autofocus=True, - on_submit=lambda e: display_icons(e.control.value), + on_submit=search_click, ) - def search_click(e): - display_icons(search_txt.value) - - search_query = Row( - [search_txt, IconButton(icon=Icons.SEARCH, on_click=search_click)] + search_query = ft.Row( + [search_txt, ft.IconButton(icon=ft.Icons.SEARCH, on_click=search_click)] ) - search_results = GridView( + search_results = ft.GridView( expand=1, runs_count=10, max_extent=150, @@ -66,64 +47,70 @@ def search_click(e): run_spacing=5, child_aspect_ratio=1, ) - status_bar = Text() + status_bar = ft.Text() - def copy_to_clipboard(e): + async def copy_to_clipboard(e): icon_key = e.control.data print("Copy to clipboard:", icon_key) - self.page.set_clipboard(e.control.data) - self.page.open(SnackBar(Text(f"Copied {icon_key}"), open=True)) + await ft.Clipboard().set(icon_key) + self.page.show_dialog(ft.SnackBar(ft.Text(f"Copied {icon_key}"))) def search_icons(search_term: str): # switch variable to allow empty search, which shows all icons all_icons = 0 - for icon_name in icons_list: + for icon in icons_list: + icon_name = icon.name if all_icons == 1 or search_term != "": # match search to query if search_term != "" and search_term in icon_name: all_icons = 0 - yield icon_name + yield icon # turn on switch, empty search, and yield to not skip 1st icon elif search_term == "*": all_icons = 1 search_term = "" - yield icon_name + yield icon # all_icons is 1, which allows for empty search, which shows all elif search_term == "" and all_icons == 1: - yield icon_name + yield icon else: all_icons = 0 - def display_icons(search_term: str): + async def display_icons(search_term: str): # clean search results search_query.disabled = True self.update() - search_results.clean() + search_results.controls.clear() + search_results.update() + + print("Searching for icons with term:", search_term) - for batch in batches(search_icons(search_term.upper()), 200): - for icon_name in batch: - icon_key = f"Icons.{icon_name.upper()}" + for batch in batches(search_icons(search_term.upper()), 500): + for icon in batch: + icon_name = icon.name + icon_key = f"ft.Icons.{icon_name}" + # print("Found icon:", icon_key) search_results.controls.append( - TextButton( - content=Container( - content=Column( + ft.TextButton( + content=ft.Container( + content=ft.Column( [ - Icon(name=icon_name, size=30), - Text( + ft.Icon(icon=icon, size=30), + ft.Text( value=f"{icon_name}", size=12, width=100, no_wrap=True, - text_align="center", - color=Colors.ON_SURFACE_VARIANT, + text_align=ft.TextAlign.CENTER, + color=ft.Colors.ON_SURFACE_VARIANT, ), ], spacing=5, - alignment="center", - horizontal_alignment="center", + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, ), - alignment=alignment.center, + alignment=ft.Alignment.CENTER, ), tooltip=f"{icon_key}\nClick to copy to a clipboard", on_click=copy_to_clipboard, @@ -132,13 +119,15 @@ def display_icons(search_term: str): ) status_bar.value = f"Icons found: {len(search_results.controls)}" self.update() + print(f"Displayed {len(search_results.controls)} icons so far...") + await asyncio.sleep(0.1) # allow UI to update if len(search_results.controls) == 0: - self.page.open(SnackBar(Text("No icons found"), open=True)) + self.page.show_dialog(ft.SnackBar(ft.Text("No icons found"))) search_query.disabled = False self.update() - self.content = Column( + self.content = ft.Column( [ search_query, search_results, @@ -148,9 +137,9 @@ def display_icons(search_term: str): ) -def main(page: Page): +def main(page: ft.Page): page.title = "Flet icons browser" page.add(IconBrowser(expand=True)) -flet.app(target=main) +ft.run(main) From 01d9cd2896ab53f250cd85d955483673b6952557 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 30 Dec 2025 13:12:00 -0800 Subject: [PATCH 2/7] Refactor icons browser and remove unused apps Updated icons_browser to support both Material and Cupertino icons in a tabbed interface. Removed separate icons_cupertino_browser and layouts/footer apps. Updated requirements and dependencies to use latest flet versions and simplified pyproject.toml. --- .../examples/apps/icons_browser/main.py | 41 ++++- .../apps/icons_browser/requirements.txt | 2 +- .../apps/icons_cupertino_browser/main.py | 164 ------------------ .../icons_cupertino_browser/requirements.txt | 1 - sdk/python/examples/apps/layouts/footer.py | 20 --- sdk/python/examples/pyproject.toml | 7 +- 6 files changed, 39 insertions(+), 196 deletions(-) delete mode 100644 sdk/python/examples/apps/icons_cupertino_browser/main.py delete mode 100644 sdk/python/examples/apps/icons_cupertino_browser/requirements.txt delete mode 100644 sdk/python/examples/apps/layouts/footer.py diff --git a/sdk/python/examples/apps/icons_browser/main.py b/sdk/python/examples/apps/icons_browser/main.py index 9cebadb003..577cc99100 100644 --- a/sdk/python/examples/apps/icons_browser/main.py +++ b/sdk/python/examples/apps/icons_browser/main.py @@ -8,8 +8,9 @@ class IconBrowser(ft.Container): - def __init__(self, expand=False, height=500): + def __init__(self, icon_set, expand=False, height=500): super().__init__() + self.icon_set = icon_set if expand: self.expand = expand else: @@ -22,7 +23,13 @@ def batches(iterable, batch_size): yield batch # fetch all icon constants from icons.py module - icons_list = list(ft.Icons) + icons_list = list(self.icon_set) + + search_icon = ( + self.icon_set.SEARCH + if hasattr(self.icon_set, "SEARCH") + else ft.Icons.SEARCH + ) async def search_click(): await display_icons(search_txt.value) @@ -36,7 +43,7 @@ async def search_click(): ) search_query = ft.Row( - [search_txt, ft.IconButton(icon=ft.Icons.SEARCH, on_click=search_click)] + [search_txt, ft.IconButton(icon=search_icon, on_click=search_click)] ) search_results = ft.GridView( @@ -89,7 +96,7 @@ async def display_icons(search_term: str): for batch in batches(search_icons(search_term.upper()), 500): for icon in batch: icon_name = icon.name - icon_key = f"ft.Icons.{icon_name}" + icon_key = f"ft.{icon.__class__.__name__}.{icon_name}" # print("Found icon:", icon_key) search_results.controls.append( ft.TextButton( @@ -139,7 +146,31 @@ async def display_icons(search_term: str): def main(page: ft.Page): page.title = "Flet icons browser" - page.add(IconBrowser(expand=True)) + page.add( + ft.Tabs( + selected_index=0, + length=2, + 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) diff --git a/sdk/python/examples/apps/icons_browser/requirements.txt b/sdk/python/examples/apps/icons_browser/requirements.txt index 6b0a95074b..3a0e96024e 100644 --- a/sdk/python/examples/apps/icons_browser/requirements.txt +++ b/sdk/python/examples/apps/icons_browser/requirements.txt @@ -1 +1 @@ -flet>=0.27.0 +flet>=0.80.0 diff --git a/sdk/python/examples/apps/icons_cupertino_browser/main.py b/sdk/python/examples/apps/icons_cupertino_browser/main.py deleted file mode 100644 index 757e0111a1..0000000000 --- a/sdk/python/examples/apps/icons_cupertino_browser/main.py +++ /dev/null @@ -1,164 +0,0 @@ -import os -from itertools import islice - -import flet -from flet import ( - Colors, - Column, - Container, - CupertinoIcons, - GridView, - Icon, - IconButton, - Page, - Row, - SnackBar, - Text, - TextButton, - TextField, - alignment, -) - -# logging.basicConfig(level=logging.INFO) - -os.environ["FLET_WS_MAX_MESSAGE_SIZE"] = "8000000" - - -class IconCupertinoBrowser(Container): - def __init__(self, expand=False, height=500): - super().__init__() - if expand: - self.expand = expand - else: - self.height = height - - def build(self): - def batches(iterable, batch_size): - iterator = iter(iterable) - while batch := list(islice(iterator, batch_size)): - yield batch - - # fetch all icon constants from icons.py module - icons_list = [] - for icon in CupertinoIcons: - icons_list.append(icon.name) - - search_txt = TextField( - expand=1, - hint_text="Enter keyword and press search button. To view all icons enter *", - autofocus=True, - on_submit=lambda e: display_icons(e.control.value), - ) - - def search_click(e): - display_icons(search_txt.value) - - search_query = Row( - [search_txt, IconButton(icon=CupertinoIcons.SEARCH, on_click=search_click)] - ) - - search_results = GridView( - expand=1, - runs_count=10, - max_extent=150, - spacing=5, - run_spacing=5, - child_aspect_ratio=1, - ) - status_bar = Text() - - def copy_to_clipboard(e): - icon_key = e.control.data - print("Copy to clipboard:", icon_key) - self.page.set_clipboard(e.control.data) - self.page.open(SnackBar(Text(f"Copied {icon_key}"), open=True)) - - def search_icons(search_term: str): - # switch variable to allow empty search, which shows all icons - all_icons = 0 - for icon_name in icons_list: - if all_icons == 1 or search_term != "": - # match search to query - if search_term != "" and search_term in icon_name: - all_icons = 0 - yield icon_name - # turn on switch, empty search, and yield to not skip 1st icon - elif search_term == "*": - all_icons = 1 - search_term = "" - yield icon_name - # all_icons is 1, which allows for empty search, which shows all - elif search_term == "" and all_icons == 1: - yield icon_name - else: - all_icons = 0 - - def display_icons(search_term: str): - # clean search results - search_query.disabled = True - self.update() - - search_results.clean() - - for batch in batches(search_icons(search_term.upper()), 200): - for icon_name in batch: - # HOT GLUE - primitive text in replace to display & copy correctly. - icon_key = f"CupertinoIcons.{icon_name.upper()}".replace( - "cupertino_".upper(), "" - ) - search_results.controls.append( - TextButton( - content=Container( - content=Column( - [ - Icon( - name=f"cupertino_{icon_name.lower()}", - size=30, - ), - Text( - # HOT GLUE - primitive text in replace to display & copy correctly. - value=f"{icon_name}".replace( - "cupertino_", "" - ), - size=12, - width=100, - no_wrap=True, - text_align="center", - color=Colors.ON_SURFACE_VARIANT, - ), - ], - spacing=5, - alignment="center", - horizontal_alignment="center", - ), - alignment=alignment.center, - ), - tooltip=f"{icon_key}\nClick to copy to a clipboard", - on_click=copy_to_clipboard, - data=icon_key, - ) - ) - status_bar.value = f"Icons found: {len(search_results.controls)}" - self.update() - - if len(search_results.controls) == 0: - self.page.open(SnackBar(Text("No icons found"), open=True)) - search_query.disabled = False - self.update() - - self.content = Column( - [ - search_query, - search_results, - status_bar, - ], - expand=True, - ) - - -def main(page: Page): - page.title = "Flet cupertino icons browser" - page.add(IconCupertinoBrowser(expand=True)) - - -flet.app(target=main) diff --git a/sdk/python/examples/apps/icons_cupertino_browser/requirements.txt b/sdk/python/examples/apps/icons_cupertino_browser/requirements.txt deleted file mode 100644 index eb1956a960..0000000000 --- a/sdk/python/examples/apps/icons_cupertino_browser/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet>=0.26.0 diff --git a/sdk/python/examples/apps/layouts/footer.py b/sdk/python/examples/apps/layouts/footer.py deleted file mode 100644 index c3d0ac7890..0000000000 --- a/sdk/python/examples/apps/layouts/footer.py +++ /dev/null @@ -1,20 +0,0 @@ -import flet -from flet import Column, Container, Page, Row, Text - - -def main(page: Page): - main_content = Column(scroll="auto") - - for i in range(100): - main_content.controls.append(Text(f"Line {i}")) - - page.padding = 0 - page.spacing = 0 - page.horizontal_alignment = "stretch" - page.add( - Container(main_content, padding=10, expand=True), - Row([Container(Text("Footer"), bgcolor="yellow", padding=5, expand=True)]), - ) - - -flet.app(target=main, port=8550, view=flet.AppView.WEB_BROWSER) diff --git a/sdk/python/examples/pyproject.toml b/sdk/python/examples/pyproject.toml index 9d821b4a5c..3aafceda2e 100644 --- a/sdk/python/examples/pyproject.toml +++ b/sdk/python/examples/pyproject.toml @@ -6,16 +6,13 @@ license = "Apache-2.0" readme = "README.md" requires-python = ">=3.10,<3.15" dependencies = [ - "flet>=0.70.0.dev0", - "flet-desktop>=0.70.0.dev0", - "flet-web>=0.70.0.dev0", - "flet-cli>=0.70.0.dev0", + "flet", "flet-contrib", ] [dependency-groups] dev = [ - "black>=23.3.0,<24.0.0", + "flet[all]", "matplotlib", "mplfinance", "pandas", From c6b50b77936417d3e5dba9792a7fd87facfff532 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 30 Dec 2025 13:18:43 -0800 Subject: [PATCH 3/7] Add build system and package discovery to pyproject.toml Configured the build system with setuptools and wheel, and specified package discovery rules for the examples directory. This enables proper packaging and building of the Python example modules. --- sdk/python/examples/pyproject.toml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sdk/python/examples/pyproject.toml b/sdk/python/examples/pyproject.toml index 3aafceda2e..656b859cd6 100644 --- a/sdk/python/examples/pyproject.toml +++ b/sdk/python/examples/pyproject.toml @@ -18,3 +18,22 @@ dev = [ "pandas", "plotly" ] + +[build-system] +requires = ["setuptools>=68", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["."] +include = [ + "apps", + "apps.*", + "controls", + "controls.*", + "cookbook", + "cookbook.*", + "services", + "services.*", + "tutorials", + "tutorials.*", +] From 6e91d9d0aa1ff01ff7b8660eccb7cbfbb2dbbb10 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 30 Dec 2025 13:21:08 -0800 Subject: [PATCH 4/7] Update publish-gallery.sh paths and dist directory Changed DIST_PATH from $PWD/python/dist to $PWD/dist and updated all app and tutorial paths to remove the 'python/' prefix. This streamlines the script to match the new directory structure. --- sdk/python/examples/publish-gallery.sh | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/sdk/python/examples/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh index 2c02f5a6b1..bb64f4ec45 100644 --- a/sdk/python/examples/publish-gallery.sh +++ b/sdk/python/examples/publish-gallery.sh @@ -1,14 +1,12 @@ -pip install flet flet --version -DIST_PATH=$PWD/python/dist -flet publish python/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 python/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 python/apps/icons_cupertino_browser/main.py --distpath $DIST_PATH/icons_cupertino_browser --base-url icons_cupertino_browser --app-name "Flet Cupertino Icons Browser" --app-description "Quickly search through icons collection to use in your app." -flet publish python/tutorials/calc/calc.py --distpath $DIST_PATH/calculator --base-url calculator --app-name "Calculator" --app-description "A simple calculator app written in Flet." -flet publish python/tutorials/solitaire/solitaire-final-part1/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 python/apps/trolli/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 python/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 python/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 python/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 python/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 python/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." +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/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/solitaire-final-part1/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/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/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 8dc399902fa33e3a15009f3f6c6f469b05aaa9e8 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 30 Dec 2025 14:52:56 -0800 Subject: [PATCH 5/7] Update Solitaire example to declarative version Switched the published Solitaire tutorial app to use the declarative version. Also renamed 'solitare-final' to 'solitaire-final' in the declarative tutorial assets and main.py for consistency. --- sdk/python/examples/publish-gallery.sh | 4 ++-- .../assets/images/10_clubs.svg | 0 .../assets/images/10_diamonds.svg | 0 .../assets/images/10_hearts.svg | 0 .../assets/images/10_spades.svg | 0 .../assets/images/2_clubs.svg | 0 .../assets/images/2_diamonds.svg | 0 .../assets/images/2_hearts.svg | 0 .../assets/images/2_spades.svg | 0 .../assets/images/3_clubs.svg | 0 .../assets/images/3_diamonds.svg | 0 .../assets/images/3_hearts.svg | 0 .../assets/images/3_spades.svg | 0 .../assets/images/4_clubs.svg | 0 .../assets/images/4_diamonds.svg | 0 .../assets/images/4_hearts.svg | 0 .../assets/images/4_spades.svg | 0 .../assets/images/5_clubs.svg | 0 .../assets/images/5_diamonds.svg | 0 .../assets/images/5_hearts.svg | 0 .../assets/images/5_spades.svg | 0 .../assets/images/6_clubs.svg | 0 .../assets/images/6_diamonds.svg | 0 .../assets/images/6_hearts.svg | 0 .../assets/images/6_spades.svg | 0 .../assets/images/7_clubs.svg | 0 .../assets/images/7_diamonds.svg | 0 .../assets/images/7_hearts.svg | 0 .../assets/images/7_spades.svg | 0 .../assets/images/8_clubs.svg | 0 .../assets/images/8_diamonds.svg | 0 .../assets/images/8_hearts.svg | 0 .../assets/images/8_spades.svg | 0 .../assets/images/9_clubs.svg | 0 .../assets/images/9_diamonds.svg | 0 .../assets/images/9_hearts.svg | 0 .../assets/images/9_spades.svg | 0 .../assets/images/Ace_clubs.svg | 0 .../assets/images/Ace_diamonds.svg | 0 .../assets/images/Ace_hearts.svg | 0 .../assets/images/Ace_spades.svg | 0 .../assets/images/Jack_clubs.svg | 0 .../assets/images/Jack_diamonds.svg | 0 .../assets/images/Jack_hearts.svg | 0 .../assets/images/Jack_spades.svg | 0 .../assets/images/King_clubs.svg | 0 .../assets/images/King_diamonds.svg | 0 .../assets/images/King_hearts.svg | 0 .../assets/images/King_spades.svg | 0 .../assets/images/Queen_clubs.svg | 0 .../assets/images/Queen_diamonds.svg | 0 .../assets/images/Queen_hearts.svg | 0 .../assets/images/Queen_spades.svg | 0 .../assets/images/card_back.png | Bin .../{solitare-final => solitaire-final}/main.py | 0 55 files changed, 2 insertions(+), 2 deletions(-) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/10_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/10_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/10_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/10_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/2_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/2_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/2_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/2_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/3_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/3_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/3_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/3_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/4_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/4_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/4_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/4_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/5_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/5_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/5_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/5_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/6_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/6_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/6_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/6_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/7_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/7_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/7_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/7_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/8_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/8_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/8_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/8_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/9_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/9_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/9_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/9_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Ace_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Ace_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Ace_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Ace_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Jack_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Jack_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Jack_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Jack_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/King_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/King_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/King_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/King_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Queen_clubs.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Queen_diamonds.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Queen_hearts.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/Queen_spades.svg (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/assets/images/card_back.png (100%) rename sdk/python/examples/tutorials/solitaire_declarative/{solitare-final => solitaire-final}/main.py (100%) diff --git a/sdk/python/examples/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh index bb64f4ec45..5582d4742a 100644 --- a/sdk/python/examples/publish-gallery.sh +++ b/sdk/python/examples/publish-gallery.sh @@ -3,8 +3,8 @@ 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/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/solitaire-final-part1/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/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 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/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/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." diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/10_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/10_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/10_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/10_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/10_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/10_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/10_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/10_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/2_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/2_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/2_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/2_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/2_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/2_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/2_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/2_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/3_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/3_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/3_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/3_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/3_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/3_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/3_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/3_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/4_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/4_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/4_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/4_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/4_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/4_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/4_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/4_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/5_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/5_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/5_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/5_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/5_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/5_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/5_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/5_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/6_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/6_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/6_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/6_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/6_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/6_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/6_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/6_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/7_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/7_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/7_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/7_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/7_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/7_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/7_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/7_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/8_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/8_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/8_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/8_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/8_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/8_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/8_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/8_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/9_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/9_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/9_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/9_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/9_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/9_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/9_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/9_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Ace_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Ace_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Ace_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Ace_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Ace_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Ace_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Ace_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Ace_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Jack_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Jack_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Jack_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Jack_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Jack_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Jack_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Jack_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Jack_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/King_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/King_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/King_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/King_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/King_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/King_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/King_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/King_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Queen_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_clubs.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Queen_clubs.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_clubs.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Queen_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_diamonds.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Queen_diamonds.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_diamonds.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Queen_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_hearts.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Queen_hearts.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_hearts.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Queen_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_spades.svg similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/Queen_spades.svg rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_spades.svg diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/card_back.png b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/card_back.png similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/assets/images/card_back.png rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/card_back.png diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitare-final/main.py b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py similarity index 100% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/main.py rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py From 994c45c491868b37e4c2bfe2db12c6a8573d1845 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 30 Dec 2025 14:53:13 -0800 Subject: [PATCH 6/7] Fix asset path handling and improve base URL patching Corrects the way asset directories are resolved in the publish command to use the script directory consistently. Enhances patch_index_html to handle base href and related config values more robustly, ensuring correct base URL and asset path injection in the generated index.html. --- .../flet-cli/src/flet_cli/commands/publish.py | 3 +-- .../flet-web/src/flet_web/patch_index.py | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py index dc3877150e..c51bcfea10 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py @@ -187,10 +187,9 @@ def handle(self, options: argparse.Namespace) -> None: # copy assets assets_dir = options.assets_dir if assets_dir and not Path(assets_dir).is_absolute(): - assets_dir = str(script_path.joinpath(assets_dir).resolve()) + assets_dir = str(script_dir / assets_dir) else: assets_dir = str(script_dir / assets_name) - if os.path.exists(assets_dir): copy_tree(assets_dir, str(dist_dir)) diff --git a/sdk/python/packages/flet-web/src/flet_web/patch_index.py b/sdk/python/packages/flet-web/src/flet_web/patch_index.py index 51fd682723..3727c8a79f 100644 --- a/sdk/python/packages/flet-web/src/flet_web/patch_index.py +++ b/sdk/python/packages/flet-web/src/flet_web/patch_index.py @@ -22,6 +22,16 @@ def patch_index_html( with open(index_path, encoding="utf-8") as f: index = f.read() + base_url = "/" + if base_href: + base_url = base_href.strip("/").strip() + base_url = "/" if base_url == "" else f"/{base_url}/" + + index = index.replace( + '', + f'', + ) + app_config = [] if pyodide and pyodide_script_path: @@ -33,6 +43,8 @@ def patch_index_html( app_config.append(f"flet.noCdn={str(no_cdn).lower()};") app_config.append(f'flet.webRenderer="{web_renderer.value}";') app_config.append(f'flet.routeUrlStrategy="{route_url_strategy.value}";') + app_config.append(f'flet.entrypointBaseUrl="{base_url}";') + app_config.append(f'flet.assetBase="{base_url}";') if websocket_endpoint_path: app_config.append(f'flet.webSocketEndpoint="{websocket_endpoint_path}";') @@ -42,13 +54,6 @@ def patch_index_html( "".format("\n".join(app_config)), ) - if base_href: - base_url = base_href.strip("/").strip() - index = index.replace( - '', - ''.format("/" if base_url == "" else f"/{base_url}/"), - ) - if app_name: index = re.sub( r"\", From e016062d047071bfd28a73b765b719abb3bebe3d Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 31 Dec 2025 16:07:08 -0800 Subject: [PATCH 7/7] Update requirements and optimize Solitaire app Added flet-web to icons_browser requirements and relaxed flet version in todo app. Refactored Solitaire declarative tutorial to use memoized views and callbacks, added missing game.notify() calls, and updated CardView and SlotView to accept a key parameter for improved performance. --- .../apps/icons_browser/requirements.txt | 1 + .../examples/apps/todo/requirements.txt | 2 +- .../solitaire-final/main.py | 26 +++++++++++++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/sdk/python/examples/apps/icons_browser/requirements.txt b/sdk/python/examples/apps/icons_browser/requirements.txt index 3a0e96024e..af7029341d 100644 --- a/sdk/python/examples/apps/icons_browser/requirements.txt +++ b/sdk/python/examples/apps/icons_browser/requirements.txt @@ -1 +1,2 @@ flet>=0.80.0 +flet-web>=0.80.0 diff --git a/sdk/python/examples/apps/todo/requirements.txt b/sdk/python/examples/apps/todo/requirements.txt index 2f82bb6754..9f5592458b 100644 --- a/sdk/python/examples/apps/todo/requirements.txt +++ b/sdk/python/examples/apps/todo/requirements.txt @@ -1 +1 @@ -flet==0.25.1 +flet>=0.25.1 diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py index 64a193105d..e69c6a480c 100644 --- a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py @@ -244,7 +244,7 @@ def check_win(self): # ---------- View (pure) ---------- @ft.component -def CardView(card: Card, on_card_click) -> ft.Control: +def CardView(card: Card, on_card_click, key=None) -> ft.Control: return ft.Container( left=card.left, top=card.top, @@ -260,7 +260,7 @@ def CardView(card: Card, on_card_click) -> ft.Control: @ft.component -def SlotView(slot: Slot, on_slot_click) -> ft.Control: +def SlotView(slot: Slot, on_slot_click, key=None) -> ft.Control: return ft.Container( margin=5, left=slot.left, @@ -301,6 +301,7 @@ def on_pan_update(e: ft.DragUpdateEvent): for c in dragging: c.left = max(0, c.left + e.local_delta.x) c.top = max(0, c.top + e.local_delta.y) + game.notify() def on_pan_end(_: ft.DragEndEvent): if dragging is None or not dragging[0].face_up: @@ -316,8 +317,23 @@ def on_pan_end(_: ft.DragEndEvent): for i, c in enumerate(dragging): c.left, c.top = start_x, start_y + i * OFFSET_Y + game.notify() set_dragging(None) + def open_card_and_notify(card: Card): + game.open_card(card) + game.notify() + + def reset_deck_and_notify(slot: Slot): + game.reset_deck(slot) + game.notify() + + cb_reset_deck = ft.use_callback(reset_deck_and_notify, [game]) + cb_open_card = ft.use_callback(open_card_and_notify, [game]) + + MemoSlotView = ft.memo(SlotView) + MemoCardView = ft.memo(CardView) + board = ft.GestureDetector( on_pan_start=on_pan_start, on_pan_update=on_pan_update, @@ -326,10 +342,10 @@ def on_pan_end(_: ft.DragEndEvent): mouse_cursor=ft.MouseCursor.MOVE, content=ft.Stack( controls=[ - ft.Container(expand=True, bgcolor="#207F4C") + ft.Container(expand=True, bgcolor="#207F4C", key="bg") ] # to capture full area - + [SlotView(s, game.reset_deck) for s in game.slots] - + [CardView(c, game.open_card) for c in game.cards], + + [MemoSlotView(s, cb_reset_deck, key=s.id) for s in game.slots] + + [MemoCardView(c, cb_open_card, key=c.id) for c in game.cards], width=1000, height=500, ),