diff --git a/sdk/python/examples/apps/icons_browser/main.py b/sdk/python/examples/apps/icons_browser/main.py index bc5fc95a0d..577cc99100 100644 --- a/sdk/python/examples/apps/icons_browser/main.py +++ b/sdk/python/examples/apps/icons_browser/main.py @@ -1,32 +1,16 @@ -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): - def __init__(self, expand=False, height=500): +class IconBrowser(ft.Container): + def __init__(self, icon_set, expand=False, height=500): super().__init__() + self.icon_set = icon_set if expand: self.expand = expand else: @@ -39,26 +23,30 @@ 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(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) - 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=search_icon, on_click=search_click)] ) - search_results = GridView( + search_results = ft.GridView( expand=1, runs_count=10, max_extent=150, @@ -66,64 +54,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.{icon.__class__.__name__}.{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 +126,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 +144,33 @@ 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)) + 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), + ], + ), + ], + ), + ) + ) -flet.app(target=main) +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..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.27.0 +flet>=0.80.0 +flet-web>=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/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/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh index 2c02f5a6b1..5582d4742a 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_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." +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." diff --git a/sdk/python/examples/pyproject.toml b/sdk/python/examples/pyproject.toml index 9d821b4a5c..656b859cd6 100644 --- a/sdk/python/examples/pyproject.toml +++ b/sdk/python/examples/pyproject.toml @@ -6,18 +6,34 @@ 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", "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.*", +] 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 93% rename from sdk/python/examples/tutorials/solitaire_declarative/solitare-final/main.py rename to sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py index 64a193105d..e69c6a480c 100644 --- a/sdk/python/examples/tutorials/solitaire_declarative/solitare-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, ), 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"\",