5 Commits
Author SHA1 Message Date
marco 1141ab8f3c implemented relativetime input widget 2026-07-24 01:44:36 +02:00
marco a130757daa changed to standardized column spacing 2026-07-24 01:21:45 +02:00
marco cd719cd641 changed to correct alarm type 2026-07-24 01:21:25 +02:00
marco 4061b4bf73 fixed json parsing error 2026-07-24 01:21:06 +02:00
marco e122cd0bf5 changed from dateTime to duration 2026-07-21 13:23:04 +02:00
5 changed files with 136 additions and 11 deletions
+3 -3
View File
@@ -4,7 +4,7 @@ class RelativeTimeAlarm implements Alarm {
@override
final String id;
final DateTime triggerAt;
final Duration triggerAt;
@override
final AlarmType alarmType;
@@ -15,7 +15,7 @@ class RelativeTimeAlarm implements Alarm {
factory RelativeTimeAlarm.fromJson(Map<String, dynamic> json) {
return RelativeTimeAlarm(
id: json['id'] as String,
triggerAt: DateTime.parse(json['triggerAt'] as String),
triggerAt: Duration(minutes: json['triggerAt'] as int),
);
}
@@ -23,7 +23,7 @@ class RelativeTimeAlarm implements Alarm {
Map<String, dynamic> toJson() {
return {
'id': id,
'triggerAt': triggerAt.toIso8601String(),
'triggerAt': triggerAt.inMinutes,
'alarmType': alarmType.toJson(),
};
}
@@ -3,7 +3,7 @@ import '../alarm/relative_time_alarm.dart';
import 'create_alarm_request.dart';
class CreateRelativeTimeAlarmRequest extends CreateAlarmRequest {
final DateTime? triggerAt;
final Duration? triggerAt;
const CreateRelativeTimeAlarmRequest({this.triggerAt})
: super(alarmType: AlarmType.timeRelative);
+1 -2
View File
@@ -268,9 +268,8 @@ class _TaskEditPageState extends State<TaskEditPage> {
alarmRequests.add(CreateLocationAlarmRequest());
case AlarmType.timeFixed:
alarmRequests.add(CreateFixedTimeAlarmRequest());
case AlarmType.timeRelative:
alarmRequests.add(CreateFixedTimeAlarmRequest());
alarmRequests.add(CreateRelativeTimeAlarmRequest());
}
setState(() {});
}
@@ -45,6 +45,7 @@ class _FixedTimeAlarmFormState extends State<FixedTimeAlarmForm> {
Widget build(BuildContext context) {
return Flex(
direction: Axis.horizontal,
spacing: AppTheme.formColumnSpacing,
children: [
Flexible(
flex: 3,
@@ -76,9 +77,6 @@ class _FixedTimeAlarmFormState extends State<FixedTimeAlarmForm> {
textInputAction: TextInputAction.next,
),
),
Padding(
padding: EdgeInsetsGeometry.only(left: AppTheme.formColumnSpacing),
),
Flexible(
flex: 2,
child: TextFormField(
@@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import '../../app_theme.dart';
import '../../model/requests/create_alarm_request.dart';
import '../../model/requests/create_relative_time_alarm_request.dart';
import '../../service/validators.dart';
class RelativeTimeAlarmForm extends StatelessWidget {
class RelativeTimeAlarmForm extends StatefulWidget {
const RelativeTimeAlarmForm({
super.key,
required this.request,
@@ -12,8 +14,134 @@ class RelativeTimeAlarmForm extends StatelessWidget {
final CreateRelativeTimeAlarmRequest request;
final ValueChanged<CreateAlarmRequest> onChanged;
@override
State<RelativeTimeAlarmForm> createState() => _RelativeTimeAlarmFormState();
}
class _RelativeTimeAlarmFormState extends State<RelativeTimeAlarmForm> {
final timeController = TextEditingController();
static const List<DropdownMenuEntry<TimeUnit>> timeUnitOptions = [
DropdownMenuEntry<TimeUnit>(value: TimeUnit.minute, label: 'Minutes'),
DropdownMenuEntry<TimeUnit>(value: TimeUnit.hour, label: 'Hours'),
DropdownMenuEntry<TimeUnit>(value: TimeUnit.day, label: 'Days'),
];
static const List<DropdownMenuEntry<TimeRelation>> timeRelationOptions = [
DropdownMenuEntry<TimeRelation>(
value: TimeRelation.before,
label: 'Before',
),
DropdownMenuEntry<TimeRelation>(value: TimeRelation.after, label: 'After'),
];
late TimeUnit selectedTimeUnit;
late TimeRelation selectedTimeRelation;
@override
void initState() {
super.initState();
if (widget.request.triggerAt == null) {
selectedTimeUnit = TimeUnit.minute;
selectedTimeRelation = TimeRelation.before;
return;
}
final duration = widget.request.triggerAt!;
selectedTimeRelation = duration.isNegative
? TimeRelation.before
: TimeRelation.after;
final absDuration = duration.abs();
if (absDuration.inMinutes <= 99 && absDuration.inMinutes % 60 != 0) {
selectedTimeUnit = TimeUnit.minute;
timeController.text = absDuration.inMinutes.toString();
} else if (absDuration.inHours <= 99 && absDuration.inHours % 24 != 0) {
selectedTimeUnit = TimeUnit.hour;
timeController.text = absDuration.inHours.toString();
} else {
selectedTimeUnit = TimeUnit.day;
timeController.text = absDuration.inDays.toString();
}
}
@override
Widget build(BuildContext context) {
return const Placeholder();
return Flex(
direction: Axis.horizontal,
spacing: AppTheme.formColumnSpacing,
children: [
Flexible(
flex: 7,
child: TextFormField(
controller: timeController,
maxLength: 2,
onChanged: onTimeChanged,
validator: (value) =>
notEmptyValidator(value) ?? wholeNumberValidator(value),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
decoration: InputDecoration(label: Text('Time'), counterText: ''),
),
),
Flexible(
flex: 10,
child: DropdownMenuFormField<TimeUnit>(
dropdownMenuEntries: timeUnitOptions,
initialSelection: selectedTimeUnit,
showTrailingIcon: false,
onSelected: (value) {
selectedTimeUnit = value!;
onTimeChanged(timeController.text);
},
),
),
Flexible(
flex: 10,
child: DropdownMenuFormField<TimeRelation>(
dropdownMenuEntries: timeRelationOptions,
initialSelection: selectedTimeRelation,
showTrailingIcon: false,
onSelected: (value) {
selectedTimeRelation = value!;
onTimeChanged(timeController.text);
},
),
),
],
);
}
void onTimeChanged(String value) {
int? time = int.tryParse(value);
if (wholeNumberValidator(value) != null || time == null) return;
Duration duration;
int signedTime = selectedTimeRelation.apply(time);
switch (selectedTimeUnit) {
case TimeUnit.minute:
duration = Duration(minutes: signedTime);
case TimeUnit.hour:
duration = Duration(hours: signedTime);
case TimeUnit.day:
duration = Duration(days: signedTime);
}
widget.onChanged(CreateRelativeTimeAlarmRequest(triggerAt: duration));
}
}
enum TimeRelation {
before,
after;
int apply(int value) => switch (this) {
TimeRelation.before => -value,
TimeRelation.after => value,
};
}
enum TimeUnit { minute, hour, day }