Skip to content

Commit 04c9bb4

Browse files
authored
Time picker control (#2129)
* time_picker.dart initial version * time_picker.py initial commit * time_picker_entry_mode property * value error fixed for on_change * fixed value for on_dismiss * hour_label_text and minute_label_text * remove commented code * refactor * example code added * removed commented line
1 parent 2c8be84 commit 04c9bb4

File tree

7 files changed

+372
-11
lines changed

7 files changed

+372
-11
lines changed

client/pubspec.lock

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,10 @@ packages:
434434
dependency: transitive
435435
description:
436436
name: plugin_platform_interface
437-
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
437+
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
438438
url: "https://pub.dev"
439439
source: hosted
440-
version: "2.1.6"
440+
version: "2.1.7"
441441
pointycastle:
442442
dependency: transitive
443443
description:
@@ -546,10 +546,10 @@ packages:
546546
dependency: transitive
547547
description:
548548
name: shared_preferences_web
549-
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
549+
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
550550
url: "https://pub.dev"
551551
source: hosted
552-
version: "2.2.1"
552+
version: "2.2.2"
553553
shared_preferences_windows:
554554
dependency: transitive
555555
description:
@@ -663,10 +663,10 @@ packages:
663663
dependency: transitive
664664
description:
665665
name: url_launcher_ios
666-
sha256: "4ac97281cf60e2e8c5cc703b2b28528f9b50c8f7cebc71df6bdf0845f647268a"
666+
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
667667
url: "https://pub.dev"
668668
source: hosted
669-
version: "6.2.0"
669+
version: "6.2.1"
670670
url_launcher_linux:
671671
dependency: transitive
672672
description:
@@ -807,10 +807,10 @@ packages:
807807
dependency: transitive
808808
description:
809809
name: webview_flutter_platform_interface
810-
sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f"
810+
sha256: adb8c03c2be231bea5a8ed0e9039e9d18dbb049603376beaefa15393ede468a5
811811
url: "https://pub.dev"
812812
source: hosted
813-
version: "2.6.0"
813+
version: "2.7.0"
814814
webview_flutter_wkwebview:
815815
dependency: transitive
816816
description:
@@ -868,5 +868,5 @@ packages:
868868
source: hosted
869869
version: "3.1.2"
870870
sdks:
871-
dart: ">=3.2.0-194.0.dev <4.0.0"
872-
flutter: ">=3.13.0"
871+
dart: ">=3.2.0 <4.0.0"
872+
flutter: ">=3.16.0"

package/lib/src/controls/create_control.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import 'column.dart';
2929
import 'container.dart';
3030
import 'datatable.dart';
3131
import 'date_picker.dart';
32+
import 'time_picker.dart';
3233
import 'divider.dart';
3334
import 'drag_target.dart';
3435
import 'draggable.dart';
@@ -326,6 +327,14 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
326327
parentDisabled: parentDisabled,
327328
dispatch: controlView.dispatch,
328329
);
330+
case "timepicker":
331+
return TimePickerControl(
332+
parent: parent,
333+
control: controlView.control,
334+
children: controlView.children,
335+
parentDisabled: parentDisabled,
336+
dispatch: controlView.dispatch,
337+
);
329338
case "draggable":
330339
return DraggableControl(
331340
key: key,
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import 'package:flutter/material.dart';
2+
3+
import '../actions.dart';
4+
import '../flet_app_services.dart';
5+
import '../models/control.dart';
6+
import '../protocol/update_control_props_payload.dart';
7+
8+
class TimePickerControl extends StatefulWidget {
9+
final Control? parent;
10+
final Control control;
11+
final List<Control> children;
12+
final bool parentDisabled;
13+
final dynamic dispatch;
14+
15+
const TimePickerControl({
16+
Key? key,
17+
this.parent,
18+
required this.control,
19+
required this.children,
20+
required this.parentDisabled,
21+
required this.dispatch,
22+
}) : super(key: key);
23+
24+
@override
25+
State<TimePickerControl> createState() => _TimePickerControlState();
26+
}
27+
28+
class _TimePickerControlState extends State<TimePickerControl> {
29+
@override
30+
Widget build(BuildContext context) {
31+
debugPrint("TimePicker build: ${widget.control.id}");
32+
33+
bool lastOpen = widget.control.state["open"] ?? false;
34+
35+
var open = widget.control.attrBool("open", false)!;
36+
TimeOfDay value = widget.control.attrTime("value") ?? TimeOfDay.now();
37+
String? helpText = widget.control.attrString("helpText");
38+
String? cancelText = widget.control.attrString("cancelText");
39+
String? confirmText = widget.control.attrString("confirmText");
40+
String? hourLabelText = widget.control.attrString("hourLabelText");
41+
String? minuteLabelText = widget.control.attrString("minuteLabelText");
42+
String? errorInvalidText = widget.control.attrString("errorInvalidText");
43+
TimePickerEntryMode timePickerEntryMode = TimePickerEntryMode.values
44+
.firstWhere(
45+
(a) =>
46+
a.name.toLowerCase() ==
47+
widget.control
48+
.attrString("timePickerEntryMode", "")!
49+
.toLowerCase(),
50+
orElse: () => TimePickerEntryMode.dial);
51+
52+
void onClosed(TimeOfDay? timeValue) {
53+
String stringValue;
54+
String eventName;
55+
if (timeValue == null) {
56+
String hourString = value.hour.toString();
57+
String minuteString = value.minute.toString();
58+
stringValue = '$hourString:$minuteString';
59+
eventName = "dismiss";
60+
} else {
61+
String hourString = timeValue.hour.toString();
62+
String minuteString = timeValue.minute.toString();
63+
stringValue = '$hourString:$minuteString';
64+
eventName = "change";
65+
}
66+
widget.control.state["open"] = false;
67+
List<Map<String, String>> props = [
68+
{"i": widget.control.id, "value": stringValue, "open": "false"}
69+
];
70+
widget.dispatch(
71+
UpdateControlPropsAction(UpdateControlPropsPayload(props: props)));
72+
FletAppServices.of(context).server.updateControlProps(props: props);
73+
74+
FletAppServices.of(context).server.sendPageEvent(
75+
eventTarget: widget.control.id,
76+
eventName: eventName,
77+
eventData: stringValue);
78+
}
79+
80+
Widget createSelectTimeDialog() {
81+
Widget dialog = TimePickerDialog(
82+
initialTime: value,
83+
helpText: helpText,
84+
cancelText: cancelText,
85+
confirmText: confirmText,
86+
hourLabelText: hourLabelText,
87+
minuteLabelText: minuteLabelText,
88+
errorInvalidText: errorInvalidText,
89+
initialEntryMode: timePickerEntryMode,
90+
);
91+
92+
return dialog;
93+
}
94+
95+
if (open && (open != lastOpen)) {
96+
widget.control.state["open"] = open;
97+
98+
WidgetsBinding.instance.addPostFrameCallback((_) {
99+
showDialog<TimeOfDay>(
100+
context: context,
101+
builder: (context) => createSelectTimeDialog()).then((result) {
102+
debugPrint("pickTime() completed");
103+
onClosed(result);
104+
});
105+
});
106+
}
107+
return const SizedBox.shrink();
108+
}
109+
}

package/lib/src/models/control.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:equatable/equatable.dart';
2+
import 'package:flutter/material.dart';
23

34
class Control extends Equatable {
45
static const reservedProps = ['i', 'p', 't', 'c', 'n'];
@@ -96,6 +97,16 @@ class Control extends Equatable {
9697
return DateTime.parse(value);
9798
}
9899

100+
TimeOfDay? attrTime(String name, [TimeOfDay? defValue]) {
101+
var value = attrs[name.toLowerCase()];
102+
if (value == null) {
103+
return defValue;
104+
}
105+
List<String> splitted = value.split(':');
106+
return TimeOfDay(
107+
hour: int.parse(splitted[0]), minute: int.parse(splitted[1]));
108+
}
109+
99110
Control copyWith(
100111
{String? id,
101112
String? pid,

sdk/python/packages/flet-core/src/flet_core/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@
177177
TextField,
178178
TextOnlyInputFilter,
179179
)
180+
from flet_core.time_picker import TimePicker, TimePickerEntryMode
180181
from flet_core.theme import (
181182
ColorScheme,
182183
PageTransitionsTheme,

sdk/python/packages/flet-core/src/flet_core/date_picker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class DatePicker(Control):
3232
3333
It is added to [`page.overlay`](page#overlay) and called using its `pick_date()` method.
3434
35-
Depending on the `date_picker_mode`, it will show either a Calendar or an Input (TextField) for picking a date.
35+
Depending on the `date_picker_entry_mode`, it will show either a Calendar or an Input (TextField) for picking a date.
3636
3737
Example:
3838
```

0 commit comments

Comments
 (0)