Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CupertinoDatePicker Control #2795

Merged
merged 11 commits into from
Mar 6, 2024
20 changes: 4 additions & 16 deletions packages/flet/lib/src/controls/container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ class ContainerControl extends StatelessWidget with FletStoreMixin {
children.where((c) => c.name == "content" && c.isVisible);
bool ink = control.attrBool("ink", false)!;
bool onClick = control.attrBool("onclick", false)!;
bool onTap = control.attrBool("ontap", false)!;
String url = control.attrString("url", "")!;
String? urlTarget = control.attrString("urlTarget");
bool onLongPress = control.attrBool("onLongPress", false)!;
Expand Down Expand Up @@ -146,7 +145,7 @@ class ContainerControl extends StatelessWidget with FletStoreMixin {

Widget? result;

if ((onTap || onClick || url != "" || onLongPress || onHover) &&
if ((onClick || url != "" || onLongPress || onHover) &&
ink &&
!disabled) {
var ink = Material(
Expand All @@ -156,12 +155,7 @@ class ContainerControl extends StatelessWidget with FletStoreMixin {
// Dummy callback to enable widget
// see https://github.com/flutter/flutter/issues/50116#issuecomment-582047374
// and https://github.com/flutter/flutter/blob/eed80afe2c641fb14b82a22279d2d78c19661787/packages/flutter/lib/src/material/ink_well.dart#L1125-L1129
onTap: onTap
? () {
debugPrint("Container ${control.id} Tap!");
backend.triggerControlEvent(control.id, "tap", "");
}
: null,
onTap: onHover ? () {} : null,
onTapDown: onClick || url != ""
? (details) {
debugPrint("Container ${control.id} clicked!");
Expand Down Expand Up @@ -257,10 +251,10 @@ class ContainerControl extends StatelessWidget with FletStoreMixin {
: null,
child: child);

if ((onTap || onClick || onLongPress || onHover || url != "") &&
if ((onClick || onLongPress || onHover || url != "") &&
!disabled) {
result = MouseRegion(
cursor: onTap || onClick || url != ""
cursor: onClick || url != ""
? SystemMouseCursors.click
: MouseCursor.defer,
onEnter: onHover
Expand All @@ -278,12 +272,6 @@ class ContainerControl extends StatelessWidget with FletStoreMixin {
}
: null,
child: GestureDetector(
onTap: onTap
? () {
debugPrint("Container ${control.id} onTap!");
backend.triggerControlEvent(control.id, "ontap", "");
}
: null,
onTapDown: onClick || url != ""
? (details) {
debugPrint("Container ${control.id} clicked!");
Expand Down
8 changes: 7 additions & 1 deletion packages/flet/lib/src/controls/create_control.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import 'cupertino_button.dart';
import 'cupertino_checkbox.dart';
import 'cupertino_context_menu.dart';
import 'cupertino_context_menu_action.dart';
import 'cupertino_date_picker.dart';
import 'cupertino_dialog_action.dart';
import 'cupertino_list_tile.dart';
import 'cupertino_navigation_bar.dart';
Expand Down Expand Up @@ -494,7 +495,12 @@ Widget createWidget(
return DatePickerControl(
parent: parent,
control: controlView.control,
children: controlView.children,
parentDisabled: parentDisabled,
backend: backend);
case "cupertinodatepicker":
return CupertinoDatePickerControl(
parent: parent,
control: controlView.control,
parentDisabled: parentDisabled,
backend: backend);
case "timepicker":
Expand Down
15 changes: 10 additions & 5 deletions packages/flet/lib/src/controls/cupertino_action_sheet_action.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class CupertinoActionSheetActionControl extends StatelessWidget {
debugPrint("CupertinoActionSheetActionControl build: ${control.id}");
bool disabled = control.isDisabled || parentDisabled;

String text = control.attrString("text", "")!;
var contentCtrls =
children.where((c) => c.name == "content" && c.isVisible);
if (contentCtrls.isEmpty) {
Expand All @@ -37,13 +38,17 @@ class CupertinoActionSheetActionControl extends StatelessWidget {
return constrainedControl(
context,
CupertinoActionSheetAction(
isDefaultAction: control.attrBool("default", false)!,
isDestructiveAction: control.attrBool("destructive", false)!,
isDefaultAction: control.attrBool("isDefaultAction", false)!,
isDestructiveAction: control.attrBool("isDestructiveAction", false)!,
onPressed: () {
backend.triggerControlEvent(control.id, "click", "");
if (!disabled) {
backend.triggerControlEvent(control.id, "click");
}
},
child: createControl(control, contentCtrls.first.id, disabled,
parentAdaptive: parentAdaptive),
child: contentCtrls.isNotEmpty
? createControl(control, contentCtrls.first.id, disabled,
parentAdaptive: parentAdaptive)
: Text(text),
),
parent,
control);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,13 @@ class _CupertinoContextMenuActionControlState
: Text(text, overflow: TextOverflow.ellipsis));

return CupertinoContextMenuAction(
isDefaultAction: widget.control.attrBool("default", false)!,
isDestructiveAction: widget.control.attrBool("destructive", false)!,
isDefaultAction: widget.control.attrBool("isDefaultAction", false)!,
isDestructiveAction:
widget.control.attrBool("isDestructiveAction", false)!,
onPressed: () {
widget.backend.triggerControlEvent(widget.control.id, "click", "");
if (!disabled) {
widget.backend.triggerControlEvent(widget.control.id, "click");
}
},
trailingIcon: trailingIcon,
child: child,
Expand Down
89 changes: 89 additions & 0 deletions packages/flet/lib/src/controls/cupertino_date_picker.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import 'package:collection/collection.dart';
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';

class CupertinoDatePickerControl extends StatefulWidget {
final Control? parent;
final Control control;
final bool parentDisabled;
final FletControlBackend backend;

const CupertinoDatePickerControl(
{super.key,
this.parent,
required this.control,
required this.parentDisabled,
required this.backend});

@override
State<CupertinoDatePickerControl> createState() =>
_CupertinoDatePickerControlState();
}

class _CupertinoDatePickerControlState
extends State<CupertinoDatePickerControl> {
static const double _kItemExtent = 32.0;

@override
Widget build(BuildContext context) {
debugPrint("CupertinoDatePicker build: ${widget.control.id}");

bool showDayOfWeek = widget.control.attrBool("showDayOfWeek", false)!;
Color? bgcolor = HexColor.fromString(
Theme.of(context), widget.control.attrString("bgcolor", "")!);
DateTime? value = widget.control.attrDateTime("value");
DateTime? firstDate = widget.control.attrDateTime("firstDate");
DateTime? lastDate = widget.control.attrDateTime("lastDate");
int minimumYear = widget.control.attrInt("minimumYear", 1)!;
int? maximumYear = widget.control.attrInt("maximumYear");
double itemExtent = widget.control.attrDouble("itemExtent", _kItemExtent)!;
int minuteInterval = widget.control.attrInt("minuteInterval", 1)!;
bool use24hFormat = widget.control.attrBool("use24hFormat", false)!;

DatePickerDateOrder? dateOrder = DatePickerDateOrder.values
.firstWhereOrNull((a) =>
a.name.toLowerCase() ==
widget.control.attrString("dateOrder", "")!.toLowerCase());
CupertinoDatePickerMode datePickerMode = CupertinoDatePickerMode.values
.firstWhere(
(a) =>
a.name.toLowerCase() ==
widget.control.attrString("datePickerMode", "")!.toLowerCase(),
orElse: () => CupertinoDatePickerMode.dateAndTime);

Widget dialog;
try {
dialog = CupertinoDatePicker(
initialDateTime: value,
showDayOfWeek: showDayOfWeek,
minimumDate: firstDate,
maximumDate: lastDate,
backgroundColor: bgcolor,
minimumYear: minimumYear,
maximumYear: maximumYear,
itemExtent: itemExtent,
minuteInterval: minuteInterval,
use24hFormat: use24hFormat,
dateOrder: dateOrder,
mode: datePickerMode,
onDateTimeChanged: (DateTime value) {
String stringValue = value.toIso8601String();
widget.backend
.updateControlState(widget.control.id, {"value": stringValue});
widget.backend
.triggerControlEvent(widget.control.id, "change", stringValue);
},
);
} catch (e) {
return ErrorControl("CupertinoDatePicker Error: ${e.toString()}");
}

return constrainedControl(context, dialog, widget.parent, widget.control);
}
}
2 changes: 0 additions & 2 deletions packages/flet/lib/src/controls/date_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@ import 'form_field.dart';
class DatePickerControl extends StatefulWidget {
final Control? parent;
final Control control;
final List<Control> children;
final bool parentDisabled;
final FletControlBackend backend;

const DatePickerControl(
{super.key,
this.parent,
required this.control,
required this.children,
required this.parentDisabled,
required this.backend});

Expand Down
5 changes: 5 additions & 0 deletions sdk/python/packages/flet-core/src/flet_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@
from flet_core.cupertino_checkbox import CupertinoCheckbox
from flet_core.cupertino_context_menu import CupertinoContextMenu
from flet_core.cupertino_context_menu_action import CupertinoContextMenuAction
from flet_core.cupertino_date_picker import (
CupertinoDatePicker,
CupertinoDatePickerDateOrder,
CupertinoDatePickerMode,
)
from flet_core.cupertino_dialog_action import CupertinoDialogAction
from flet_core.cupertino_filled_button import CupertinoFilledButton
from flet_core.cupertino_list_tile import CupertinoListTile
Expand Down
20 changes: 2 additions & 18 deletions sdk/python/packages/flet-core/src/flet_core/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ def __init__(
url_target: Optional[str] = None,
theme: Optional[Theme] = None,
theme_mode: Optional[ThemeMode] = None,
on_release=None,
on_click=None,
on_long_press=None,
on_hover=None,
Expand Down Expand Up @@ -165,8 +164,6 @@ def convert_container_tap_event_data(e):
d = json.loads(e.data)
return ContainerTapEvent(**d)

self.__on_release = EventHandler(convert_container_tap_event_data)
self._add_event_handler("tap", self.__on_release.get_handler())
self.__on_click = EventHandler(convert_container_tap_event_data)
self._add_event_handler("click", self.__on_click.get_handler())

Expand Down Expand Up @@ -195,7 +192,6 @@ def convert_container_tap_event_data(e):
self.url_target = url_target
self.theme = theme
self.theme_mode = theme_mode
self.on_release = on_release
self.on_click = on_click
self.on_long_press = on_long_press
self.on_hover = on_hover
Expand Down Expand Up @@ -472,16 +468,6 @@ def theme_mode(self, value: Optional[ThemeMode]):
self.__theme_mode = value
self._set_attr("themeMode", value.value if value is not None else None)

# on_release
@property
def on_release(self):
return self._get_event_handler("tap")

@on_release.setter
def on_release(self, handler):
self._add_event_handler("tap", handler)
self._set_attr("onTap", True if handler is not None else None)

# on_click
@property
def on_click(self):
Expand All @@ -490,10 +476,8 @@ def on_click(self):
@on_click.setter
def on_click(self, handler):
self.__on_click.subscribe(handler)
if handler is not None:
self._set_attr("onclick", True)
else:
self._set_attr("onclick", None)
self._set_attr("onClick", True if handler is not None else None)


# on_long_press
@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ class CupertinoActionSheetAction(ConstrainedControl):

def __init__(
self,
content: Control,
default: Optional[bool] = None,
destructive: Optional[bool] = None,
text: Optional[str] = None,
content: Optional[Control] = None,
is_default_action: Optional[bool] = None,
is_destructive_action: Optional[bool] = None,
on_click=None,
#
# ConstrainedControl
Expand Down Expand Up @@ -89,9 +90,10 @@ def __init__(
data=data,
)

self.text = text
self.content = content
self.default = default
self.destructive = destructive
self.is_default_action = is_default_action
self.is_destructive_action = is_destructive_action
self.on_click = on_click

def _get_control_name(self):
Expand All @@ -107,23 +109,32 @@ def _get_children(self):
children.append(self.__content)
return children

# default
# text
@property
def default(self) -> Optional[bool]:
return self._get_attr("default", data_type="bool", def_value=False)
def text(self):
return self._get_attr("text")

@default.setter
def default(self, value: Optional[bool]):
self._set_attr("default", value)
@text.setter
def text(self, value):
self._set_attr("text", value)

# destructive
# is_default_action
@property
def destructive(self) -> Optional[bool]:
return self._get_attr("destructive", data_type="bool", def_value=False)
def is_default_action(self) -> Optional[bool]:
return self._get_attr("isDefaultAction")

@destructive.setter
def destructive(self, value: Optional[bool]):
self._set_attr("destructive", value)
@is_default_action.setter
def is_default_action(self, value: Optional[bool]):
self._set_attr("isDefaultAction", value)

# is_destructive_action
@property
def is_destructive_action(self) -> Optional[bool]:
return self._get_attr("isDestructiveAction")

@is_destructive_action.setter
def is_destructive_action(self, value: Optional[bool]):
self._set_attr("isDestructiveAction", value)

# content
@property
Expand Down
Loading