diff --git a/packages/flet/lib/src/controls/create_control.dart b/packages/flet/lib/src/controls/create_control.dart index e4c66e4f8..83ed6d55c 100644 --- a/packages/flet/lib/src/controls/create_control.dart +++ b/packages/flet/lib/src/controls/create_control.dart @@ -38,10 +38,12 @@ import 'cupertino_checkbox.dart'; import 'cupertino_dialog_action.dart'; import 'cupertino_list_tile.dart'; import 'cupertino_navigation_bar.dart'; +import 'cupertino_picker.dart'; import 'cupertino_radio.dart'; import 'cupertino_slider.dart'; import 'cupertino_switch.dart'; import 'cupertino_textfield.dart'; +import 'cupertino_timer_picker.dart'; import 'datatable.dart'; import 'date_picker.dart'; import 'dismissible.dart'; @@ -484,6 +486,22 @@ Widget createWidget( children: controlView.children, parentDisabled: parentDisabled, backend: backend); + case "cupertinotimerpicker": + return CupertinoTimerPickerControl( + parent: parent, + control: controlView.control, + parentDisabled: parentDisabled, + nextChild: nextChild, + backend: backend); + case "cupertinopicker": + return CupertinoPickerControl( + parent: parent, + control: controlView.control, + children: controlView.children, + parentAdaptive: parentAdaptive, + parentDisabled: parentDisabled, + nextChild: nextChild, + backend: backend); case "draggable": return DraggableControl( key: key, diff --git a/packages/flet/lib/src/controls/cupertino_picker.dart b/packages/flet/lib/src/controls/cupertino_picker.dart new file mode 100644 index 000000000..8f232b47b --- /dev/null +++ b/packages/flet/lib/src/controls/cupertino_picker.dart @@ -0,0 +1,147 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../flet_control_backend.dart'; +import '../models/control.dart'; +import '../utils/colors.dart'; +import 'create_control.dart'; +import 'error.dart'; + +const double _kItemExtent = 32.0; +const double _kDefaultDiameterRatio = 1.07; +const double _kSqueeze = 1.45; + +class CupertinoPickerControl extends StatefulWidget { + final Control? parent; + final Control control; + final List children; + final bool parentDisabled; + final bool? parentAdaptive; + final Widget? nextChild; + final FletControlBackend backend; + + const CupertinoPickerControl( + {super.key, + this.parent, + required this.control, + required this.children, + required this.parentAdaptive, + required this.parentDisabled, + required this.nextChild, + required this.backend}); + + @override + State createState() => _CupertinoPickerControlState(); +} + +class _CupertinoPickerControlState extends State { + Widget _createPicker() { + bool disabled = widget.control.isDisabled || widget.parentDisabled; + + List ctrls = widget.children.where((c) => c.isVisible).map((c) { + return Center( + child: createControl(widget.control, c.id, disabled, + parentAdaptive: widget.parentAdaptive)); + }).toList(); + + double itemExtent = widget.control.attrDouble("itemExtent", _kItemExtent)!; + int? selectedIndex = widget.control.attrInt("selectedIndex"); + double diameterRatio = + widget.control.attrDouble("diameterRatio", _kDefaultDiameterRatio)!; + double magnification = widget.control.attrDouble("magnification", 1.0)!; + double squeeze = widget.control.attrDouble("squeeze", _kSqueeze)!; + double offAxisFraction = widget.control.attrDouble("offAxisFraction", 0.0)!; + bool useMagnifier = widget.control.attrBool("useMagnifier", false)!; + bool looping = widget.control.attrBool("looping", false)!; + Color? backgroundColor = HexColor.fromString( + Theme.of(context), widget.control.attrString("bgColor", "")!); + + Widget picker = CupertinoPicker( + backgroundColor: backgroundColor, + diameterRatio: diameterRatio, + magnification: magnification, + squeeze: squeeze, + offAxisFraction: offAxisFraction, + itemExtent: itemExtent, + useMagnifier: useMagnifier, + looping: looping, + onSelectedItemChanged: (int index) { + widget.backend.updateControlState( + widget.control.id, {"selectedIndex": index.toString()}); + widget.backend + .triggerControlEvent(widget.control.id, "change", index.toString()); + }, + scrollController: selectedIndex != null + ? FixedExtentScrollController(initialItem: selectedIndex) + : null, + children: ctrls, + ); + + return Container( + height: 216, + padding: const EdgeInsets.only(top: 6.0), + // The Bottom margin is provided to align the popup above the system navigation bar. + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + // Provide a background color for the popup. + color: CupertinoColors.systemBackground.resolveFrom(context), + // Use a SafeArea widget to avoid system overlaps. + child: SafeArea( + top: false, + child: picker, + ), + ); + } + + @override + Widget build(BuildContext context) { + debugPrint("CupertinoPicker build: ${widget.control.id}"); + + bool lastOpen = widget.control.state["open"] ?? false; + + var open = widget.control.attrBool("open", false)!; + var modal = widget.control.attrBool("modal", false)!; + + debugPrint("Current open state: $lastOpen"); + debugPrint("New open state: $open"); + + if (open && (open != lastOpen)) { + var dialog = _createPicker(); + if (dialog is ErrorControl) { + return dialog; + } + + // close previous dialog + if (ModalRoute.of(context)?.isCurrent != true) { + Navigator.of(context).pop(); + } + + widget.control.state["open"] = open; + + WidgetsBinding.instance.addPostFrameCallback((_) { + showCupertinoModalPopup( + barrierDismissible: !modal, + useRootNavigator: false, + context: context, + builder: (context) => _createPicker()).then((value) { + lastOpen = widget.control.state["open"] ?? false; + debugPrint("Picker should be dismissed ($hashCode): $lastOpen"); + bool shouldDismiss = lastOpen; + widget.control.state["open"] = false; + + if (shouldDismiss) { + widget.backend + .updateControlState(widget.control.id, {"open": "false"}); + widget.backend + .triggerControlEvent(widget.control.id, "dismiss", ""); + } + }); + }); + } else if (open != lastOpen && lastOpen) { + Navigator.of(context).pop(); + } + + return widget.nextChild ?? const SizedBox.shrink(); + } +} diff --git a/packages/flet/lib/src/controls/cupertino_timer_picker.dart b/packages/flet/lib/src/controls/cupertino_timer_picker.dart new file mode 100644 index 000000000..700a2e216 --- /dev/null +++ b/packages/flet/lib/src/controls/cupertino_timer_picker.dart @@ -0,0 +1,132 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../flet_control_backend.dart'; +import '../models/control.dart'; +import '../utils/alignment.dart'; +import '../utils/colors.dart'; +import 'error.dart'; + +class CupertinoTimerPickerControl extends StatefulWidget { + final Control? parent; + final Control control; + final bool parentDisabled; + final Widget? nextChild; + + final FletControlBackend backend; + + const CupertinoTimerPickerControl( + {super.key, + this.parent, + required this.control, + required this.parentDisabled, + required this.nextChild, + required this.backend}); + + @override + State createState() => + _CupertinoTimerPickerControlState(); +} + +class _CupertinoTimerPickerControlState + extends State { + Widget _createPicker() { + int value = widget.control.attrInt("value", 0)!; + Duration initialTimerDuration = Duration(seconds: value); + int minuteInterval = + widget.control.attrDouble("minuteInterval", 1)!.toInt(); + int secondInterval = + widget.control.attrDouble("secondInterval", 1)!.toInt(); + CupertinoTimerPickerMode mode = CupertinoTimerPickerMode.values.firstWhere( + (a) => + a.name.toLowerCase() == + widget.control.attrString("mode", "")!.toLowerCase(), + orElse: () => CupertinoTimerPickerMode.hms); + + Color? backgroundColor = HexColor.fromString( + Theme.of(context), widget.control.attrString("bgColor", "")!); + + Widget picker = CupertinoTimerPicker( + mode: mode, + initialTimerDuration: initialTimerDuration, + minuteInterval: minuteInterval, + secondInterval: secondInterval, + alignment: + parseAlignment(widget.control, "alignment") ?? Alignment.center, + backgroundColor: backgroundColor, + onTimerDurationChanged: (Duration d) { + widget.backend.updateControlState( + widget.control.id, {"value": d.inSeconds.toString()}); + widget.backend.triggerControlEvent( + widget.control.id, "change", d.inSeconds.toString()); + }, + ); + + return Container( + height: 216, + padding: const EdgeInsets.only(top: 6.0), + // The Bottom margin is provided to align the popup above the system navigation bar. + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + // Provide a background color for the popup. + color: CupertinoColors.systemBackground.resolveFrom(context), + // Use a SafeArea widget to avoid system overlaps. + child: SafeArea( + top: false, + child: picker, + ), + ); + } + + @override + Widget build(BuildContext context) { + debugPrint("CupertinoTimerPicker build: ${widget.control.id}"); + + bool lastOpen = widget.control.state["open"] ?? false; + + var open = widget.control.attrBool("open", false)!; + var modal = widget.control.attrBool("modal", false)!; + + debugPrint("Current open state: $lastOpen"); + debugPrint("New open state: $open"); + + if (open && (open != lastOpen)) { + var dialog = _createPicker(); + if (dialog is ErrorControl) { + return dialog; + } + + // close previous dialog + if (ModalRoute.of(context)?.isCurrent != true) { + Navigator.of(context).pop(); + } + + widget.control.state["open"] = open; + + WidgetsBinding.instance.addPostFrameCallback((_) { + showCupertinoModalPopup( + barrierDismissible: !modal, + useRootNavigator: false, + context: context, + builder: (context) => _createPicker()).then((value) { + lastOpen = widget.control.state["open"] ?? false; + debugPrint("Picker should be dismissed ($hashCode): $lastOpen"); + bool shouldDismiss = lastOpen; + widget.control.state["open"] = false; + + if (shouldDismiss) { + widget.backend + .updateControlState(widget.control.id, {"open": "false"}); + widget.backend + .triggerControlEvent(widget.control.id, "dismiss", ""); + } + }); + }); + } else if (open != lastOpen && lastOpen) { + Navigator.of(context).pop(); + } + + return widget.nextChild ?? const SizedBox.shrink(); + } +} diff --git a/sdk/python/packages/flet-core/src/flet_core/__init__.py b/sdk/python/packages/flet-core/src/flet_core/__init__.py index 2d327c7c8..476dc56b5 100644 --- a/sdk/python/packages/flet-core/src/flet_core/__init__.py +++ b/sdk/python/packages/flet-core/src/flet_core/__init__.py @@ -77,10 +77,15 @@ from flet_core.cupertino_filled_button import CupertinoFilledButton from flet_core.cupertino_list_tile import CupertinoListTile from flet_core.cupertino_navigation_bar import CupertinoNavigationBar +from flet_core.cupertino_picker import CupertinoPicker from flet_core.cupertino_radio import CupertinoRadio from flet_core.cupertino_slider import CupertinoSlider from flet_core.cupertino_switch import CupertinoSwitch from flet_core.cupertino_textfield import CupertinoTextField, VisibilityMode +from flet_core.cupertino_timer_picker import ( + CupertinoTimerPicker, + CupertinoTimerPickerMode, +) from flet_core.datatable import ( DataCell, DataColumn, diff --git a/sdk/python/packages/flet-core/src/flet_core/cupertino_action_sheet.py b/sdk/python/packages/flet-core/src/flet_core/cupertino_action_sheet.py index 59d253439..62fb85595 100644 --- a/sdk/python/packages/flet-core/src/flet_core/cupertino_action_sheet.py +++ b/sdk/python/packages/flet-core/src/flet_core/cupertino_action_sheet.py @@ -1,18 +1,10 @@ from typing import Any, List, Optional, Union -from flet_core.adaptive_control import AdaptiveControl from flet_core.control import Control, OptionalNumber from flet_core.ref import Ref -from flet_core.types import ( - AnimationValue, - OffsetValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -class CupertinoActionSheet(AdaptiveControl): +class CupertinoActionSheet(Control): """ An iOS-style action sheet. @@ -31,13 +23,12 @@ def __init__( open: bool = False, on_dismiss=None, # - # ConstrainedControl and AdaptiveControl + # Control # ref: Optional[Ref] = None, visible: Optional[bool] = None, disabled: Optional[bool] = None, data: Any = None, - adaptive: Optional[bool] = None, ): Control.__init__( self, @@ -47,8 +38,6 @@ def __init__( data=data, ) - AdaptiveControl.__init__(self, adaptive=adaptive) - self.cancel = cancel self.title = title self.message = message diff --git a/sdk/python/packages/flet-core/src/flet_core/cupertino_action_sheet_action.py b/sdk/python/packages/flet-core/src/flet_core/cupertino_action_sheet_action.py index 85c2c0372..49c848aeb 100644 --- a/sdk/python/packages/flet-core/src/flet_core/cupertino_action_sheet_action.py +++ b/sdk/python/packages/flet-core/src/flet_core/cupertino_action_sheet_action.py @@ -1,6 +1,5 @@ from typing import Any, Optional, Union -from flet_core.adaptive_control import AdaptiveControl from flet_core.constrained_control import ConstrainedControl from flet_core.control import Control, OptionalNumber from flet_core.ref import Ref @@ -13,7 +12,7 @@ ) -class CupertinoActionSheetAction(ConstrainedControl, AdaptiveControl): +class CupertinoActionSheetAction(ConstrainedControl): """ An action button typically used in a CupertinoActionSheet. @@ -29,7 +28,7 @@ def __init__( destructive: Optional[bool] = None, on_click=None, # - # ConstrainedControl and AdaptiveControl + # ConstrainedControl # ref: Optional[Ref] = None, key: Optional[str] = None, @@ -58,7 +57,6 @@ def __init__( visible: Optional[bool] = None, disabled: Optional[bool] = None, data: Any = None, - adaptive: Optional[bool] = None, ): ConstrainedControl.__init__( self, @@ -91,8 +89,6 @@ def __init__( data=data, ) - AdaptiveControl.__init__(self, adaptive=adaptive) - self.content = content self.default = default self.destructive = destructive @@ -122,11 +118,11 @@ def default(self, value: Optional[bool]): # destructive @property - def destructive(self) -> Optional[Control]: + def destructive(self) -> Optional[bool]: return self._get_attr("destructive", data_type="bool", def_value=False) @destructive.setter - def destructive(self, value: Optional[Control]): + def destructive(self, value: Optional[bool]): self._set_attr("destructive", value) # content diff --git a/sdk/python/packages/flet-core/src/flet_core/cupertino_picker.py b/sdk/python/packages/flet-core/src/flet_core/cupertino_picker.py new file mode 100644 index 000000000..e38968768 --- /dev/null +++ b/sdk/python/packages/flet-core/src/flet_core/cupertino_picker.py @@ -0,0 +1,199 @@ +from typing import Any, List, Optional, Union + +from flet_core.control import Control, OptionalNumber +from flet_core.ref import Ref + + +class CupertinoPicker(Control): + """ + An iOS-styled picker. + + ----- + + Online docs: https://flet.dev/docs/controls/cupertinopicker + """ + + def __init__( + self, + controls: List[Control], + item_extent: OptionalNumber = None, + selected_index: Optional[int] = None, + bgcolor: Optional[str] = None, + use_magnifier: Optional[bool] = None, + looping: Optional[bool] = None, + magnification: OptionalNumber = None, + squeeze: OptionalNumber = None, + diameter_ratio: OptionalNumber = None, + off_axis_fraction: OptionalNumber = None, + modal: bool = False, + open: bool = False, + on_change=None, + on_dismiss=None, + # + # Control + # + ref: Optional[Ref] = None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + ): + Control.__init__( + self, + ref=ref, + disabled=disabled, + visible=visible, + data=data, + ) + + self.squeeze = squeeze + self.bgcolor = bgcolor + self.on_change = on_change + self.magnification = magnification + self.diameter_ratio = diameter_ratio + self.off_axis_fraction = off_axis_fraction + self.use_magnifier = use_magnifier + self.item_extent = item_extent + self.controls = controls + self.looping = looping + self.selected_index = selected_index + self.modal = modal + self.open = open + self.on_dismiss = on_dismiss + + def _get_control_name(self): + return "cupertinopicker" + + def _get_children(self): + return self.controls + + # squeeze + @property + def squeeze(self) -> OptionalNumber: + return self._get_attr("squeeze", data_type="float", def_value=1.45) + + @squeeze.setter + def squeeze(self, value: OptionalNumber): + if value is not None and value <= 0: + raise ValueError("CupertinoPicker.squeeze must be greater than 0") + self._set_attr("squeeze", value) + + # bgcolor + @property + def bgcolor(self) -> Optional[str]: + return self._get_attr("bgcolor") + + @bgcolor.setter + def bgcolor(self, value: Optional[str]): + self._set_attr("bgcolor", value) + + # use_magnifier + @property + def use_magnifier(self) -> Optional[bool]: + return self._get_attr("useMagnifier", data_type="bool", def_value=False) + + @use_magnifier.setter + def use_magnifier(self, value: Optional[bool]): + self._set_attr("useMagnifier", value) + + # magnification + @property + def magnification(self) -> OptionalNumber: + return self._get_attr("magnification", data_type="float", def_value=1.0) + + @magnification.setter + def magnification(self, value: OptionalNumber): + if value is not None and value <= 0: + raise ValueError("CupertinoPicker.magnification must be greater than 0") + self._set_attr("magnification", value) + + # item_extent + @property + def item_extent(self) -> OptionalNumber: + return self._get_attr("itemExtent", data_type="float") + + @item_extent.setter + def item_extent(self, value: OptionalNumber): + if value is not None and value <= 0: + raise ValueError("CupertinoPicker.item_extent must be greater than 0") + self._set_attr("itemExtent", value) + + # looping + @property + def looping(self) -> Optional[bool]: + return self._get_attr("looping", data_type="bool", def_value=False) + + @looping.setter + def looping(self, value: Optional[bool]): + self._set_attr("looping", value) + + # selected_index + @property + def selected_index(self) -> Optional[int]: + return self._get_attr("selectedIndex", data_type="int", def_value=0) + + @selected_index.setter + def selected_index(self, value: Optional[int]): + self._set_attr("selectedIndex", value) + + # diameter_ratio + @property + def diameter_ratio(self) -> OptionalNumber: + return self._get_attr("diameterRatio", data_type="float", def_value=1.07) + + @diameter_ratio.setter + def diameter_ratio(self, value: OptionalNumber): + self._set_attr("diameterRatio", value) + + # off_axis_fraction + @property + def off_axis_fraction(self) -> OptionalNumber: + return self._get_attr("offAxisFraction", data_type="float", def_value=0.0) + + @off_axis_fraction.setter + def off_axis_fraction(self, value: OptionalNumber): + self._set_attr("offAxisFraction", value) + + # controls + @property + def controls(self): + return self.__controls + + @controls.setter + def controls(self, value: Optional[List[Control]]): + self.__controls = value if value is not None else [] + + # open + @property + def open(self) -> Optional[bool]: + return self._get_attr("open", data_type="bool", def_value=False) + + @open.setter + def open(self, value: Optional[bool]): + self._set_attr("open", value) + + # modal + @property + def modal(self) -> Optional[bool]: + return self._get_attr("modal", data_type="bool", def_value=False) + + @modal.setter + def modal(self, value: Optional[bool]): + self._set_attr("modal", value) + + # on_change + @property + def on_change(self): + return self._get_event_handler("change") + + @on_change.setter + def on_change(self, handler): + self._add_event_handler("change", handler) + + # on_dismiss + @property + def on_dismiss(self): + return self._get_event_handler("dismiss") + + @on_dismiss.setter + def on_dismiss(self, handler): + self._add_event_handler("dismiss", handler) diff --git a/sdk/python/packages/flet-core/src/flet_core/cupertino_timer_picker.py b/sdk/python/packages/flet-core/src/flet_core/cupertino_timer_picker.py new file mode 100644 index 000000000..7db04538a --- /dev/null +++ b/sdk/python/packages/flet-core/src/flet_core/cupertino_timer_picker.py @@ -0,0 +1,151 @@ +from enum import Enum +from typing import Any, Optional, Union + +from flet_core.control import Control, OptionalNumber +from flet_core.ref import Ref +from flet_core.types import ( + AnimationValue, + OffsetValue, + ResponsiveNumber, + RotateValue, + ScaleValue, +) + + +class CupertinoTimerPickerMode(Enum): + HOUR_MINUTE = "hm" + HOUR_MINUTE_SECONDS = "hms" + MINUTE_SECONDS = "ms" + + +class CupertinoTimerPicker(Control): + """ + A countdown timer picker in iOS style. + + It can show a countdown duration with hour, minute and second spinners. The duration is bound between 0 and 23 hours 59 minutes 59 seconds. + + ----- + + Online docs: https://flet.dev/docs/controls/cupertinotimerpicker + """ + + def __init__( + self, + value: Optional[int] = None, + second_interval: OptionalNumber = None, + minute_interval: OptionalNumber = None, + mode: Optional[CupertinoTimerPickerMode] = None, + bgcolor: Optional[str] = None, + modal: bool = False, + open: bool = False, + on_change=None, + on_dismiss=None, + # + # Control + # + ref: Optional[Ref] = None, + visible: Optional[bool] = None, + disabled: Optional[bool] = None, + data: Any = None, + ): + Control.__init__( + self, + ref=ref, + disabled=disabled, + visible=visible, + data=data, + ) + self.value = value + self.mode = mode + self.bgcolor = bgcolor + self.on_change = on_change + self.second_interval = second_interval + self.minute_interval = minute_interval + self.modal = modal + self.open = open + self.on_dismiss = on_dismiss + + def _get_control_name(self): + return "cupertinotimerpicker" + + # value + @property + def value(self) -> Optional[int]: + return self._get_attr("value", data_type="int", def_value=0) + + @value.setter + def value(self, value: Optional[int]): + self._set_attr("value", value) + + # bgcolor + @property + def bgcolor(self) -> Optional[str]: + return self._get_attr("bgcolor") + + @bgcolor.setter + def bgcolor(self, value: Optional[str]): + self._set_attr("bgcolor", value) + + # second_interval + @property + def second_interval(self) -> OptionalNumber: + return self._get_attr("secondInterval", data_type="int", def_value=1) + + @second_interval.setter + def second_interval(self, value: OptionalNumber): + self._set_attr("secondInterval", value) + + # minute_interval + @property + def minute_interval(self) -> OptionalNumber: + return self._get_attr("minuteInterval", data_type="int", def_value=1) + + @minute_interval.setter + def minute_interval(self, value: OptionalNumber): + self._set_attr("minuteInterval", value) + + # mode + @property + def mode(self) -> Optional[CupertinoTimerPickerMode]: + return self.__mode + + @mode.setter + def mode(self, value: Optional[CupertinoTimerPickerMode]): + self.__mode = value + self._set_attr("mode", value.value if value is not None else None) + + # open + @property + def open(self) -> Optional[bool]: + return self._get_attr("open", data_type="bool", def_value=False) + + @open.setter + def open(self, value: Optional[bool]): + self._set_attr("open", value) + + # modal + @property + def modal(self) -> Optional[bool]: + return self._get_attr("modal", data_type="bool", def_value=False) + + @modal.setter + def modal(self, value: Optional[bool]): + self._set_attr("modal", value) + + # on_change + @property + def on_change(self): + return self._get_event_handler("change") + + @on_change.setter + def on_change(self, handler): + self._add_event_handler("change", handler) + + # on_dismiss + @property + def on_dismiss(self): + return self._get_event_handler("dismiss") + + @on_dismiss.setter + def on_dismiss(self, handler): + self._add_event_handler("dismiss", handler) diff --git a/sdk/python/packages/flet-core/src/flet_core/page.py b/sdk/python/packages/flet-core/src/flet_core/page.py index d51ba7750..61d4ca9dc 100644 --- a/sdk/python/packages/flet-core/src/flet_core/page.py +++ b/sdk/python/packages/flet-core/src/flet_core/page.py @@ -27,6 +27,8 @@ from flet_core.cupertino_alert_dialog import CupertinoAlertDialog from flet_core.cupertino_app_bar import CupertinoAppBar from flet_core.cupertino_navigation_bar import CupertinoNavigationBar +from flet_core.cupertino_picker import CupertinoPicker +from flet_core.cupertino_timer_picker import CupertinoTimerPicker from flet_core.event import Event from flet_core.event_handler import EventHandler from flet_core.floating_action_button import FloatingActionButton @@ -985,7 +987,12 @@ async def close_banner_async(self): # # BottomSheet # - def show_bottom_sheet(self, bottom_sheet: Union[BottomSheet, CupertinoActionSheet]): + def show_bottom_sheet( + self, + bottom_sheet: Union[ + BottomSheet, CupertinoActionSheet, CupertinoPicker, CupertinoTimerPicker + ], + ): self.__offstage.bottom_sheet = bottom_sheet self.__offstage.bottom_sheet.open = True self.__offstage.update() @@ -996,7 +1003,10 @@ def show_bottom_sheet(self, bottom_sheet: Union[BottomSheet, CupertinoActionShee delete_version="1.0", ) async def show_bottom_sheet_async( - self, bottom_sheet: Union[BottomSheet, CupertinoActionSheet] + self, + bottom_sheet: Union[ + BottomSheet, CupertinoActionSheet, CupertinoPicker, CupertinoTimerPicker + ], ): self.show_bottom_sheet(bottom_sheet) @@ -1979,11 +1989,24 @@ def dialog(self, value: Union[AlertDialog, CupertinoAlertDialog, None]): # bottom_sheet @property - def bottom_sheet(self) -> Union[BottomSheet, CupertinoActionSheet, None]: + def bottom_sheet( + self, + ) -> Union[ + BottomSheet, CupertinoActionSheet, CupertinoPicker, CupertinoTimerPicker, None + ]: return self.__bottom_sheet @bottom_sheet.setter - def bottom_sheet(self, value: Union[BottomSheet, CupertinoActionSheet, None]): + def bottom_sheet( + self, + value: Union[ + BottomSheet, + CupertinoActionSheet, + CupertinoPicker, + CupertinoTimerPicker, + None, + ], + ): self.__bottom_sheet = value