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"\",