From 9c479bf334743220d0542932a0147a4a215c189f Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 17 Nov 2025 08:55:48 -0800 Subject: [PATCH 01/18] Fix layout and doc formatting in canvas and bottomsheet Updated brush_on_image.py to remove invalid width and set expand on Stack for proper layout. Added a missing newline in bottomsheet.md for improved markdown formatting. --- sdk/python/examples/controls/canvas/brush_on_image.py | 4 ++-- sdk/python/packages/flet/docs/controls/bottomsheet.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sdk/python/examples/controls/canvas/brush_on_image.py b/sdk/python/examples/controls/canvas/brush_on_image.py index 0ffc3f80ff..cec24534d3 100644 --- a/sdk/python/examples/controls/canvas/brush_on_image.py +++ b/sdk/python/examples/controls/canvas/brush_on_image.py @@ -34,9 +34,9 @@ def handle_pan_update(e: ft.DragUpdateEvent): page.add( ft.Container( border_radius=5, - width=float("inf"), expand=True, content=ft.Stack( + expand=True, controls=[ ft.Image( src="https://picsum.photos/200/300", @@ -51,7 +51,7 @@ def handle_pan_update(e: ft.DragUpdateEvent): drag_interval=10, ), ), - ] + ], ), ) ) diff --git a/sdk/python/packages/flet/docs/controls/bottomsheet.md b/sdk/python/packages/flet/docs/controls/bottomsheet.md index 8792affaf5..53d4e5feb8 100644 --- a/sdk/python/packages/flet/docs/controls/bottomsheet.md +++ b/sdk/python/packages/flet/docs/controls/bottomsheet.md @@ -23,6 +23,7 @@ example_images: ../test-images/examples/material/golden/macos/bottom_sheet ```python --8<-- "{{ examples }}/fullscreen.py" ``` + {{ image(example_images + "/fullscreen.gif", width="60%") }} From a2ecbabed2392cba2ba07fc4a416b9d3f4df6172 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 17 Nov 2025 10:24:31 -0800 Subject: [PATCH 02/18] Update chart examples and dependencies Refactored chart and color examples for improved clarity and modern Python practices, including use of dataclasses and async clipboard handling. Enhanced custom scrollbar and infinite scrolling examples with more realistic content and fixed key usage. Updated documentation to require both 'plotly' and 'kaleido' for PlotlyChart. Added 'matplotlib', 'plotly', and 'kaleido' to dependencies in pyproject.toml. --- .../colors/themecolors/01_theme_colors.py | 16 ++++++---- .../controls/charts/line_chart/example_2.py | 5 ++- .../controls/charts/pie_chart/example_2.py | 5 ++- .../controls/column/custom_scrollbar.py | 32 ++++++++++++++++++- .../controls/column/infinite_scrolling.py | 23 ++++++------- .../src/flet_charts/plotly_chart.py | 5 +-- sdk/python/pyproject.toml | 5 ++- 7 files changed, 61 insertions(+), 30 deletions(-) diff --git a/sdk/python/examples/apps/controls-gallery/examples/colors/themecolors/01_theme_colors.py b/sdk/python/examples/apps/controls-gallery/examples/colors/themecolors/01_theme_colors.py index 445df9d4d4..8900788578 100644 --- a/sdk/python/examples/apps/controls-gallery/examples/colors/themecolors/01_theme_colors.py +++ b/sdk/python/examples/apps/controls-gallery/examples/colors/themecolors/01_theme_colors.py @@ -1,14 +1,16 @@ +from dataclasses import dataclass + import flet as ft name = "Theme colors" def example(): + @dataclass class Color: - def __init__(self, display_name, name, is_dark=False): - self.name = name - self.display_name = display_name - self.is_dark = is_dark + name: str + display_name: str + is_dark: bool = False theme_colors = [ Color("PRIMARY", "primary"), @@ -40,9 +42,9 @@ def __init__(self, display_name, name, is_dark=False): Color("SCRIM", "scrim", True), ] - def copy_to_clipboard(e): - e.control.page.set_clipboard(f"ft.Colors.{e.control.content.value}") - e.control.page.open( + async def copy_to_clipboard(e): + await e.control.page.clipboard.set(f"ft.Colors.{e.control.content.value}") + e.control.page.show_dialog( ft.SnackBar( ft.Text(f"Copied to clipboard: ft.Colors.{e.control.content.value}"), open=True, diff --git a/sdk/python/examples/controls/charts/line_chart/example_2.py b/sdk/python/examples/controls/charts/line_chart/example_2.py index d7663e70f2..be384be542 100644 --- a/sdk/python/examples/controls/charts/line_chart/example_2.py +++ b/sdk/python/examples/controls/charts/line_chart/example_2.py @@ -1,6 +1,5 @@ -import flet_charts as fch - import flet as ft +import flet_charts as fch class State: @@ -134,7 +133,7 @@ def toggle_data(e: ft.Event[ft.ElevatedButton]): state.toggled = not state.toggled chart.update() - page.add(ft.ElevatedButton("avg", on_click=toggle_data), chart) + page.add(ft.Button("avg", on_click=toggle_data), chart) ft.run(main) diff --git a/sdk/python/examples/controls/charts/pie_chart/example_2.py b/sdk/python/examples/controls/charts/pie_chart/example_2.py index 9a776f470b..1e48927ca7 100644 --- a/sdk/python/examples/controls/charts/pie_chart/example_2.py +++ b/sdk/python/examples/controls/charts/pie_chart/example_2.py @@ -1,6 +1,5 @@ -import flet_charts as fch - import flet as ft +import flet_charts as fch NORMAL_RADIUS = 50 HOVER_RADIUS = 60 @@ -11,7 +10,7 @@ size=22, color=ft.Colors.WHITE, weight=ft.FontWeight.BOLD, - shadow=ft.BoxShadow(blur_radius=2, color=ft.Colors.BLACK54), + shadow=ft.BoxShadow(blur_radius=2, color=ft.Colors.BLACK_54), ) diff --git a/sdk/python/examples/controls/column/custom_scrollbar.py b/sdk/python/examples/controls/column/custom_scrollbar.py index 23e54f886f..133cb072fb 100644 --- a/sdk/python/examples/controls/column/custom_scrollbar.py +++ b/sdk/python/examples/controls/column/custom_scrollbar.py @@ -22,7 +22,37 @@ def main(page: ft.Page): ) ) - # todo: finish example + fake_messages = [ + ft.Container( + ft.Text(f"Message {i}", size=16, weight=ft.FontWeight.W_500), + bgcolor=ft.Colors.with_opacity(0.15, ft.Colors.BLUE_200), + border_radius=8, + padding=10, + ) + for i in range(1, 31) + ] + + page.add( + ft.Row( + [ + ft.Container( + content=ft.Column( + controls=fake_messages, + spacing=10, + scroll=ft.ScrollMode.ALWAYS, + expand=True, + ), + width=320, + height=420, + bgcolor=ft.Colors.with_opacity(0.15, ft.Colors.AMBER_200), + padding=15, + border_radius=12, + ) + ], + alignment=ft.MainAxisAlignment.CENTER, + expand=True, + ) + ) ft.run(main) diff --git a/sdk/python/examples/controls/column/infinite_scrolling.py b/sdk/python/examples/controls/column/infinite_scrolling.py index c2bc1314d6..f41263c3f6 100644 --- a/sdk/python/examples/controls/column/infinite_scrolling.py +++ b/sdk/python/examples/controls/column/infinite_scrolling.py @@ -13,17 +13,14 @@ class State: def main(page: ft.Page): def on_scroll(e: ft.OnScrollEvent): - if e.pixels >= e.max_scroll_extent - 100: - if sem.acquire(blocking=False): - try: - for i in range(0, 10): - cl.controls.append( - ft.Text(f"Text line {s.i}", scroll_key=str(s.i)) - ) - s.i += 1 - cl.update() - finally: - sem.release() + if e.pixels >= e.max_scroll_extent - 100 and sem.acquire(blocking=False): + try: + for _i in range(0, 10): + cl.controls.append(ft.Text(f"Text line {s.i}", key=str(s.i))) + s.i += 1 + cl.update() + finally: + sem.release() cl = ft.Column( spacing=10, @@ -33,8 +30,8 @@ def on_scroll(e: ft.OnScrollEvent): scroll_interval=0, on_scroll=on_scroll, ) - for i in range(0, 50): - cl.controls.append(ft.Text(f"Text line {s.i}", scroll_key=str(s.i))) + for _i in range(0, 50): + cl.controls.append(ft.Text(f"Text line {s.i}", key=str(s.i))) s.i += 1 page.add(ft.Container(cl, border=ft.Border.all(1))) diff --git a/sdk/python/packages/flet-charts/src/flet_charts/plotly_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/plotly_chart.py index 5c739a9fd4..dc93f704d7 100644 --- a/sdk/python/packages/flet-charts/src/flet_charts/plotly_chart.py +++ b/sdk/python/packages/flet-charts/src/flet_charts/plotly_chart.py @@ -29,8 +29,9 @@ class PlotlyChart(ft.Container): Displays a [Plotly](https://plotly.com/python/) chart. Warning: - This control requires the [`plotly`](https://plotly.com/python/) Python - package to be installed. + This control requires the [`plotly`](https://plotly.com/python/) and + [`kaleido`](https://github.com/plotly/Kaleido) Python + packages to be installed. See this [installation guide](index.md#installation) for more information. """ diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 84e2d5dd29..67db396dee 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -22,7 +22,10 @@ dependencies = [ "flet-permission-handler", "flet-rive", "flet-video", - "flet-webview" + "flet-webview", + "matplotlib>=3.10.7", + "plotly>=6.4.0", + "kaleido>=1.2.0", ] [tool.uv.sources] From e204d9be7af80750317ffd29c21913203ec05d72 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 17 Nov 2025 13:13:53 -0800 Subject: [PATCH 03/18] Fix type and class usage in example scripts Updated scroll event handler to use generic OnScrollEvent type in column example. Replaced ft.border.all with ft.Border.all in nested container themes example for correct class usage. --- sdk/python/examples/controls/column/scroll_events.py | 2 +- sdk/python/examples/controls/container/nested_themes_2.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/python/examples/controls/column/scroll_events.py b/sdk/python/examples/controls/column/scroll_events.py index 4fc39936ff..e4d15bbeff 100644 --- a/sdk/python/examples/controls/column/scroll_events.py +++ b/sdk/python/examples/controls/column/scroll_events.py @@ -2,7 +2,7 @@ def main(page: ft.Page): - def handle_column_scroll(e: ft.OnScrollEvent[ft.Column]): + def handle_column_scroll(e: ft.OnScrollEvent): print(e) page.add( diff --git a/sdk/python/examples/controls/container/nested_themes_2.py b/sdk/python/examples/controls/container/nested_themes_2.py index ad3a54406e..6374649c59 100644 --- a/sdk/python/examples/controls/container/nested_themes_2.py +++ b/sdk/python/examples/controls/container/nested_themes_2.py @@ -52,7 +52,7 @@ def main(page: ft.Page): ft.Container( padding=20, bgcolor=ft.Colors.SURFACE_TINT, - border=ft.border.all(3, ft.Colors.OUTLINE), + border=ft.Border.all(3, ft.Colors.OUTLINE), theme_mode=ft.ThemeMode.LIGHT, theme=ft.Theme(), content=ft.Row( @@ -69,7 +69,7 @@ def main(page: ft.Page): ft.Container( padding=20, bgcolor=ft.Colors.SURFACE_TINT, - border=ft.border.all(3, ft.Colors.OUTLINE), + border=ft.Border.all(3, ft.Colors.OUTLINE), border_radius=10, theme_mode=ft.ThemeMode.SYSTEM, theme=ft.Theme(), From 53210f206723b34acb07353bacd8cc6838ba6242 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 17 Nov 2025 13:49:02 -0800 Subject: [PATCH 04/18] Update Cupertino control examples for API changes Replaced deprecated usages in CupertinoButton and CupertinoRadio examples to match updated Flet API. Refactored CupertinoTimerPicker example to simplify timer value handling and fix event data usage. --- .../controls/cupertino_button/basic.py | 2 +- .../examples/controls/cupertino_radio/basic.py | 2 +- .../controls/cupertino_timer_picker/basic.py | 18 +++++++----------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/sdk/python/examples/controls/cupertino_button/basic.py b/sdk/python/examples/controls/cupertino_button/basic.py index 550c8483af..106ce1747e 100644 --- a/sdk/python/examples/controls/cupertino_button/basic.py +++ b/sdk/python/examples/controls/cupertino_button/basic.py @@ -15,7 +15,7 @@ def main(page: ft.Page): ft.CupertinoButton( bgcolor=ft.Colors.PRIMARY, alignment=ft.Alignment.TOP_LEFT, - border_radius=ft.border_radius.all(15), + border_radius=ft.BorderRadius.all(15), opacity_on_click=0.5, on_click=lambda e: print("Filled CupertinoButton clicked!"), content=ft.Text("Filled CupertinoButton", color=ft.Colors.YELLOW), diff --git a/sdk/python/examples/controls/cupertino_radio/basic.py b/sdk/python/examples/controls/cupertino_radio/basic.py index b89df0f928..c7d7a3f359 100644 --- a/sdk/python/examples/controls/cupertino_radio/basic.py +++ b/sdk/python/examples/controls/cupertino_radio/basic.py @@ -30,7 +30,7 @@ def handle_button_click(e: ft.Event[ft.ElevatedButton]): ] ) ), - ft.ElevatedButton(content="Submit", on_click=handle_button_click), + ft.Button(content="Submit", on_click=handle_button_click), message := ft.Text(), ) diff --git a/sdk/python/examples/controls/cupertino_timer_picker/basic.py b/sdk/python/examples/controls/cupertino_timer_picker/basic.py index c9317361de..80d00ad254 100644 --- a/sdk/python/examples/controls/cupertino_timer_picker/basic.py +++ b/sdk/python/examples/controls/cupertino_timer_picker/basic.py @@ -6,13 +6,14 @@ def main(page: ft.Page): page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - timer_picker_value_ref = ft.Ref[ft.Text]() + timer_value_text = ft.Text( + value="00:01:10", + size=23, + color=ft.CupertinoColors.DESTRUCTIVE_RED, + ) def handle_timer_picker_change(e: ft.Event[ft.CupertinoTimerPicker]): - timer_picker_value_ref.current.value = time.strftime( - "%H:%M:%S", time.gmtime(e.data.in_seconds) - ) - # timer_picker_value_ref.current.value = f"{e.data.in_hours}:{(e.data.in_minutes % 60)}:{(e.data.in_seconds % 60) % 60}" + timer_value_text.value = time.strftime("%H:%M:%S", time.gmtime(e.data)) page.update() timer_picker = ft.CupertinoTimerPicker( @@ -29,12 +30,7 @@ def handle_timer_picker_change(e: ft.Event[ft.CupertinoTimerPicker]): controls=[ ft.Text("TimerPicker Value:", size=23), ft.CupertinoButton( - content=ft.Text( - ref=timer_picker_value_ref, - value="00:01:10", - size=23, - color=ft.CupertinoColors.DESTRUCTIVE_RED, - ), + content=timer_value_text, on_click=lambda e: page.show_dialog( ft.CupertinoBottomSheet( content=timer_picker, From 015722cc3ee6f04aa9fd76fdfd98c62629a2d158 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 17 Nov 2025 18:31:24 -0800 Subject: [PATCH 05/18] Fix DataTable event handling and sorting logic Corrected color constant names and border usage in DataTable examples. Refactored sorting logic in datatable2 example to properly sort data and update table state, and fixed initialization of sorted data and DataTable2 instance. --- .../controls/data_table/handling_events.py | 16 +++--- .../data_table/sortable_and_selectable.py | 4 +- .../examples/controls/datatable2/example_2.py | 49 +++++++++++++------ 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/sdk/python/examples/controls/data_table/handling_events.py b/sdk/python/examples/controls/data_table/handling_events.py index 8ab18599f8..9b51a8504a 100644 --- a/sdk/python/examples/controls/data_table/handling_events.py +++ b/sdk/python/examples/controls/data_table/handling_events.py @@ -3,22 +3,22 @@ def main(page: ft.Page): def handle_row_selection_change(e: ft.Event[ft.DataRow]): - match e.control.data: - case 1: + if e.control.data: + if e.control.data == 1: row1.selected = not row1.selected - case 2: + elif e.control.data == 2: row2.selected = not row2.selected - case 3: + elif e.control.data == 3: row3.selected = not row3.selected page.update() def handle_column_sort(e: ft.DataColumnSortEvent): - match e.control.data: - case 1: + if e.control.data: + if e.control.data == 1: print(f"{e.column_index}, {e.ascending}") # table.sort_column_index = 1 table.sort_ascending = e.ascending - case 2: + elif e.control.data == 2: print(f"{e.column_index}, {e.ascending}") # table.sort_column_index = 2 table.sort_ascending = e.ascending @@ -34,7 +34,7 @@ def handle_column_sort(e: ft.DataColumnSortEvent): horizontal_lines=ft.border.BorderSide(1, ft.Colors.GREEN_600), sort_column_index=0, sort_ascending=True, - heading_row_color=ft.Colors.BLACK12, + heading_row_color=ft.Colors.BLACK_12, heading_row_height=100, data_row_color={ft.ControlState.HOVERED: "0x30FF0000"}, show_checkbox_column=True, diff --git a/sdk/python/examples/controls/data_table/sortable_and_selectable.py b/sdk/python/examples/controls/data_table/sortable_and_selectable.py index ff958543d4..abd425cf91 100644 --- a/sdk/python/examples/controls/data_table/sortable_and_selectable.py +++ b/sdk/python/examples/controls/data_table/sortable_and_selectable.py @@ -6,13 +6,13 @@ def main(page: ft.Page): ft.DataTable( width=700, bgcolor=ft.Colors.YELLOW, - border=ft.border.all(2, ft.Colors.RED), + border=ft.Border.all(2, ft.Colors.RED), border_radius=10, vertical_lines=ft.border.BorderSide(3, ft.Colors.BLUE), horizontal_lines=ft.border.BorderSide(1, ft.Colors.GREEN), sort_column_index=0, sort_ascending=True, - heading_row_color=ft.Colors.BLACK12, + heading_row_color=ft.Colors.BLACK_12, heading_row_height=100, data_row_color={ft.ControlState.HOVERED: "0x30FF0000"}, show_checkbox_column=True, diff --git a/sdk/python/examples/controls/datatable2/example_2.py b/sdk/python/examples/controls/datatable2/example_2.py index 2eda6cd9d0..d929e034bf 100644 --- a/sdk/python/examples/controls/datatable2/example_2.py +++ b/sdk/python/examples/controls/datatable2/example_2.py @@ -1,19 +1,37 @@ -import flet_datatable2 as ftd from data import desserts import flet as ft +import flet_datatable2 as ftd def main(page: ft.Page): page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + sorted_desserts = list(desserts) + data_table: ftd.DataTable2 | None = None def handle_row_selection_change(e: ft.Event[ftd.DataRow2]): e.control.selected = not e.control.selected e.control.update() def sort_column(e: ft.DataColumnSortEvent): - print(f"Sorting column {e.column_index}, ascending={e.ascending}") + if data_table is None: + return + sorters = [ + lambda d: d.name.lower(), + lambda d: d.calories, + lambda d: d.fat, + lambda d: d.carbs, + lambda d: d.protein, + lambda d: d.sodium, + lambda d: d.calcium, + lambda d: d.iron, + ] + sorted_desserts.sort(key=sorters[e.column_index], reverse=not e.ascending) + data_table.rows = get_data_rows(sorted_desserts) + data_table.sort_column_index = e.column_index + data_table.sort_ascending = e.ascending + data_table.update() def get_data_columns(): data_columns = [ @@ -83,21 +101,20 @@ def get_data_rows(desserts): ) return data_rows - page.add( - ftd.DataTable2( - show_checkbox_column=True, - expand=True, - column_spacing=0, - heading_row_color=ft.Colors.SECONDARY_CONTAINER, - horizontal_margin=12, - sort_ascending=True, - bottom_margin=10, - min_width=600, - on_select_all=lambda e: print("All selected"), - columns=get_data_columns(), - rows=get_data_rows(desserts), - ), + data_table = ftd.DataTable2( + show_checkbox_column=True, + expand=True, + column_spacing=0, + heading_row_color=ft.Colors.SECONDARY_CONTAINER, + horizontal_margin=12, + sort_ascending=True, + bottom_margin=10, + min_width=600, + on_select_all=lambda e: print("All selected"), + columns=get_data_columns(), + rows=get_data_rows(sorted_desserts), ) + page.add(data_table) ft.run(main) From ff1d93feada0bc99e49b2c748bf074dac70fe4bd Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 17 Nov 2025 18:35:04 -0800 Subject: [PATCH 06/18] Refactor DatePicker instantiation in example Moves DatePicker creation outside the button click handler to reuse the same instance. This simplifies the code and avoids creating a new DatePicker object on each click. --- .../examples/controls/date_picker/basic.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sdk/python/examples/controls/date_picker/basic.py b/sdk/python/examples/controls/date_picker/basic.py index 91a40ac2ee..b888792b83 100644 --- a/sdk/python/examples/controls/date_picker/basic.py +++ b/sdk/python/examples/controls/date_picker/basic.py @@ -14,20 +14,18 @@ def handle_dismissal(e: ft.Event[ft.DialogControl]): today = datetime.datetime.now() + d = ft.DatePicker( + first_date=datetime.datetime(year=today.year - 1, month=1, day=1), + last_date=datetime.datetime(year=today.year + 1, month=today.month, day=20), + on_change=handle_change, + on_dismiss=handle_dismissal, + ) + page.add( ft.Button( content="Pick date", icon=ft.Icons.CALENDAR_MONTH, - on_click=lambda e: page.show_dialog( - ft.DatePicker( - first_date=datetime.datetime(year=today.year - 1, month=1, day=1), - last_date=datetime.datetime( - year=today.year + 1, month=today.month, day=20 - ), - on_change=handle_change, - on_dismiss=handle_dismissal, - ) - ), + on_click=lambda e: page.show_dialog(d), ) ) From 9be6a9547486abac70ec7233c664a43e982bdd3a Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Mon, 17 Nov 2025 18:36:42 -0800 Subject: [PATCH 07/18] Refactor DateRangePicker instantiation in example Moves DateRangePicker creation outside the button click handler to avoid redundant instantiation. The picker is now created once and reused when the button is clicked. --- .../controls/date_range_picker/basic.py | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/sdk/python/examples/controls/date_range_picker/basic.py b/sdk/python/examples/controls/date_range_picker/basic.py index 7eb5ffee74..bd59d6dfc6 100644 --- a/sdk/python/examples/controls/date_range_picker/basic.py +++ b/sdk/python/examples/controls/date_range_picker/basic.py @@ -19,22 +19,18 @@ def handle_dismissal(e: ft.Event[ft.DialogControl]): today = datetime.datetime.now() + drp = ft.DateRangePicker( + start_value=datetime.datetime(year=today.year, month=today.month, day=1), + end_value=datetime.datetime(year=today.year, month=today.month, day=15), + on_change=handle_change, + on_dismiss=handle_dismissal, + ) + page.add( ft.Button( content=ft.Text("Pick date"), icon=ft.Icons.PHONE, - on_click=lambda e: page.show_dialog( - ft.DateRangePicker( - start_value=datetime.datetime( - year=today.year, month=today.month, day=1 - ), - end_value=datetime.datetime( - year=today.year, month=today.month, day=15 - ), - on_change=handle_change, - on_dismiss=handle_dismissal, - ) - ), + on_click=lambda e: page.show_dialog(drp), ) ) From 09e90a3bece5ff75cab437eb4efc10f31da9e3a8 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 08:12:17 -0800 Subject: [PATCH 08/18] Remove unused drag-and-drop example files Deleted ordering.py and outer_inner.py from the drag_target_and_draggable examples to clean up deprecated or redundant code. Also fixed a color constant typo in drag_and_drop_containers.py. --- .../drag_and_drop_containers.py | 2 +- .../drag_target_and_draggable/ordering.py | 244 ------------------ .../drag_target_and_draggable/outer_inner.py | 122 --------- 3 files changed, 1 insertion(+), 367 deletions(-) delete mode 100644 sdk/python/examples/controls/drag_target_and_draggable/ordering.py delete mode 100644 sdk/python/examples/controls/drag_target_and_draggable/outer_inner.py diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers.py b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers.py index 7bc86902b5..677d2c21de 100644 --- a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers.py +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers.py @@ -4,7 +4,7 @@ def main(page: ft.Page): def handle_drag_will_accept(e: ft.DragWillAcceptEvent): e.control.content.border = ft.Border.all( - 2, ft.Colors.BLACK45 if e.accept else ft.Colors.RED + 2, ft.Colors.BLACK_45 if e.accept else ft.Colors.RED ) e.control.update() diff --git a/sdk/python/examples/controls/drag_target_and_draggable/ordering.py b/sdk/python/examples/controls/drag_target_and_draggable/ordering.py deleted file mode 100644 index 51cfbf6403..0000000000 --- a/sdk/python/examples/controls/drag_target_and_draggable/ordering.py +++ /dev/null @@ -1,244 +0,0 @@ -import flet as ft - - -class ItemList(ft.Draggable): - def __init__(self, page: ft.Page, list_row, list_name, color): - # self.page: ft.Page = page - self.list_row = list_row - self.list_name: str = list_name - self.list_color = color - self.items = ft.Column(tight=True, spacing=5) - self.end_indicator = ft.Container( - bgcolor=ft.Colors.BLACK26, - border_radius=ft.border_radius.all(30), - height=3, - width=200, - opacity=0.0, - ) - self.item_name = ft.TextField( - label="New Item Name", - width=200, - height=50, - bgcolor=ft.Colors.WHITE, - on_submit=self.handle_item_addition, - ) - self.target = ft.DragTarget( - group="items", - data=self, - on_accept=self.item_drag_accept, - on_will_accept=self.item_drag_will_accept, - on_leave=self.item_drag_leave, - content=ft.DragTarget( - group="lists", - data=self, - on_accept=self.handle_drag_accept, - on_will_accept=self.handle_drag_will_accept, - on_leave=self.handle_drag_leave, - content=ft.Container( - border=ft.Border.all(2, ft.Colors.BLACK12), - border_radius=ft.border_radius.all(15), - bgcolor=self.list_color, - padding=ft.Padding.all(20), - content=ft.Column( - spacing=4, - tight=True, - expand=True, - controls=[ - self.item_name, - ft.TextButton( - content="Add Item", - icon=ft.Icons.ADD, - on_click=self.handle_item_addition, - ), - self.items, - self.end_indicator, - ], - ), - ), - ), - ) - super().__init__(group="lists", content=self.target, data=self) - - def handle_item_addition(self, e): - self.add_item() - - def add_item( - self, - item: str = None, - chosen_control: ft.Draggable = None, - swap_control: ft.Draggable = None, - ): - controls_list = [x.controls[1] for x in self.items.controls] - to_index = ( - controls_list.index(swap_control) if swap_control in controls_list else None - ) - from_index = ( - controls_list.index(chosen_control) - if chosen_control in controls_list - else None - ) - control_to_add = ft.Column( - controls=[ - ft.Container( - bgcolor=ft.Colors.BLACK26, - border_radius=ft.border_radius.all(30), - height=3, - alignment=ft.Alignment.CENTER_RIGHT, - width=200, - opacity=0.0, - ) - ] - ) - - # rearrange (i.e. drag drop from same list) - if (from_index is not None) and (to_index is not None): - self.items.controls.insert(to_index, self.items.controls.pop(from_index)) - self.set_indicator_opacity(swap_control, 0.0) - - # insert (drag from other list to middle of this list) - elif to_index is not None: - new_item = Item(self, item) - control_to_add.controls.append(new_item) - self.items.controls.insert(to_index, control_to_add) - - # add new (drag from other list to end of this list, or use add item button) - else: - new_item = Item(self, item) if item else Item(self, self.item_name.value) - control_to_add.controls.append(new_item) - self.items.controls.append(control_to_add) - self.item_name.value = "" - - self.update() - self.page.update() - - def set_indicator_opacity(self, item, opacity): - controls_list = [x.controls[1] for x in self.items.controls] - self.items.controls[controls_list.index(item)].controls[0].opacity = opacity - self.update() - - def remove_item(self, item): - controls_list = [x.controls[1] for x in self.items.controls] - del self.items.controls[controls_list.index(item)] - self.update() - - def handle_drag_accept(self, e: ft.DragTargetEvent): - src = self.page.get_control(e.src_id) - - ctrls = self.list_row.current.controls - to_index = ctrls.index(e.control.data) - from_index = ctrls.index(src.content.data) - ctrls[to_index], ctrls[from_index] = ctrls[from_index], ctrls[to_index] - self.end_indicator.opacity = 0.0 - self.page.update() - - def handle_drag_will_accept(self, e: ft.DragWillAcceptEvent): - self.end_indicator.opacity = 0.0 - self.page.update() - - def handle_drag_leave(self, e: ft.DragTargetLeaveEvent): - self.end_indicator.opacity = 0.0 - self.page.update() - - def item_drag_accept(self, e: ft.DragTargetEvent): - src = self.page.get_control(e.src_id) - self.add_item(src.data.item_text) - src.data.list.remove_item(src) - self.end_indicator.opacity = 0.0 - self.page.update() - - def item_drag_will_accept(self, e: ft.DragWillAcceptEvent): - self.end_indicator.opacity = 1.0 - self.page.update() - - def item_drag_leave(self, e: ft.DragTargetLeaveEvent): - self.end_indicator.opacity = 0.0 - self.page.update() - - -class Item(ft.Draggable): - def __init__(self, list: ItemList, item_text: str): - self.list = list - self.item_text = item_text - self.card_item = ft.Card( - elevation=1, - data=self.list, - content=ft.Container( - width=200, - padding=7, - content=ft.Row( - alignment=ft.MainAxisAlignment.START, - controls=[ - ft.Icon(ft.Icons.CIRCLE_OUTLINED), - ft.Text(value=f"{self.item_text}"), - ], - ), - ), - ) - self.target = ft.DragTarget( - group="items", - content=self.card_item, - on_accept=self.handle_drag_accept, - on_leave=self.handle_drag_leave, - on_will_accept=self.handle_drag_will_accept, - ) - super().__init__(group="items", content=self.target, data=self) - - def handle_drag_accept(self, e: ft.DragTargetEvent): - # this is the item picked up (Draggable control) - src = self.list.page.get_control(e.src_id) - - # e.control is the DragTarget, i.e. This (self) Item in the list - # skip if item is dropped on itself - if src.content.content == e.control.content: - e.control.content.elevation = 1 - self.list.set_indicator_opacity(self, 0.0) - e.control.update() - return - - # item dropped within same list but not on self - if src.data.list == self.list: - self.list.add_item(chosen_control=src, swap_control=self) - self.list.set_indicator_opacity(self, 0.0) - e.control.content.elevation = 1 - e.control.update() - return - - # item added to different list - self.list.add_item(src.data.item_text, swap_control=self) - - # remove from the list to which draggable belongs - src.data.list.remove_item(src) - - self.list.set_indicator_opacity(self, 0.0) - e.control.content.elevation = 1 - e.control.update() - - def handle_drag_will_accept(self, e: ft.DragWillAcceptEvent): - self.list.set_indicator_opacity(self, 1.0) - e.control.content.elevation = 20 if e.data == "true" else 1 - e.control.update() - - def handle_drag_leave(self, e: ft.DragTargetLeaveEvent): - self.list.set_indicator_opacity(self, 0.0) - e.control.content.elevation = 1 - e.control.update() - - -def main(page: ft.Page): - list_row = ft.Ref[ft.Row]() - - page.add( - ft.Row( - vertical_alignment=ft.CrossAxisAlignment.START, - ref=list_row, - controls=[ - ItemList(page, list_row, "List 1", ft.Colors.DEEP_ORANGE_400), - ItemList(page, list_row, "List 2", ft.Colors.PINK_400), - ItemList(page, list_row, "List 3", ft.Colors.CYAN_400), - ], - ) - ) - page.update() - - -ft.run(main) diff --git a/sdk/python/examples/controls/drag_target_and_draggable/outer_inner.py b/sdk/python/examples/controls/drag_target_and_draggable/outer_inner.py deleted file mode 100644 index e476c92190..0000000000 --- a/sdk/python/examples/controls/drag_target_and_draggable/outer_inner.py +++ /dev/null @@ -1,122 +0,0 @@ -import flet as ft - - -class OuterContainer(ft.Draggable): - def __init__(self, color, list_ref): - self.list_ref = list_ref - self.container_color = color - self.inner_container = InnerContainer(self) - self.outer_container = ft.Container( - content=self.inner_container, - width=200, - height=200, - bgcolor=self.container_color, - border_radius=5, - alignment=ft.Alignment.CENTER, - border=ft.Border.all(4, ft.Colors.BLACK12), - ) - - self.target = ft.DragTarget( - group="inner", - data=self, - on_accept=self.inner_drag_accept, - on_will_accept=self.inner_drag_will_accept, - on_leave=self.inner_drag_leave, - content=ft.DragTarget( - group="outer", - content=self.outer_container, - on_accept=self.handle_drag_accept, - on_will_accept=self.handle_drag_will_accept, - on_leave=self.handle_drag_leave, - ), - ) - super().__init__(content=self.target, group="outer") - - def handle_drag_accept(self, e: ft.DragTargetEvent): - if e.data: - self.outer_container.border = ft.Border.all(4, ft.Colors.BLACK12) - self.update() - - def handle_drag_will_accept(self, e: ft.DragWillAcceptEvent): - if e.data: - self.outer_container.border = ft.Border.all(4, ft.Colors.BLACK54) - self.update() - - def handle_drag_leave(self, e: ft.DragTargetLeaveEvent): - self.outer_container.border = ft.Border.all(4, ft.Colors.BLACK12) - self.update() - - def inner_drag_accept(self, e): - if e.data: - self.outer_container.border_radius = 5 - self.update() - - def inner_drag_will_accept(self, e: ft.DragWillAcceptEvent): - if e.data: - self.outer_container.border_radius = 25 - self.update() - - def inner_drag_leave(self, e: ft.DragTargetLeaveEvent): - self.outer_container.border_radius = 5 - self.update() - - -class InnerContainer(ft.Draggable): - def __init__(self, outer: OuterContainer): - self.outer = outer - self.inner_icon = ft.Icon( - name=ft.Icons.CIRCLE, - color=ft.Colors.WHITE54, - size=100, - tooltip="drag me!", - ) - # self.data = self - - self.target = ft.DragTarget( - group="inner", - content=self.inner_icon, - on_accept=self.handle_drag_accept, - on_leave=self.handle_drag_leave, - on_will_accept=self.handle_drag_will_accept, - ) - super().__init__(content=self.target, group="outer") - - def set_color(self, color: str): - self.inner_icon.color = color - self.update() - - def handle_drag_accept(self, e: ft.DragTargetEvent): - if e.data: - self.set_color(ft.Colors.WHITE54) - - def handle_drag_will_accept(self, e: ft.DragWillAcceptEvent): - if e.data: - self.set_color(ft.Colors.BLUE_GREY) - self.update() - - def handle_drag_leave(self, e: ft.DragTargetLeaveEvent): - self.set_color(ft.Colors.WHITE54) - self.update() - - -def main(page: ft.Page): - page.bgcolor = ft.Colors.BLUE_GREY_100 - - list_ref = ft.Ref[ft.Row]() - - page.add( - ft.Row( - ref=list_ref, - alignment=ft.MainAxisAlignment.SPACE_AROUND, - vertical_alignment=ft.CrossAxisAlignment.CENTER, - expand=True, - controls=[ - OuterContainer(ft.Colors.DEEP_ORANGE_400, list_ref), - OuterContainer(ft.Colors.BLUE_400, list_ref), - ], - ) - ) - page.update() - - -ft.run(main) From 46e80a71e07e692c176381a6ffeabffb9f665316 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 08:24:56 -0800 Subject: [PATCH 09/18] Add declarative drag-and-drop examples Added two new Python examples demonstrating declarative drag-and-drop: one for containers and one for ordering items and groups. Updated draggable.md documentation to reference the new declarative containers example. --- .../drag_and_drop_containers_declarative.py | 89 ++++++ .../drag_and_drop_ordering_declarative.py | 258 ++++++++++++++++++ .../packages/flet/docs/controls/draggable.md | 8 + 3 files changed, 355 insertions(+) create mode 100644 sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative.py create mode 100644 sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative.py b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative.py new file mode 100644 index 0000000000..621c898ebc --- /dev/null +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_containers_declarative.py @@ -0,0 +1,89 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +@ft.observable +class TargetState: + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + is_drag_over: bool = False + + +@ft.component +def App(): + target, _ = ft.use_state(lambda: TargetState()) + + def on_will_accept(e: ft.DragWillAcceptEvent): + target.is_drag_over = True + + def on_accept(e: ft.DragTargetEvent): + target.bgcolor = e.src.data + target.is_drag_over = False + + def on_leave(e: ft.DragTargetLeaveEvent): + target.is_drag_over = False + + return ft.Row( + controls=[ + ft.Column( + controls=[ + ft.Draggable( + group="color", + data=ft.Colors.CYAN, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN, + border_radius=5, + ), + content_feedback=ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.CYAN, + border_radius=3, + ), + ), + ft.Draggable( + group="color", + data=ft.Colors.YELLOW, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.YELLOW, + border_radius=5, + ), + ), + ft.Draggable( + group="color", + data=ft.Colors.GREEN, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.GREEN, + border_radius=5, + ), + ), + ] + ), + ft.Container(width=100), + ft.DragTarget( + group="color", + on_will_accept=on_will_accept, + on_accept=on_accept, + on_leave=on_leave, + content=ft.Container( + width=50, + height=50, + bgcolor=target.bgcolor, + border=ft.Border.all(2, ft.Colors.BLACK_45) + if target.is_drag_over + else None, + border_radius=5, + ), + ), + ] + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py new file mode 100644 index 0000000000..0a7b90c0ae --- /dev/null +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py @@ -0,0 +1,258 @@ +import logging +from dataclasses import dataclass, field + +import flet as ft + +logging.basicConfig(level=logging.INFO) +logging.getLogger("flet_object_patch").setLevel(logging.INFO) +logging.getLogger("flet_components").setLevel(logging.INFO) + +ItemID = ft.IdCounter() + + +@ft.observable +@dataclass +class AppState: + groups: list["Group"] = field(default_factory=list) + + def move_group(self, src: "Group", dst: "Group"): + src_index = self.groups.index(src) + dst_index = self.groups.index(dst) + if src_index != dst_index: + print("Move group", src.title, "to position of", dst.title) + self.groups.insert(dst_index, self.groups.pop(src_index)) + + +@ft.observable +@dataclass +class Group: + title: str + color: ft.Colors + items: list["Item"] = field(default_factory=list) + + def add_item(self, text: str): + self.items.append(Item(text=text, group=self)) + + def move_item_into(self, item: "Item"): + print("Move item", item.text, "from", item.group.title, "to", self.title) + item.group.items.remove(item) + item.group = self + self.items.append(item) + + +@ft.observable +@dataclass +class Item: + text: str + group: Group + id: int = field(default_factory=ItemID) + + def move_item_at(self, item: "Item", to_item: "Item"): + if item == to_item: + return + print( + f"Move item {item.text} from {item.group.title} " + f"to {to_item.group.title} at position of {to_item.text}" + ) + item.group.items.remove(item) + item.group = to_item.group + to_index = to_item.group.items.index(to_item) + to_item.group.items.insert(to_index, item) + + +@ft.component +def ItemView(item: Item, **kwargs): + is_item_over, set_is_item_over = ft.use_state(False) + + def on_accept(e: ft.DragTargetEvent): + item.move_item_at(e.src.data, item) + set_is_item_over(False) + + return ft.Column( + spacing=2, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Divider( + color=ft.Colors.BLACK38, + thickness=2, + height=2, + radius=2, + opacity=1.0 if is_item_over else 0.0, + ), + ft.Draggable( + group="items", + data=item, + content=ft.DragTarget( + group="items", + data=item, + on_will_accept=lambda e: set_is_item_over( + e.accept and e.src.data != item + ), + on_accept=on_accept, + on_leave=lambda: set_is_item_over(False), + content=ft.Card( + content=ft.Container( + padding=7, + width=200, + content=ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + ft.Icon(ft.Icons.CIRCLE_OUTLINED), + ft.Text(value=item.text), + ], + ), + ), + ), + ), + ), + ], + ) + + +@ft.component +def GroupView(group: Group, move_group, **kwargs): + is_group_over, set_is_group_over = ft.use_state(False) + is_item_over, set_is_item_over = ft.use_state(False) + new_item_text, set_new_item_text = ft.use_state("") + + def on_item_accept(e: ft.DragTargetEvent): + group.move_item_into(e.src.data) + set_is_item_over(False) + + def on_group_accept(e: ft.DragTargetEvent): + move_group(e.src.data, group) + set_is_group_over(False) + + def on_add_item(self): + if stripped_text := new_item_text.strip(): + group.add_item(stripped_text) + set_new_item_text("") + + return ft.Row( + spacing=4, + intrinsic_height=True, + controls=[ + ft.VerticalDivider( + color=ft.Colors.BLACK_54, + width=2, + thickness=2, + radius=2, + leading_indent=15, + trailing_indent=15, + opacity=1.0 if is_group_over else 0.0, + ), + ft.Draggable( + group="groups", + data=group, + content=ft.DragTarget( + group="items", + data=group, + on_will_accept=lambda e: set_is_item_over(e.accept), + on_accept=on_item_accept, + on_leave=lambda: set_is_item_over(False), + content=ft.DragTarget( + group="groups", + data=group, + on_will_accept=lambda e: set_is_group_over( + e.accept and e.src.data != group + ), + on_accept=on_group_accept, + on_leave=lambda: set_is_group_over(False), + content=ft.Container( + border=ft.Border.all(2, ft.Colors.BLACK12) + if not is_group_over + else ft.Border.all(2, ft.Colors.BLACK38), + border_radius=ft.BorderRadius.all(15), + bgcolor=group.color, + padding=ft.Padding.all(20), + width=220, + content=ft.Column( + spacing=4, + controls=[ + ft.Text( + group.title, + theme_style=ft.TextThemeStyle.TITLE_LARGE, + ), + ft.TextField( + label="New item", + bgcolor=ft.Colors.WHITE, + value=new_item_text, + on_change=lambda e: set_new_item_text( + e.control.value + ), + on_submit=on_add_item, + ), + ft.TextButton( + content="Add", + icon=ft.Icons.ADD, + on_click=on_add_item, + ), + ft.Column( + spacing=2, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + *[ + ItemView(item, key=item.id) + for item in group.items + ], + ft.Divider( + color=ft.Colors.BLACK38, + thickness=2, + height=2, + radius=2, + opacity=1.0 if is_item_over else 0.0, + ), + ], + ), + ], + ), + ), + ), + ), + ), + ], + ) + + +@ft.component +def App(): + group_1 = Group(title="Group 1", color=ft.Colors.DEEP_ORANGE_400) + group_1.add_item("Item 1") + group_1.add_item("Item 2") + + group_2 = Group(title="Group 2", color=ft.Colors.PINK_400) + group_2.add_item("Item 3") + + group_3 = Group(title="Group 3", color=ft.Colors.CYAN_400) + group_3.add_item("Item 4") + + # group_4 = Group(title="Group 4", color=ft.Colors.GREEN_400) + # group_4.add_item("Item 5") + + app, _ = ft.use_state( + lambda: AppState( + groups=[ + group_1, + group_2, + group_3, + # group_4, + ] + ) + ) + + def on_mounted(): + ft.context.page.theme_mode = ft.ThemeMode.LIGHT + + ft.on_mounted(on_mounted) + + return ft.Row( + spacing=4, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + GroupView(group, move_group=app.move_group, key=group.title) + for group in app.groups + ], + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/packages/flet/docs/controls/draggable.md b/sdk/python/packages/flet/docs/controls/draggable.md index 30053f47ad..0b7f12f81f 100644 --- a/sdk/python/packages/flet/docs/controls/draggable.md +++ b/sdk/python/packages/flet/docs/controls/draggable.md @@ -12,10 +12,18 @@ example_images: ../examples/controls/drag_target_and_draggable/media ### Drag and drop Containers +#### Imperative + ```python --8<-- "{{ examples }}/drag_and_drop_containers.py" ``` +#### Declarative + +```python +--8<-- "{{ examples }}/drag_and_drop_containers_declarative.py" +``` + {{ image(example_images + "/drag_and_drop_containers.gif", alt="drag-and-drop-containers", width="80%") }} From 67456a56be3ebdee4529d5c84e99a3b66829405f Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 08:31:35 -0800 Subject: [PATCH 10/18] Rename dropdown example and clean up code Renamed 'reactive.py' to 'declarative.py' for clarity. Removed unused logging setup from 'basic.py'. Fixed icon name reference in 'dropdown_random_icon.py' to use 'icon.icon' instead of 'icon.name'. --- .../controls/dropdown/{reactive.py => declarative.py} | 0 sdk/python/examples/controls/dropdown_m2/basic.py | 4 ---- .../examples/controls/dropdown_m2/dropdown_random_icon.py | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) rename sdk/python/examples/controls/dropdown/{reactive.py => declarative.py} (100%) diff --git a/sdk/python/examples/controls/dropdown/reactive.py b/sdk/python/examples/controls/dropdown/declarative.py similarity index 100% rename from sdk/python/examples/controls/dropdown/reactive.py rename to sdk/python/examples/controls/dropdown/declarative.py diff --git a/sdk/python/examples/controls/dropdown_m2/basic.py b/sdk/python/examples/controls/dropdown_m2/basic.py index 9476e82c2a..02b94a10fc 100644 --- a/sdk/python/examples/controls/dropdown_m2/basic.py +++ b/sdk/python/examples/controls/dropdown_m2/basic.py @@ -1,9 +1,5 @@ -import logging - import flet as ft -logging.basicConfig(level=logging.DEBUG) - def main(page: ft.Page): # page.theme_mode = ft.ThemeMode.DARK diff --git a/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon.py b/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon.py index 890822fc71..02c491b982 100644 --- a/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon.py +++ b/sdk/python/examples/controls/dropdown_m2/dropdown_random_icon.py @@ -11,7 +11,7 @@ def handle_dropdown_change(e: ft.Event[ft.DropdownM2]): def handle_new_random_item(e: ft.Event[ft.Button]): icon = ft.Icon(ft.Icons.random()) dd.options.append( - ft.dropdownm2.Option(text=f"{str(icon.name)[6:]}", content=icon) + ft.dropdownm2.Option(text=f"{str(icon.icon)[6:]}", content=icon) ) page.update() From c89b46d9aa05a21b29886af532f908d390713ac2 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 08:45:01 -0800 Subject: [PATCH 11/18] Fix ExpansionTile trailing icon property usage Replaces incorrect usage of 'name' with 'icon' for the trailing property in ExpansionTile event handlers. Also updates SnackBar text assignment for ruff formatting. --- sdk/python/examples/controls/expansion_tile/basic.py | 9 ++++++--- .../controls/expansion_tile/theme_mode_toggle.py | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sdk/python/examples/controls/expansion_tile/basic.py b/sdk/python/examples/controls/expansion_tile/basic.py index 1b6c39d148..9e47ab1f14 100644 --- a/sdk/python/examples/controls/expansion_tile/basic.py +++ b/sdk/python/examples/controls/expansion_tile/basic.py @@ -11,14 +11,17 @@ def handle_tile_change(e: ft.Event[ft.ExpansionTile]): ft.SnackBar( duration=1000, content=ft.Text( - value=f"ExpansionTile was {'expanded' if e.data == 'true' else 'collapsed'}" + value=( + f"ExpansionTile was " + f"{'expanded' if e.data == 'true' else 'collapsed'}" + ) ), ) ) if e.control.trailing: - e.control.trailing.name = ( + e.control.trailing.icon = ( ft.Icons.ARROW_DROP_DOWN - if e.control.trailing.name == ft.Icons.ARROW_DROP_DOWN_CIRCLE + if e.control.trailing.icon == ft.Icons.ARROW_DROP_DOWN_CIRCLE else ft.Icons.ARROW_DROP_DOWN_CIRCLE ) page.update() diff --git a/sdk/python/examples/controls/expansion_tile/theme_mode_toggle.py b/sdk/python/examples/controls/expansion_tile/theme_mode_toggle.py index 0f4c0ffd87..778bdf031f 100644 --- a/sdk/python/examples/controls/expansion_tile/theme_mode_toggle.py +++ b/sdk/python/examples/controls/expansion_tile/theme_mode_toggle.py @@ -19,14 +19,17 @@ def handle_expansion_tile_change(e: ft.Event[ft.ExpansionTile]): ft.SnackBar( duration=1000, content=ft.Text( - f"ExpansionTile was {'expanded' if e.data == 'true' else 'collapsed'}" + value=( + f"ExpansionTile was " + f"{'expanded' if e.data == 'true' else 'collapsed'}" + ) ), ) ) if e.control.trailing: - e.control.trailing.name = ( + e.control.trailing.icon = ( ft.Icons.ARROW_DROP_DOWN - if e.control.trailing.name == ft.Icons.ARROW_DROP_DOWN_CIRCLE + if e.control.trailing.icon == ft.Icons.ARROW_DROP_DOWN_CIRCLE else ft.Icons.ARROW_DROP_DOWN_CIRCLE ) page.update() From a4de04176c8265ef63f7fd70fc968d3ff1bd53f8 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 09:22:59 -0800 Subject: [PATCH 12/18] Update gesture detector event handling and cursor change Replaced usage of delta_x and delta_y with local_delta.x and local_delta.y in draggable_containers.py for more accurate drag updates. Simplified mouse cursor change logic in mouse_cursors.py by using random.choice instead of a generator. --- .../controls/gesture_detector/draggable_containers.py | 8 ++++---- .../controls/gesture_detector/mouse_cursors.py | 10 +++------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/sdk/python/examples/controls/gesture_detector/draggable_containers.py b/sdk/python/examples/controls/gesture_detector/draggable_containers.py index 88326f82a0..7b11d7d52d 100644 --- a/sdk/python/examples/controls/gesture_detector/draggable_containers.py +++ b/sdk/python/examples/controls/gesture_detector/draggable_containers.py @@ -4,13 +4,13 @@ def main(page: ft.Page): def handle_pan_update1(e: ft.DragUpdateEvent[ft.GestureDetector]): container = e.control.parent - container.top = max(0.0, container.top + e.delta_y) - container.left = max(0.0, container.left + e.delta_x) + container.top = max(0.0, container.top + e.local_delta.y) + container.left = max(0.0, container.left + e.local_delta.x) container.update() def handle_pan_update2(e: ft.DragUpdateEvent[ft.GestureDetector]): - e.control.top = max(0.0, e.control.top + e.delta_y) - e.control.left = max(0.0, e.control.left + e.delta_x) + e.control.top = max(0.0, e.control.top + e.local_delta.y) + e.control.left = max(0.0, e.control.left + e.local_delta.x) e.control.update() page.add( diff --git a/sdk/python/examples/controls/gesture_detector/mouse_cursors.py b/sdk/python/examples/controls/gesture_detector/mouse_cursors.py index 5745bb3342..3fc1c567af 100644 --- a/sdk/python/examples/controls/gesture_detector/mouse_cursors.py +++ b/sdk/python/examples/controls/gesture_detector/mouse_cursors.py @@ -1,3 +1,5 @@ +import random + import flet as ft @@ -22,16 +24,10 @@ def on_pan_update(event: ft.DragUpdateEvent[ft.GestureDetector]): ) def handle_button_click(e: ft.Event[ft.Button]): - gesture_detector.mouse_cursor = next( - generate_mouse_cursors(list(ft.MouseCursor)) - ) + gesture_detector.mouse_cursor = random.choice(list(ft.MouseCursor)) text.value = f"Mouse Cursor: {gesture_detector.mouse_cursor}" page.update() - def generate_mouse_cursors(m_list): - while True: - yield from m_list - page.add( ft.Stack(controls=[container], width=1000, height=500), ft.Button("Change mouse Cursor", on_click=handle_button_click), From 50de9b48ecf9dd1bf2e86785fda79e3cf3848496 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 10:20:44 -0800 Subject: [PATCH 13/18] Update image assets and fix control property usage Added app_icon_512.png and updated gallery.py to use the new image asset. Fixed property names and usage in static_svg.py, handling_events.py, and outlined_button/icons.py to use correct constants and class references for colors, margins, and icons. --- .../controls/image/assets/app_icon_512.png | Bin 0 -> 21589 bytes sdk/python/examples/controls/image/gallery.py | 2 +- .../examples/controls/image/static_svg.py | 47 +++++++++++------- .../interactive_viewer/handling_events.py | 2 +- .../controls/outlined_button/icons.py | 6 +-- 5 files changed, 33 insertions(+), 24 deletions(-) create mode 100644 sdk/python/examples/controls/image/assets/app_icon_512.png diff --git a/sdk/python/examples/controls/image/assets/app_icon_512.png b/sdk/python/examples/controls/image/assets/app_icon_512.png new file mode 100644 index 0000000000000000000000000000000000000000..f89a749adafe1a1306e9034cbb156ab99d2d5c1c GIT binary patch literal 21589 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 AD*ylh literal 0 HcmV?d00001 diff --git a/sdk/python/examples/controls/image/gallery.py b/sdk/python/examples/controls/image/gallery.py index a57a300d39..fb6d6bc2ce 100644 --- a/sdk/python/examples/controls/image/gallery.py +++ b/sdk/python/examples/controls/image/gallery.py @@ -8,7 +8,7 @@ def main(page: ft.Page): page.add( ft.Image( - src="/icons/icon-512.png", + src="app_icon_512.png", width=100, height=100, fit=ft.BoxFit.CONTAIN, diff --git a/sdk/python/examples/controls/image/static_svg.py b/sdk/python/examples/controls/image/static_svg.py index 633d0a0fab..fd2e3b5ae1 100644 --- a/sdk/python/examples/controls/image/static_svg.py +++ b/sdk/python/examples/controls/image/static_svg.py @@ -3,25 +3,34 @@ def main(page: ft.Page): svg_image = """ - + - - - + + + """ @@ -34,7 +43,7 @@ def main(page: ft.Page): ft.Image(src=svg_image, width=100, height=100, color=ft.Colors.RED), ft.Image(src=svg_image, width=100, height=100, color=ft.Colors.BLUE), ft.Container( - bgcolor=ft.Colors.BLACK87, + bgcolor=ft.Colors.BLACK_87, border_radius=5, content=ft.Image( src=svg_image, diff --git a/sdk/python/examples/controls/interactive_viewer/handling_events.py b/sdk/python/examples/controls/interactive_viewer/handling_events.py index 305a522d82..0aa1c3b8fe 100644 --- a/sdk/python/examples/controls/interactive_viewer/handling_events.py +++ b/sdk/python/examples/controls/interactive_viewer/handling_events.py @@ -6,7 +6,7 @@ def main(page: ft.Page): ft.InteractiveViewer( min_scale=0.1, max_scale=15, - boundary_margin=ft.margin.all(20), + boundary_margin=ft.Margin.all(20), on_interaction_start=lambda e: print(e), on_interaction_end=lambda e: print(e), on_interaction_update=lambda e: print(e), diff --git a/sdk/python/examples/controls/outlined_button/icons.py b/sdk/python/examples/controls/outlined_button/icons.py index dc03b3bdd3..5821d56af8 100644 --- a/sdk/python/examples/controls/outlined_button/icons.py +++ b/sdk/python/examples/controls/outlined_button/icons.py @@ -5,11 +5,11 @@ def main(page: ft.Page): page.title = "OutlinedButton Example" page.add( - ft.OutlinedButton(content="Button with icon", icon="chair_outlined"), + ft.OutlinedButton(content="Button with icon", icon=ft.Icons.CHAIR_OUTLINED), ft.OutlinedButton( content="Button with colorful icon", - icon="park_rounded", - icon_color="green400", + icon=ft.Icons.PARK_ROUNDED, + icon_color=ft.Colors.GREEN_400, ), ) From 4c8b1b9c59c77cb5c4b8d61afed4cec3b86c291a Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 10:32:47 -0800 Subject: [PATCH 14/18] Fix color constant in ButtonControl border Replaces 'ft.Colors.BLACK54' with 'ft.Colors.BLACK_54' to use the correct color constant for the button border. --- sdk/python/examples/controls/page/keyboard_events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/python/examples/controls/page/keyboard_events.py b/sdk/python/examples/controls/page/keyboard_events.py index 2ce5e2c764..91b931ad39 100644 --- a/sdk/python/examples/controls/page/keyboard_events.py +++ b/sdk/python/examples/controls/page/keyboard_events.py @@ -5,7 +5,7 @@ class ButtonControl(ft.Container): def __init__(self, text): super().__init__() self.content: ft.Text = ft.Text(text) - self.border = ft.Border.all(1, ft.Colors.BLACK54) + self.border = ft.Border.all(1, ft.Colors.BLACK_54) self.border_radius = 3 self.bgcolor = "0x09000000" self.padding = 10 From ec27561db920ffb8ca5bf67e20377ac2728106ec Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 11:01:25 -0800 Subject: [PATCH 15/18] Update event handlers to print control object Changed event handler print statements to output the control object instead of its uid for better debugging and information in rich text example. --- sdk/python/examples/controls/text/rich_text_basic.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/python/examples/controls/text/rich_text_basic.py b/sdk/python/examples/controls/text/rich_text_basic.py index 3fe7378db5..44e8cb2f6e 100644 --- a/sdk/python/examples/controls/text/rich_text_basic.py +++ b/sdk/python/examples/controls/text/rich_text_basic.py @@ -34,9 +34,9 @@ def main(page: ft.Page): ft.TextSpan( text="underlined and clickable", style=ft.TextStyle(decoration=ft.TextDecoration.UNDERLINE), - on_click=lambda e: print(f"Clicked span: {e.control.uid}"), - on_enter=lambda e: print(f"Entered span: {e.control.uid}"), - on_exit=lambda e: print(f"Exited span: {e.control.uid}"), + on_click=lambda e: print(f"Clicked span: {e.control}"), + on_enter=lambda e: print(f"Entered span: {e.control}"), + on_exit=lambda e: print(f"Exited span: {e.control}"), ), ft.TextSpan(text=" "), ft.TextSpan( @@ -46,8 +46,8 @@ def main(page: ft.Page): decoration_color=ft.Colors.RED, decoration_style=ft.TextDecorationStyle.WAVY, ), - on_enter=lambda e: print(f"Entered span: {e.control.uid}"), - on_exit=lambda e: print(f"Exited span: {e.control.uid}"), + on_enter=lambda e: print(f"Entered span: {e.control}"), + on_exit=lambda e: print(f"Exited span: {e.control}"), ), ft.TextSpan(text=" "), ft.TextSpan( From 8db6529bb69c8d51e02172f0d80bbd6e05e1f132 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Tue, 18 Nov 2025 11:08:26 -0800 Subject: [PATCH 16/18] Fix string formatting and color constant in text field examples Corrected multi-line string assignment in prefix_and_suffix.py to properly display textbox values. Updated styled.py to use the correct color constant 'BLACK_26' instead of 'BLACK26'. --- .../examples/controls/text_field/prefix_and_suffix.py | 9 +++++++-- sdk/python/examples/controls/text_field/styled.py | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sdk/python/examples/controls/text_field/prefix_and_suffix.py b/sdk/python/examples/controls/text_field/prefix_and_suffix.py index ca46563b90..0007346b47 100644 --- a/sdk/python/examples/controls/text_field/prefix_and_suffix.py +++ b/sdk/python/examples/controls/text_field/prefix_and_suffix.py @@ -3,8 +3,13 @@ def main(page: ft.Page): def handle_button_click(e: ft.Event[ft.Button]): - message.value = f"Textboxes values are: '{prefix_field.value}', " - f"'{suffix_field.value}', '{prefix_suffix_field.value}', '{color_field.value}'." + message.value = ( + "Textboxes values are: " + f"'{prefix_field.value}', " + f"'{suffix_field.value}', " + f"'{prefix_suffix_field.value}', " + f"'{color_field.value}'." + ) page.update() page.add( diff --git a/sdk/python/examples/controls/text_field/styled.py b/sdk/python/examples/controls/text_field/styled.py index b95e279f19..fe2aca1f4c 100644 --- a/sdk/python/examples/controls/text_field/styled.py +++ b/sdk/python/examples/controls/text_field/styled.py @@ -10,7 +10,7 @@ async def main(page: ft.Page): cursor_color=ft.Colors.RED, selection_color=ft.Colors.YELLOW, color=ft.Colors.PINK, - bgcolor=ft.Colors.BLACK26, + bgcolor=ft.Colors.BLACK_26, filled=True, focused_color=ft.Colors.GREEN, focused_bgcolor=ft.Colors.CYAN_200, @@ -23,4 +23,5 @@ async def main(page: ft.Page): ) await tf.focus() + ft.run(main) From e9f537476edc2e1f817f9d97f1e82b5224dc6779 Mon Sep 17 00:00:00 2001 From: InesaFitsner Date: Wed, 19 Nov 2025 09:32:25 -0800 Subject: [PATCH 17/18] Remove logging setup from drag and drop example Eliminated unnecessary logging configuration and logger level settings from the drag_and_drop_ordering_declarative.py example to simplify the code. --- .../drag_and_drop_ordering_declarative.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py index 0a7b90c0ae..04a1b4cf30 100644 --- a/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py @@ -1,12 +1,7 @@ -import logging from dataclasses import dataclass, field import flet as ft -logging.basicConfig(level=logging.INFO) -logging.getLogger("flet_object_patch").setLevel(logging.INFO) -logging.getLogger("flet_components").setLevel(logging.INFO) - ItemID = ft.IdCounter() From 0189602fefdc51adab076d01fc1b7b2f185ae6d6 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 19 Nov 2025 09:54:51 -0800 Subject: [PATCH 18/18] Move plotting libraries to dev dependencies matplotlib, plotly, and kaleido have been moved from main dependencies to dev dependencies in pyproject.toml. This reduces the default install footprint for end users and keeps plotting tools available for development and testing. --- sdk/python/pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 0178d298a1..07880750de 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -22,10 +22,7 @@ dependencies = [ "flet-permission-handler", "flet-rive", "flet-video", - "flet-webview", - "matplotlib>=3.10.7", - "plotly>=6.4.0", - "kaleido>=1.2.0", + "flet-webview" ] [tool.uv.sources] @@ -66,6 +63,9 @@ dev = [ "numpy >=2.2.0", "scikit-image >=0.25.2", "ruff >=0.13.1", + "matplotlib>=3.10.7", + "plotly>=6.4.0", + "kaleido>=1.2.0", { include-group = 'test' }, ] docs-coverage = [