Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions client/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,10 @@ packages:
dependency: transitive
description:
name: plugin_platform_interface
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
url: "https://pub.dev"
source: hosted
version: "2.1.6"
version: "2.1.7"
pointycastle:
dependency: transitive
description:
Expand Down Expand Up @@ -546,10 +546,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
Expand Down Expand Up @@ -663,10 +663,10 @@ packages:
dependency: transitive
description:
name: url_launcher_ios
sha256: "4ac97281cf60e2e8c5cc703b2b28528f9b50c8f7cebc71df6bdf0845f647268a"
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
url: "https://pub.dev"
source: hosted
version: "6.2.0"
version: "6.2.1"
url_launcher_linux:
dependency: transitive
description:
Expand Down Expand Up @@ -807,10 +807,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f"
sha256: adb8c03c2be231bea5a8ed0e9039e9d18dbb049603376beaefa15393ede468a5
url: "https://pub.dev"
source: hosted
version: "2.6.0"
version: "2.7.0"
webview_flutter_wkwebview:
dependency: transitive
description:
Expand Down Expand Up @@ -868,5 +868,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0-194.0.dev <4.0.0"
flutter: ">=3.13.0"
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"
9 changes: 9 additions & 0 deletions package/lib/src/controls/create_control.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import 'column.dart';
import 'container.dart';
import 'datatable.dart';
import 'date_picker.dart';
import 'time_picker.dart';
import 'divider.dart';
import 'drag_target.dart';
import 'draggable.dart';
Expand Down Expand Up @@ -326,6 +327,14 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
parentDisabled: parentDisabled,
dispatch: controlView.dispatch,
);
case "timepicker":
return TimePickerControl(
parent: parent,
control: controlView.control,
children: controlView.children,
parentDisabled: parentDisabled,
dispatch: controlView.dispatch,
);
case "draggable":
return DraggableControl(
key: key,
Expand Down
109 changes: 109 additions & 0 deletions package/lib/src/controls/time_picker.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import 'package:flutter/material.dart';

import '../actions.dart';
import '../flet_app_services.dart';
import '../models/control.dart';
import '../protocol/update_control_props_payload.dart';

class TimePickerControl extends StatefulWidget {
final Control? parent;
final Control control;
final List<Control> children;
final bool parentDisabled;
final dynamic dispatch;

const TimePickerControl({
Key? key,
this.parent,
required this.control,
required this.children,
required this.parentDisabled,
required this.dispatch,
}) : super(key: key);

@override
State<TimePickerControl> createState() => _TimePickerControlState();
}

class _TimePickerControlState extends State<TimePickerControl> {
@override
Widget build(BuildContext context) {
debugPrint("TimePicker build: ${widget.control.id}");

bool lastOpen = widget.control.state["open"] ?? false;

var open = widget.control.attrBool("open", false)!;
TimeOfDay value = widget.control.attrTime("value") ?? TimeOfDay.now();
String? helpText = widget.control.attrString("helpText");
String? cancelText = widget.control.attrString("cancelText");
String? confirmText = widget.control.attrString("confirmText");
String? hourLabelText = widget.control.attrString("hourLabelText");
String? minuteLabelText = widget.control.attrString("minuteLabelText");
String? errorInvalidText = widget.control.attrString("errorInvalidText");
TimePickerEntryMode timePickerEntryMode = TimePickerEntryMode.values
.firstWhere(
(a) =>
a.name.toLowerCase() ==
widget.control
.attrString("timePickerEntryMode", "")!
.toLowerCase(),
orElse: () => TimePickerEntryMode.dial);

void onClosed(TimeOfDay? timeValue) {
String stringValue;
String eventName;
if (timeValue == null) {
String hourString = value.hour.toString();
String minuteString = value.minute.toString();
stringValue = '$hourString:$minuteString';
eventName = "dismiss";
} else {
String hourString = timeValue.hour.toString();
String minuteString = timeValue.minute.toString();
stringValue = '$hourString:$minuteString';
eventName = "change";
}
widget.control.state["open"] = false;
List<Map<String, String>> props = [
{"i": widget.control.id, "value": stringValue, "open": "false"}
];
widget.dispatch(
UpdateControlPropsAction(UpdateControlPropsPayload(props: props)));
FletAppServices.of(context).server.updateControlProps(props: props);

FletAppServices.of(context).server.sendPageEvent(
eventTarget: widget.control.id,
eventName: eventName,
eventData: stringValue);
}

Widget createSelectTimeDialog() {
Widget dialog = TimePickerDialog(
initialTime: value,
helpText: helpText,
cancelText: cancelText,
confirmText: confirmText,
hourLabelText: hourLabelText,
minuteLabelText: minuteLabelText,
errorInvalidText: errorInvalidText,
initialEntryMode: timePickerEntryMode,
);

return dialog;
}

if (open && (open != lastOpen)) {
widget.control.state["open"] = open;

WidgetsBinding.instance.addPostFrameCallback((_) {
showDialog<TimeOfDay>(
context: context,
builder: (context) => createSelectTimeDialog()).then((result) {
debugPrint("pickTime() completed");
onClosed(result);
});
});
}
return const SizedBox.shrink();
}
}
11 changes: 11 additions & 0 deletions package/lib/src/models/control.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';

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

TimeOfDay? attrTime(String name, [TimeOfDay? defValue]) {
var value = attrs[name.toLowerCase()];
if (value == null) {
return defValue;
}
List<String> splitted = value.split(':');
return TimeOfDay(
hour: int.parse(splitted[0]), minute: int.parse(splitted[1]));
}

Control copyWith(
{String? id,
String? pid,
Expand Down
1 change: 1 addition & 0 deletions sdk/python/packages/flet-core/src/flet_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
TextField,
TextOnlyInputFilter,
)
from flet_core.time_picker import TimePicker, TimePickerEntryMode
from flet_core.theme import (
ColorScheme,
PageTransitionsTheme,
Expand Down
2 changes: 1 addition & 1 deletion sdk/python/packages/flet-core/src/flet_core/date_picker.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class DatePicker(Control):

It is added to [`page.overlay`](page#overlay) and called using its `pick_date()` method.

Depending on the `date_picker_mode`, it will show either a Calendar or an Input (TextField) for picking a date.
Depending on the `date_picker_entry_mode`, it will show either a Calendar or an Input (TextField) for picking a date.

Example:
```
Expand Down
Loading