From cfd90f6d4876a8181b747f1da648710fa5f18c28 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Fri, 7 Nov 2025 14:53:56 +0100 Subject: [PATCH 01/15] initial commit --- .../flet/lib/src/controls/time_picker.dart | 9 +- sdk/python/packages/flet/src/flet/__init__.py | 2 + .../src/flet/controls/material/time_picker.py | 84 ++++++++++++++----- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/packages/flet/lib/src/controls/time_picker.dart b/packages/flet/lib/src/controls/time_picker.dart index 3aaea38596..dcfa52674f 100644 --- a/packages/flet/lib/src/controls/time_picker.dart +++ b/packages/flet/lib/src/controls/time_picker.dart @@ -25,6 +25,7 @@ class _TimePickerControlState extends State { var open = widget.control.getBool("open", false)!; var value = widget.control.getTimeOfDay("value", TimeOfDay.now())!; + var hourFormat = widget.control.getString("hour_format"); void onClosed(TimeOfDay? timeValue) { widget.control.updateProperties({"_open": false}, python: false); @@ -52,7 +53,13 @@ class _TimePickerControlState extends State { }, ); - return dialog; + final hourFormatMap = {"h12": false, "h24": true, "system": null}; + return MediaQuery( + data: MediaQuery.of(context) + .copyWith(alwaysUse24HourFormat: hourFormatMap[hourFormat]), + child: dialog, + ); + ; } if (open && (open != lastOpen)) { diff --git a/sdk/python/packages/flet/src/flet/__init__.py b/sdk/python/packages/flet/src/flet/__init__.py index a16828e7f6..c56c469163 100644 --- a/sdk/python/packages/flet/src/flet/__init__.py +++ b/sdk/python/packages/flet/src/flet/__init__.py @@ -374,6 +374,7 @@ TimePicker, TimePickerEntryMode, TimePickerEntryModeChangeEvent, + TimePickerHourFormat, ) from flet.controls.material.tooltip import Tooltip, TooltipTriggerMode, TooltipValue from flet.controls.material.vertical_divider import VerticalDivider @@ -939,6 +940,7 @@ "TimePicker", "TimePickerEntryMode", "TimePickerEntryModeChangeEvent", + "TimePickerHourFormat", "TimePickerTheme", "Tooltip", "TooltipTheme", diff --git a/sdk/python/packages/flet/src/flet/controls/material/time_picker.py b/sdk/python/packages/flet/src/flet/controls/material/time_picker.py index 88eff6bd31..27a518bcc6 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/time_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/material/time_picker.py @@ -15,7 +15,27 @@ Orientation, ) -__all__ = ["TimePicker", "TimePickerEntryMode", "TimePickerEntryModeChangeEvent"] +__all__ = [ + "TimePicker", + "TimePickerEntryMode", + "TimePickerEntryModeChangeEvent", + "TimePickerHourFormat", +] + + +class TimePickerHourFormat(Enum): + """ + Defines the hour format for the [`TimePicker`][flet.] control. + """ + + SYSTEM = "system" + """Respect the host platform setting.""" + + H12 = "h12" + """Force a 12-hour clock with an AM/PM selector.""" + + H24 = "h24" + """Force a 24-hour clock without an AM/PM selector.""" class TimePickerEntryMode(Enum): @@ -34,24 +54,27 @@ class TimePicker(DialogControl): """ A Material-style time picker dialog. - Can be opened by calling `page.show_dialog()` method. + Can be opened by calling the + [`Page.show_dialog()`][flet.Page.show_dialog] method. - Depending on the `time_picker_entry_mode`, it will show either a Dial or + Depending on the [`time_picker_entry_mode`][(c).], it will show either a Dial or an Input (hour and minute text fields) for picking a time. - ```python - ft.TimePicker( - value=time(1, 2), - time_picker_entry_mode=ft.TimePickerEntryMode.INPUT_ONLY, - open=True, - ) - ``` + Example: + ```python + ft.TimePicker( + open=True, + value=time(1, 2), + time_picker_entry_mode=ft.TimePickerEntryMode.INPUT_ONLY, + ) + ``` """ value: Optional[time] = field(default_factory=lambda: datetime.now().time()) """ - The selected time that the picker should display. The default value is equal - to the current time. + The selected time that this picker should display. + + The default value is equal to the current time. """ modal: bool = False @@ -61,23 +84,23 @@ class TimePicker(DialogControl): time_picker_entry_mode: Optional[TimePickerEntryMode] = None """ - The initial mode of time entry method for the time picker dialog. + The initial mode of time entry method for this picker. - Defaults to `TimePickerEntryMode.DIAL`. + Defaults to [`TimePickerEntryMode.DIAL`][flet.]. """ hour_label_text: Optional[str] = None """ The text that is displayed below the hour input text field. - The default value is "Hour". + The default value is `"Hour"`. """ minute_label_text: Optional[str] = None """ The text that is displayed below the minute input text field. - The default value is "Minute". + The default value is `"Minute"`. """ help_text: Optional[str] = None @@ -85,23 +108,29 @@ class TimePicker(DialogControl): The text that is displayed at the top of the header. This is used to indicate to the user what they are selecting a time for. - The default value is "Enter time". + The default value is `"Enter time"`. """ cancel_text: Optional[str] = None """ - The text that is displayed on the cancel button. The default value is "Cancel". + The text that is displayed on the cancel button. + + The default value is `"Cancel"`. """ confirm_text: Optional[str] = None """ - The text that is displayed on the confirm button. The default value is "OK". + The text that is displayed on the confirm button. + + The default value is `"OK"`. """ error_invalid_text: Optional[str] = None """ The error message displayed below the input text field if the input is not a - valid hour/minute. The default value is "Enter a valid time". + valid hour/minute. + + The default value is `"Enter a valid time"`. """ orientation: Optional[Orientation] = None @@ -116,11 +145,20 @@ class TimePicker(DialogControl): on_change: Optional[ControlEventHandler["TimePicker"]] = None """ - Called when user clicks confirm button. `value` property is updated with selected - time. `e.data` also contains the selected time. + Called when user clicks confirm button. + + `value` property is updated with selected time. + Additionally, the [`data`][flet.Event.] property of the event handler argument + also contains the selected time. """ on_entry_mode_change: Optional[EventHandler[TimePickerEntryModeChangeEvent]] = None """ - Called when the `time_picker_entry_mode` is changed. + Called when the [`time_picker_entry_mode`][(c).] + is changed through the time picker dialog. + """ + + hour_format: TimePickerHourFormat = TimePickerHourFormat.SYSTEM + """ + Defines the hour format of this time picker. """ From cb62a492d818de5c3e3ab4a2d00035a0b6f900f9 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Fri, 7 Nov 2025 14:54:40 +0100 Subject: [PATCH 02/15] docs --- .../packages/flet/docs/types/timepickerhourformat.md | 1 + sdk/python/packages/flet/mkdocs.yml | 1 + sdk/python/packages/flet/src/flet/controls/theme.py | 12 ++++++------ 3 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 sdk/python/packages/flet/docs/types/timepickerhourformat.md diff --git a/sdk/python/packages/flet/docs/types/timepickerhourformat.md b/sdk/python/packages/flet/docs/types/timepickerhourformat.md new file mode 100644 index 0000000000..860e231e99 --- /dev/null +++ b/sdk/python/packages/flet/docs/types/timepickerhourformat.md @@ -0,0 +1 @@ +{{ class_all_options("flet.TimePickerHourFormat", separate_signature=False) }} diff --git a/sdk/python/packages/flet/mkdocs.yml b/sdk/python/packages/flet/mkdocs.yml index d22146d102..0c70e239ab 100644 --- a/sdk/python/packages/flet/mkdocs.yml +++ b/sdk/python/packages/flet/mkdocs.yml @@ -820,6 +820,7 @@ nav: - ThemeMode: types/thememode.md - TileAffinity: types/tileaffinity.md - TimePickerEntryMode: types/timepickerentrymode.md + - TimePickerHourFormat: types/timepickerhourformat.md - TooltipTriggerMode: types/tooltiptriggermode.md - UrlTarget: types/urltarget.md - VerticalAlignment: types/verticalalignment.md diff --git a/sdk/python/packages/flet/src/flet/controls/theme.py b/sdk/python/packages/flet/src/flet/controls/theme.py index 2f91b59f4b..c3a5621362 100644 --- a/sdk/python/packages/flet/src/flet/controls/theme.py +++ b/sdk/python/packages/flet/src/flet/controls/theme.py @@ -2135,7 +2135,7 @@ class TimePickerTheme: day_period_text_style: Optional[TextStyle] = None """ - Used to configure the [TextStyle][flet.TextStyle] for the AM/PM toggle control. + Used to configure the [`TextStyle`][flet.TextStyle] for the AM/PM toggle control. If this is null, the time picker defaults to the overall theme's [`TextTheme.title_medium`][flet.]. @@ -2143,18 +2143,18 @@ class TimePickerTheme: dial_text_style: Optional[TextStyle] = None """ - The [TextStyle][flet.TextStyle] for the numbers on the time selection dial. + The [`TextStyle`][[flet.TextStyle] for the numbers on the time selection dial. """ help_text_style: Optional[TextStyle] = None """ - Used to configure the [TextStyle][flet.TextStyle] for the helper text in the header. - + Used to configure the [`TextStyle`][[flet.TextStyle] + for the helper text in the header. """ hour_minute_text_style: Optional[TextStyle] = None """ - Used to configure the [TextStyle][flet.TextStyle] for the hour/minute controls. + Used to configure the [`TextStyle`][[flet.TextStyle] for the hour/minute controls. """ elevation: Optional[Number] = None @@ -2547,7 +2547,7 @@ class SliderTheme: value_indicator_text_style: Optional[TextStyle] = None """ - The [TextStyle][flet.TextStyle] for the text on the value indicator. + The [`TextStyle`][flet.TextStyle] for the text on the value indicator. """ mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None From e02d43e2bfe8217b8cb1eca4ac755e231adbf6de Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Fri, 7 Nov 2025 16:07:37 +0100 Subject: [PATCH 03/15] examples --- .../flet/lib/src/controls/time_picker.dart | 9 +-- .../examples/controls/time_picker/basic.py | 18 +++--- .../controls/time_picker/hour_format.py | 57 +++++++++++++++++++ .../packages/flet/docs/controls/timepicker.md | 6 ++ .../flet/src/flet/controls/base_page.py | 6 +- .../src/flet/controls/material/time_picker.py | 50 +++++++++++++--- 6 files changed, 125 insertions(+), 21 deletions(-) create mode 100644 sdk/python/examples/controls/time_picker/hour_format.py diff --git a/packages/flet/lib/src/controls/time_picker.dart b/packages/flet/lib/src/controls/time_picker.dart index dcfa52674f..115c4c3033 100644 --- a/packages/flet/lib/src/controls/time_picker.dart +++ b/packages/flet/lib/src/controls/time_picker.dart @@ -45,11 +45,13 @@ class _TimePickerControlState extends State { hourLabelText: widget.control.getString("hour_label_text"), minuteLabelText: widget.control.getString("minute_label_text"), errorInvalidText: widget.control.getString("error_invalid_text"), - initialEntryMode: widget.control.getTimePickerEntryMode( - "time_picker_entry_mode", TimePickerEntryMode.dial)!, + initialEntryMode: widget.control + .getTimePickerEntryMode("entry_mode", TimePickerEntryMode.dial)!, orientation: widget.control.getOrientation("orientation"), onEntryModeChanged: (TimePickerEntryMode mode) { - widget.control.triggerEvent("entry_mode_change", mode.name); + widget.control.updateProperties({"entry_mode": mode.name}); + widget.control + .triggerEvent("entry_mode_change", {"entry_mode": mode.name}); }, ); @@ -59,7 +61,6 @@ class _TimePickerControlState extends State { .copyWith(alwaysUse24HourFormat: hourFormatMap[hourFormat]), child: dialog, ); - ; } if (open && (open != lastOpen)) { diff --git a/sdk/python/examples/controls/time_picker/basic.py b/sdk/python/examples/controls/time_picker/basic.py index 99c9743108..5815c5a90e 100644 --- a/sdk/python/examples/controls/time_picker/basic.py +++ b/sdk/python/examples/controls/time_picker/basic.py @@ -1,21 +1,24 @@ -import flet as ft from datetime import time +import flet as ft + def main(page: ft.Page): page.horizontal_alignment = ft.CrossAxisAlignment.CENTER def handle_change(e: ft.Event[ft.TimePicker]): - page.add(ft.Text(f"TimePicker change: {time_picker.value}")) + selection.value = f"Selection: {time_picker.value}" + page.show_dialog(ft.SnackBar(f"TimePicker change: {time_picker.value}")) def handle_dismissal(e: ft.Event[ft.TimePicker]): - page.add(ft.Text(f"TimePicker dismissed: {time_picker.value}")) + page.show_dialog(ft.SnackBar("TimePicker dismissed!")) def handle_entry_mode_change(e: ft.TimePickerEntryModeChangeEvent): - page.add(ft.Text(f"TimePicker Entry mode changed to {e.entry_mode}")) + page.show_dialog(ft.SnackBar(f"Entry mode changed: {time_picker.entry_mode}")) + # print(e, e.entry_mode) time_picker = ft.TimePicker( - value=time(1, 2), + value=time(hour=1, minute=2), confirm_text="Confirm", error_invalid_text="Time out of range", help_text="Pick your time slot", @@ -28,8 +31,9 @@ def handle_entry_mode_change(e: ft.TimePickerEntryModeChangeEvent): ft.Button( content="Pick time", icon=ft.Icons.TIME_TO_LEAVE, - on_click=lambda _: page.show_dialog(time_picker), - ) + on_click=lambda: page.show_dialog(time_picker), + ), + selection := ft.Text(weight=ft.FontWeight.BOLD), ) diff --git a/sdk/python/examples/controls/time_picker/hour_format.py b/sdk/python/examples/controls/time_picker/hour_format.py new file mode 100644 index 0000000000..7bba5197db --- /dev/null +++ b/sdk/python/examples/controls/time_picker/hour_format.py @@ -0,0 +1,57 @@ +from datetime import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def handle_change(e: ft.Event[ft.TimePicker]): + fmt = ( + "%H:%M" + if time_picker.hour_format == ft.TimePickerHourFormat.H24 + else "%I:%M %p" + ) + selection.value = f"Selection: {time_picker.value.strftime(fmt)}" + + time_picker = ft.TimePicker( + value=time(hour=9, minute=30), + help_text="Choose your meeting time", + on_change=handle_change, + ) + + def open_picker(e: ft.Event[ft.Button]): + choice = format_dropdown.value + hour_format_map = { + "system": ft.TimePickerHourFormat.SYSTEM, + "12h": ft.TimePickerHourFormat.H12, + "24h": ft.TimePickerHourFormat.H24, + } + time_picker.hour_format = hour_format_map[choice] + page.show_dialog(time_picker) + + page.add( + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + format_dropdown := ft.Dropdown( + label="Hour format", + value="system", + width=210, + options=[ + ft.DropdownOption(key="system", text="System default"), + ft.DropdownOption(key="12h", text="12-hour clock"), + ft.DropdownOption(key="24h", text="24-hour clock"), + ], + ), + ft.Button( + "Open TimePicker", icon=ft.Icons.SCHEDULE, on_click=open_picker + ), + ], + ), + selection := ft.Text(weight=ft.FontWeight.BOLD), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/packages/flet/docs/controls/timepicker.md b/sdk/python/packages/flet/docs/controls/timepicker.md index 60d512cfde..1a0e1282e6 100644 --- a/sdk/python/packages/flet/docs/controls/timepicker.md +++ b/sdk/python/packages/flet/docs/controls/timepicker.md @@ -18,5 +18,11 @@ example_images: ../test-images/examples/material/golden/macos/time_picker {{ image(example_images + "/basic.png", alt="basic", width="80%") }} +### Hour Format + +```python +--8<-- "{{ examples }}/hour_format.py" +``` + {{ class_members(class_name) }} diff --git a/sdk/python/packages/flet/src/flet/controls/base_page.py b/sdk/python/packages/flet/src/flet/controls/base_page.py index e0dff8dced..366f233de3 100644 --- a/sdk/python/packages/flet/src/flet/controls/base_page.py +++ b/sdk/python/packages/flet/src/flet/controls/base_page.py @@ -317,17 +317,17 @@ def show_dialog(self, dialog: DialogControl) -> None: Displays a dialog and manages its dismissal lifecycle. This method adds the specified `dialog` to the active dialog stack - and renders it on the page. If the dialog is already open, an exception + and renders it on the page. If the dialog is already open, a `RuntimeError` is raised. The [`on_dismiss`][flet.DialogControl.] handler of the dialog is temporarily wrapped to ensure the dialog is removed from the stack and its dismissal event is triggered appropriately. Args: - dialog: The dialog instance to display. Must not already be open. + dialog: The dialog instance to display. Must not yet be open. Raises: - Exception: If the specified dialog is already open. + RuntimeError: If the specified dialog is already open. """ if dialog in self._dialogs.controls: raise RuntimeError("Dialog is already opened") diff --git a/sdk/python/packages/flet/src/flet/controls/material/time_picker.py b/sdk/python/packages/flet/src/flet/controls/material/time_picker.py index 27a518bcc6..6929089298 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/time_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/material/time_picker.py @@ -39,14 +39,51 @@ class TimePickerHourFormat(Enum): class TimePickerEntryMode(Enum): + """ + Interactive input mode of the [`TimePicker`][flet.] dialog. + + In [`DIAL`][(c).] mode, a clock dial is displayed, and the user taps or drags + the time they wish to select. In [`INPUT`][(c).] mode, [`TextField`][flet.]s are + displayed and the user types in the time they wish to select. + """ + DIAL = "dial" + """ + User picks time from a clock dial. + + Can switch to [`INPUT`][(c).] by activating a mode button in the time picker dialog. + """ + INPUT = "input" + """ + User can input the time by typing it into text fields. + + Can switch to [`DIAL`][(c).] by activating a mode button in the time picker dialog. + """ + DIAL_ONLY = "dialOnly" + """ + User can only pick time from a clock dial. + + There is no user interface to switch to another mode. + """ + INPUT_ONLY = "inputOnly" + """ + User can only input the time by typing it into text fields. + + There is no user interface to switch to another mode. + """ class TimePickerEntryModeChangeEvent(Event["TimePicker"]): - entry_mode: Optional[TimePickerEntryMode] + """ + Represents the event triggered when the + entry mode of a [`TimePicker`][flet.] changes. + """ + + entry_mode: TimePickerEntryMode + """The new entry mode.""" @control("TimePicker") @@ -57,7 +94,7 @@ class TimePicker(DialogControl): Can be opened by calling the [`Page.show_dialog()`][flet.Page.show_dialog] method. - Depending on the [`time_picker_entry_mode`][(c).], it will show either a Dial or + Depending on the [`entry_mode`][(c).], it will show either a Dial or an Input (hour and minute text fields) for picking a time. Example: @@ -65,7 +102,7 @@ class TimePicker(DialogControl): ft.TimePicker( open=True, value=time(1, 2), - time_picker_entry_mode=ft.TimePickerEntryMode.INPUT_ONLY, + entry_mode=ft.TimePickerEntryMode.INPUT_ONLY, ) ``` """ @@ -82,7 +119,7 @@ class TimePicker(DialogControl): TBD """ - time_picker_entry_mode: Optional[TimePickerEntryMode] = None + entry_mode: Optional[TimePickerEntryMode] = None """ The initial mode of time entry method for this picker. @@ -147,15 +184,14 @@ class TimePicker(DialogControl): """ Called when user clicks confirm button. - `value` property is updated with selected time. + [`value`][(c).] property is updated with selected time. Additionally, the [`data`][flet.Event.] property of the event handler argument also contains the selected time. """ on_entry_mode_change: Optional[EventHandler[TimePickerEntryModeChangeEvent]] = None """ - Called when the [`time_picker_entry_mode`][(c).] - is changed through the time picker dialog. + Called when the [`entry_mode`][(c).] is changed through the time picker dialog. """ hour_format: TimePickerHourFormat = TimePickerHourFormat.SYSTEM From 287477f73ae4af49e34f63db8b7a3b3e4a62c1d7 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Sat, 8 Nov 2025 00:42:53 +0100 Subject: [PATCH 04/15] `PageMediaData.always_use_24_hour_format` --- packages/flet/lib/src/flet_backend.dart | 12 +++++---- .../lib/src/protocol/page_media_data.dart | 13 ++++++++-- packages/flet/lib/src/widgets/page_media.dart | 1 + .../{hour_format.py => hour_formats.py} | 26 +++++++++++++------ .../packages/flet/docs/controls/timepicker.md | 6 ++--- .../flet/src/flet/controls/base_page.py | 19 +++++++++++++- 6 files changed, 58 insertions(+), 19 deletions(-) rename sdk/python/examples/controls/time_picker/{hour_format.py => hour_formats.py} (62%) diff --git a/packages/flet/lib/src/flet_backend.dart b/packages/flet/lib/src/flet_backend.dart index 08b2318698..5b178fad9a 100644 --- a/packages/flet/lib/src/flet_backend.dart +++ b/packages/flet/lib/src/flet_backend.dart @@ -73,11 +73,13 @@ class FletBackend extends ChangeNotifier { }; Brightness platformBrightness = Brightness.light; PageMediaData media = PageMediaData( - padding: PaddingData(EdgeInsets.zero), - viewPadding: PaddingData(EdgeInsets.zero), - viewInsets: PaddingData(EdgeInsets.zero), - devicePixelRatio: 0, - orientation: Orientation.portrait); + padding: PaddingData(EdgeInsets.zero), + viewPadding: PaddingData(EdgeInsets.zero), + viewInsets: PaddingData(EdgeInsets.zero), + devicePixelRatio: 0, + orientation: Orientation.portrait, + alwaysUse24HourFormat: false, + ); TargetPlatform platform = defaultTargetPlatform; late Control _page; diff --git a/packages/flet/lib/src/protocol/page_media_data.dart b/packages/flet/lib/src/protocol/page_media_data.dart index 7cb5c561ca..52b63f8fce 100644 --- a/packages/flet/lib/src/protocol/page_media_data.dart +++ b/packages/flet/lib/src/protocol/page_media_data.dart @@ -7,6 +7,7 @@ class PageMediaData extends Equatable { final PaddingData viewInsets; final double devicePixelRatio; final Orientation orientation; + final bool alwaysUse24HourFormat; const PageMediaData({ required this.padding, @@ -14,6 +15,7 @@ class PageMediaData extends Equatable { required this.viewInsets, required this.devicePixelRatio, required this.orientation, + required this.alwaysUse24HourFormat, }); Map toMap() => { @@ -22,11 +24,18 @@ class PageMediaData extends Equatable { 'view_insets': viewInsets.toMap(), 'device_pixel_ratio': devicePixelRatio, 'orientation': orientation.name, + 'always_use_24_hour_format': alwaysUse24HourFormat, }; @override - List get props => - [padding, viewPadding, viewInsets, devicePixelRatio, orientation]; + List get props => [ + padding, + viewPadding, + viewInsets, + devicePixelRatio, + orientation, + alwaysUse24HourFormat, + ]; } class PaddingData extends Equatable { diff --git a/packages/flet/lib/src/widgets/page_media.dart b/packages/flet/lib/src/widgets/page_media.dart index d814bdc648..16429cb1c7 100644 --- a/packages/flet/lib/src/widgets/page_media.dart +++ b/packages/flet/lib/src/widgets/page_media.dart @@ -60,6 +60,7 @@ class _PageMediaState extends State { viewInsets: PaddingData(MediaQuery.viewInsetsOf(context)), devicePixelRatio: MediaQuery.devicePixelRatioOf(context), orientation: MediaQuery.orientationOf(context), + alwaysUse24HourFormat: MediaQuery.alwaysUse24HourFormatOf(context), ); if (newMedia != backend.media || !pageSizeUpdated) { diff --git a/sdk/python/examples/controls/time_picker/hour_format.py b/sdk/python/examples/controls/time_picker/hour_formats.py similarity index 62% rename from sdk/python/examples/controls/time_picker/hour_format.py rename to sdk/python/examples/controls/time_picker/hour_formats.py index 7bba5197db..02fcb5b9a4 100644 --- a/sdk/python/examples/controls/time_picker/hour_format.py +++ b/sdk/python/examples/controls/time_picker/hour_formats.py @@ -6,13 +6,20 @@ def main(page: ft.Page): page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - def handle_change(e: ft.Event[ft.TimePicker]): - fmt = ( - "%H:%M" - if time_picker.hour_format == ft.TimePickerHourFormat.H24 - else "%I:%M %p" + def get_system_hour_format(): + """Returns the current system's hour format.""" + return "24h" if page.media.always_use_24_hour_format else "12h" + + def format_time(value: time) -> str: + """Returns a formatted time string based on TimePicker and system settings.""" + use_24h = time_picker.hour_format == ft.TimePickerHourFormat.H24 or ( + time_picker.hour_format == ft.TimePickerHourFormat.SYSTEM + and page.media.always_use_24_hour_format ) - selection.value = f"Selection: {time_picker.value.strftime(fmt)}" + return value.strftime("%H:%M" if use_24h else "%I:%M %p") + + def handle_change(e: ft.Event[ft.TimePicker]): + selection.value = f"Selection: {format_time(time_picker.value)}" time_picker = ft.TimePicker( value=time(hour=9, minute=30), @@ -37,9 +44,12 @@ def open_picker(e: ft.Event[ft.Button]): format_dropdown := ft.Dropdown( label="Hour format", value="system", - width=210, + width=260, options=[ - ft.DropdownOption(key="system", text="System default"), + ft.DropdownOption( + key="system", + text=f"System default ({get_system_hour_format()})", + ), ft.DropdownOption(key="12h", text="12-hour clock"), ft.DropdownOption(key="24h", text="24-hour clock"), ], diff --git a/sdk/python/packages/flet/docs/controls/timepicker.md b/sdk/python/packages/flet/docs/controls/timepicker.md index 1a0e1282e6..9266c3e33d 100644 --- a/sdk/python/packages/flet/docs/controls/timepicker.md +++ b/sdk/python/packages/flet/docs/controls/timepicker.md @@ -16,12 +16,12 @@ example_images: ../test-images/examples/material/golden/macos/time_picker --8<-- "{{ examples }}/basic.py" ``` -{{ image(example_images + "/basic.png", alt="basic", width="80%") }} +{{ image(example_images + "/basic.png", width="80%") }} -### Hour Format +### Hour Formats ```python ---8<-- "{{ examples }}/hour_format.py" +--8<-- "{{ examples }}/hour_formats.py" ``` diff --git a/sdk/python/packages/flet/src/flet/controls/base_page.py b/sdk/python/packages/flet/src/flet/controls/base_page.py index 366f233de3..2136fd9be8 100644 --- a/sdk/python/packages/flet/src/flet/controls/base_page.py +++ b/sdk/python/packages/flet/src/flet/controls/base_page.py @@ -61,7 +61,7 @@ class PageMediaData: view_padding: Padding """ - Similar to `padding`, but includes padding that is always reserved + Similar to [`padding`][(c).], but includes padding that is always reserved (even when the system UI is hidden). """ @@ -81,6 +81,22 @@ class PageMediaData: The orientation of the page. """ + always_use_24_hour_format: bool = False + """ + Whether to use 24-hour format when formatting time. + + Note: + The behavior of this flag is different across platforms: + + - On Android this flag is reported directly from the user settings called + "Use 24-hour format". It applies to any locale used by the application, + whether it is the system-wide locale, or the custom locale set by the + application. + - On iOS this flag is set to true when the user setting called "24-Hour Time" + is set or the system-wide locale's default uses 24-hour + formatting. + """ + @dataclass class PageResizeEvent(Event["BasePage"]): @@ -201,6 +217,7 @@ def handle_page_size(e): view_insets=Padding.zero(), device_pixel_ratio=0, orientation=Orientation.PORTRAIT, + always_use_24_hour_format=False, ) ) """ From d605d5af4689cd140c8aa18c38305609b7c149b1 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Sat, 8 Nov 2025 01:11:32 +0100 Subject: [PATCH 05/15] tests --- packages/flet/lib/src/services/tester.dart | 2 +- .../examples/controls/time_picker/basic.py | 1 + .../controls/time_picker/hour_formats.py | 5 +- .../golden/macos/time_picker/basic.png | Bin 0 -> 59661 bytes .../macos/time_picker/hour_format_12.png | Bin 0 -> 46925 bytes .../macos/time_picker/hour_format_24.png | Bin 0 -> 58127 bytes .../macos/time_picker/time_picker_basic.png | Bin 48204 -> 0 bytes .../controls/material/test_time_picker.py | 58 +++++++++- .../golden/macos/time_picker/basic.png | Bin 22989 -> 33404 bytes .../macos/time_picker/image_for_docs.png | Bin 23771 -> 45552 bytes .../examples/material/test_time_picker.py | 102 ++++++++++++++++-- .../src/flet/controls/material/time_picker.py | 4 +- 12 files changed, 152 insertions(+), 20 deletions(-) create mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/basic.png create mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/hour_format_12.png create mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/hour_format_24.png delete mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/time_picker_basic.png diff --git a/packages/flet/lib/src/services/tester.dart b/packages/flet/lib/src/services/tester.dart index cc5d011ae4..1f70f3fc6d 100644 --- a/packages/flet/lib/src/services/tester.dart +++ b/packages/flet/lib/src/services/tester.dart @@ -49,7 +49,7 @@ class TesterService extends FletService { ? control.backend.globalKeys[controlKey.toString()] : ValueKey(controlKey.value); if (key == null) { - throw Exception("Scroll key not found: $key"); + throw Exception("Key not found: $key"); } var finder = control.backend.tester!.findByKey(key); _finders[finder.id] = finder; diff --git a/sdk/python/examples/controls/time_picker/basic.py b/sdk/python/examples/controls/time_picker/basic.py index 5815c5a90e..e3a4329244 100644 --- a/sdk/python/examples/controls/time_picker/basic.py +++ b/sdk/python/examples/controls/time_picker/basic.py @@ -22,6 +22,7 @@ def handle_entry_mode_change(e: ft.TimePickerEntryModeChangeEvent): confirm_text="Confirm", error_invalid_text="Time out of range", help_text="Pick your time slot", + entry_mode=ft.TimePickerEntryMode.INPUT_ONLY, on_change=handle_change, on_dismiss=handle_dismissal, on_entry_mode_change=handle_entry_mode_change, diff --git a/sdk/python/examples/controls/time_picker/hour_formats.py b/sdk/python/examples/controls/time_picker/hour_formats.py index 02fcb5b9a4..40221fbb20 100644 --- a/sdk/python/examples/controls/time_picker/hour_formats.py +++ b/sdk/python/examples/controls/time_picker/hour_formats.py @@ -45,6 +45,7 @@ def open_picker(e: ft.Event[ft.Button]): label="Hour format", value="system", width=260, + key="dd", options=[ ft.DropdownOption( key="system", @@ -55,7 +56,9 @@ def open_picker(e: ft.Event[ft.Button]): ], ), ft.Button( - "Open TimePicker", icon=ft.Icons.SCHEDULE, on_click=open_picker + "Open TimePicker", + icon=ft.Icons.SCHEDULE, + on_click=open_picker, ), ], ), diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/basic.png new file mode 100644 index 0000000000000000000000000000000000000000..304b461aa18be7369222f903271e5de280030fd6 GIT binary patch literal 59661 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