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/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/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/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(), 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, 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) 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), ) ) 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), ) ) 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/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..04a1b4cf30 --- /dev/null +++ b/sdk/python/examples/controls/drag_target_and_draggable/drag_and_drop_ordering_declarative.py @@ -0,0 +1,253 @@ +from dataclasses import dataclass, field + +import flet as ft + +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/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) 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() 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() 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), 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 0000000000..f89a749ada Binary files /dev/null and b/sdk/python/examples/controls/image/assets/app_icon_512.png differ 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, ), ) 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 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( 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) 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/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%") }} 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%") }} diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 2bd45fcce2..07880750de 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -63,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 = [