Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1141ab8f3c | ||
|
|
a130757daa | ||
|
|
cd719cd641 | ||
|
|
4061b4bf73 | ||
|
|
e122cd0bf5 | ||
|
|
2c3e52ba53 | ||
|
|
62af007799 | ||
|
|
8f3afc3bd7 | ||
|
|
e6951b4c25 | ||
|
|
cd97dada2a | ||
|
|
6778b6426f | ||
|
|
1b9e096b77 | ||
|
|
8113ce9c22 | ||
|
|
06de421ee2 | ||
|
|
e7d6735d27 | ||
|
|
79cae9570d |
@@ -4,18 +4,17 @@ import 'relative_time_alarm.dart';
|
||||
|
||||
abstract class Alarm {
|
||||
String get id;
|
||||
String get taskId;
|
||||
AlarmType get alarmType;
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
factory Alarm.fromJson(Map<String, dynamic> json) {
|
||||
if (json.containsKey('alarmType')) {
|
||||
switch (json['alarmType'] as String) {
|
||||
case 'timeFixed':
|
||||
switch (AlarmType.fromJson(json['alarmType'])) {
|
||||
case AlarmType.timeFixed:
|
||||
return FixedTimeAlarm.fromJson(json);
|
||||
case 'timeRelative':
|
||||
case AlarmType.timeRelative:
|
||||
return RelativeTimeAlarm.fromJson(json);
|
||||
case 'location':
|
||||
case AlarmType.location:
|
||||
return LocationAlarm.fromJson(json);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +30,14 @@ abstract class Alarm {
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => taskId.hashCode;
|
||||
int get hashCode => id.hashCode;
|
||||
}
|
||||
|
||||
enum AlarmType { timeFixed, timeRelative, location }
|
||||
enum AlarmType {
|
||||
timeFixed,
|
||||
timeRelative,
|
||||
location;
|
||||
|
||||
String toJson() => name;
|
||||
static AlarmType fromJson(String json) => values.byName(json);
|
||||
}
|
||||
|
||||
@@ -4,24 +4,17 @@ class FixedTimeAlarm implements Alarm {
|
||||
@override
|
||||
final String id;
|
||||
|
||||
@override
|
||||
final String taskId;
|
||||
|
||||
final DateTime triggerAt;
|
||||
|
||||
@override
|
||||
final AlarmType alarmType;
|
||||
|
||||
const FixedTimeAlarm({
|
||||
required this.id,
|
||||
required this.taskId,
|
||||
required this.triggerAt,
|
||||
}) : alarmType = AlarmType.timeFixed;
|
||||
const FixedTimeAlarm({required this.id, required this.triggerAt})
|
||||
: alarmType = AlarmType.timeFixed;
|
||||
|
||||
factory FixedTimeAlarm.fromJson(Map<String, dynamic> json) {
|
||||
return FixedTimeAlarm(
|
||||
id: json['id'] as String,
|
||||
taskId: json['taskId'] as String,
|
||||
triggerAt: DateTime.parse(json['triggerAt'] as String),
|
||||
);
|
||||
}
|
||||
@@ -30,9 +23,8 @@ class FixedTimeAlarm implements Alarm {
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'taskId': taskId,
|
||||
'triggerAt': triggerAt.toIso8601String(),
|
||||
'alarmType': alarmType,
|
||||
'alarmType': alarmType.toJson(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,6 @@ class LocationAlarm implements Alarm {
|
||||
@override
|
||||
final String id;
|
||||
|
||||
@override
|
||||
final String taskId;
|
||||
|
||||
final Location location;
|
||||
|
||||
final int radiusMeters;
|
||||
@@ -17,7 +14,6 @@ class LocationAlarm implements Alarm {
|
||||
|
||||
const LocationAlarm({
|
||||
required this.id,
|
||||
required this.taskId,
|
||||
required this.location,
|
||||
required this.radiusMeters,
|
||||
}) : alarmType = AlarmType.location;
|
||||
@@ -25,7 +21,6 @@ class LocationAlarm implements Alarm {
|
||||
factory LocationAlarm.fromJson(Map<String, dynamic> json) {
|
||||
return LocationAlarm(
|
||||
id: json['id'] as String,
|
||||
taskId: json['taskId'] as String,
|
||||
location: Location.fromJson(json['location'] as Map<String, dynamic>),
|
||||
radiusMeters: json['radiusMeters'] as int,
|
||||
);
|
||||
@@ -35,10 +30,9 @@ class LocationAlarm implements Alarm {
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'taskId': taskId,
|
||||
'location': location.toJson(),
|
||||
'radiusMeters': radiusMeters,
|
||||
'alarmType': alarmType,
|
||||
'alarmType': alarmType.toJson(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,25 +4,18 @@ class RelativeTimeAlarm implements Alarm {
|
||||
@override
|
||||
final String id;
|
||||
|
||||
@override
|
||||
final String taskId;
|
||||
|
||||
final DateTime triggerAt;
|
||||
final Duration triggerAt;
|
||||
|
||||
@override
|
||||
final AlarmType alarmType;
|
||||
|
||||
const RelativeTimeAlarm({
|
||||
required this.id,
|
||||
required this.taskId,
|
||||
required this.triggerAt,
|
||||
}) : alarmType = AlarmType.timeRelative;
|
||||
const RelativeTimeAlarm({required this.id, required this.triggerAt})
|
||||
: alarmType = AlarmType.timeRelative;
|
||||
|
||||
factory RelativeTimeAlarm.fromJson(Map<String, dynamic> json) {
|
||||
return RelativeTimeAlarm(
|
||||
id: json['id'] as String,
|
||||
taskId: json['taskId'] as String,
|
||||
triggerAt: DateTime.parse(json['triggerAt'] as String),
|
||||
triggerAt: Duration(minutes: json['triggerAt'] as int),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,9 +23,8 @@ class RelativeTimeAlarm implements Alarm {
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'taskId': taskId,
|
||||
'triggerAt': triggerAt.toIso8601String(),
|
||||
'alarmType': alarmType,
|
||||
'triggerAt': triggerAt.inMinutes,
|
||||
'alarmType': alarmType.toJson(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import '../alarm/alarm.dart' show AlarmType;
|
||||
import '../alarm/alarm.dart' show AlarmType, Alarm;
|
||||
|
||||
class CreateAlarmRequest {
|
||||
abstract class CreateAlarmRequest {
|
||||
const CreateAlarmRequest({required this.alarmType});
|
||||
|
||||
final AlarmType alarmType;
|
||||
|
||||
Alarm toAlarm(String id);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import '../alarm/alarm.dart';
|
||||
import '../alarm/fixed_time_alarm.dart';
|
||||
import 'create_alarm_request.dart';
|
||||
|
||||
class CreateFixedTimeAlarmRequest extends CreateAlarmRequest {
|
||||
final DateTime? triggerAt;
|
||||
|
||||
CreateFixedTimeAlarmRequest({this.triggerAt})
|
||||
const CreateFixedTimeAlarmRequest({this.triggerAt})
|
||||
: super(alarmType: AlarmType.timeFixed);
|
||||
|
||||
CreateFixedTimeAlarmRequest.fromAlarm(FixedTimeAlarm alarm)
|
||||
: triggerAt = alarm.triggerAt,
|
||||
super(alarmType: AlarmType.timeFixed);
|
||||
|
||||
@override
|
||||
FixedTimeAlarm toAlarm(String id) =>
|
||||
FixedTimeAlarm(id: id, triggerAt: triggerAt!);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import '../alarm/alarm.dart' show AlarmType;
|
||||
import '../alarm/location_alarm.dart';
|
||||
import '../location.dart';
|
||||
import 'create_alarm_request.dart';
|
||||
|
||||
@@ -9,4 +10,13 @@ class CreateLocationAlarmRequest extends CreateAlarmRequest {
|
||||
|
||||
const CreateLocationAlarmRequest({this.location, this.radiusMeters})
|
||||
: super(alarmType: AlarmType.location);
|
||||
|
||||
CreateLocationAlarmRequest.fromAlarm(LocationAlarm alarm)
|
||||
: location = alarm.location,
|
||||
radiusMeters = alarm.radiusMeters,
|
||||
super(alarmType: AlarmType.location);
|
||||
|
||||
@override
|
||||
LocationAlarm toAlarm(String id) =>
|
||||
LocationAlarm(id: id, location: location!, radiusMeters: radiusMeters!);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import '../alarm/alarm.dart' show AlarmType;
|
||||
import '../alarm/relative_time_alarm.dart';
|
||||
import 'create_alarm_request.dart';
|
||||
|
||||
class CreateRelativeTimeAlarmRequest extends CreateAlarmRequest {
|
||||
final DateTime? triggerAt;
|
||||
final Duration? triggerAt;
|
||||
|
||||
CreateRelativeTimeAlarmRequest({this.triggerAt})
|
||||
const CreateRelativeTimeAlarmRequest({this.triggerAt})
|
||||
: super(alarmType: AlarmType.timeRelative);
|
||||
|
||||
CreateRelativeTimeAlarmRequest.fromAlarm(RelativeTimeAlarm alarm)
|
||||
: triggerAt = alarm.triggerAt,
|
||||
super(alarmType: AlarmType.timeRelative);
|
||||
|
||||
@override
|
||||
RelativeTimeAlarm toAlarm(String id) =>
|
||||
RelativeTimeAlarm(id: id, triggerAt: triggerAt!);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import '../alarm/alarm.dart';
|
||||
import '../task.dart';
|
||||
|
||||
class CreateTaskRequest {
|
||||
@@ -9,6 +10,7 @@ class CreateTaskRequest {
|
||||
final String category;
|
||||
final List<Task> subtasks;
|
||||
final String url;
|
||||
final List<Alarm> alarms;
|
||||
|
||||
CreateTaskRequest({
|
||||
required this.title,
|
||||
@@ -19,6 +21,7 @@ class CreateTaskRequest {
|
||||
required this.category,
|
||||
required this.subtasks,
|
||||
required this.url,
|
||||
required this.alarms,
|
||||
});
|
||||
|
||||
CreateTaskRequest.fromTask(Task task)
|
||||
@@ -29,7 +32,8 @@ class CreateTaskRequest {
|
||||
isCompleted = task.isCompleted,
|
||||
category = task.category,
|
||||
subtasks = task.subtasks,
|
||||
url = task.url;
|
||||
url = task.url,
|
||||
alarms = task.alarms;
|
||||
|
||||
Task toTask({required String id}) {
|
||||
return Task(
|
||||
@@ -42,6 +46,7 @@ class CreateTaskRequest {
|
||||
category: category,
|
||||
subtasks: subtasks,
|
||||
url: url,
|
||||
alarms: alarms,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-1
@@ -1,3 +1,4 @@
|
||||
import 'alarm/alarm.dart';
|
||||
import 'location.dart';
|
||||
|
||||
class Task {
|
||||
@@ -10,6 +11,7 @@ class Task {
|
||||
final String category;
|
||||
final List<Task> subtasks;
|
||||
final String url;
|
||||
final List<Alarm> alarms;
|
||||
|
||||
Task({
|
||||
required this.id,
|
||||
@@ -21,6 +23,7 @@ class Task {
|
||||
this.category = '',
|
||||
this.subtasks = const [],
|
||||
this.url = '',
|
||||
required this.alarms,
|
||||
});
|
||||
|
||||
Task copyWith({
|
||||
@@ -32,7 +35,7 @@ class Task {
|
||||
bool? isCompleted,
|
||||
String? category,
|
||||
List<Task>? subtasks,
|
||||
List<DateTime>? alarms,
|
||||
List<Alarm>? alarms,
|
||||
Location? location,
|
||||
String? url,
|
||||
}) {
|
||||
@@ -46,6 +49,7 @@ class Task {
|
||||
category: category ?? this.category,
|
||||
subtasks: subtasks ?? this.subtasks,
|
||||
url: url ?? this.url,
|
||||
alarms: alarms ?? this.alarms,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,6 +70,11 @@ class Task {
|
||||
.toList() ??
|
||||
[],
|
||||
url: json['url'] as String? ?? '',
|
||||
alarms:
|
||||
(json['alarms'] as List<dynamic>?)
|
||||
?.map((e) => Alarm.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,6 +89,7 @@ class Task {
|
||||
'category': category,
|
||||
'subtasks': subtasks.map((e) => e.toJson()).toList(),
|
||||
'url': url,
|
||||
'alarms': alarms.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,13 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../app_theme.dart';
|
||||
import '../model/alarm/alarm.dart';
|
||||
import '../model/alarm/fixed_time_alarm.dart';
|
||||
import '../model/alarm/location_alarm.dart';
|
||||
import '../model/alarm/relative_time_alarm.dart';
|
||||
import '../model/requests/create_alarm_request.dart';
|
||||
import '../model/requests/create_fixed_time_alarm_request.dart';
|
||||
import '../model/requests/create_location_alarm_request.dart';
|
||||
import '../model/requests/create_relative_time_alarm_request.dart';
|
||||
import '../model/requests/create_task_request.dart';
|
||||
import '../model/extensions/controller_context.dart';
|
||||
import '../model/task.dart';
|
||||
@@ -37,7 +41,7 @@ class _TaskEditPageState extends State<TaskEditPage> {
|
||||
final formKey = GlobalKey<FormState>(debugLabel: 'taskEditFormKey');
|
||||
bool didFormChange = false;
|
||||
bool isDueTimeEnabled = false;
|
||||
final List<CreateAlarmRequest> alarms = [];
|
||||
final List<CreateAlarmRequest> alarmRequests = [];
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
@@ -56,6 +60,18 @@ class _TaskEditPageState extends State<TaskEditPage> {
|
||||
isDueTimeEnabled = true;
|
||||
}
|
||||
isInitialized = true;
|
||||
alarmRequests.addAll(
|
||||
task!.alarms.map((alarm) {
|
||||
if (alarm is FixedTimeAlarm) {
|
||||
return CreateFixedTimeAlarmRequest.fromAlarm(alarm);
|
||||
} else if (alarm is RelativeTimeAlarm) {
|
||||
return CreateRelativeTimeAlarmRequest.fromAlarm(alarm);
|
||||
} else if (alarm is LocationAlarm) {
|
||||
return CreateLocationAlarmRequest.fromAlarm(alarm);
|
||||
}
|
||||
throw TypeError();
|
||||
}),
|
||||
);
|
||||
pageTitle = task!.title;
|
||||
}
|
||||
}
|
||||
@@ -151,15 +167,28 @@ class _TaskEditPageState extends State<TaskEditPage> {
|
||||
label: Text('Location'),
|
||||
icon: Icon(Icons.location_on),
|
||||
),
|
||||
for (final (index, alarm) in alarms.indexed)
|
||||
AlarmForm(
|
||||
request: alarm,
|
||||
onChanged: (updated) {
|
||||
setState(() {
|
||||
alarms[index] = updated;
|
||||
});
|
||||
},
|
||||
for (final (index, alarmRequest) in alarmRequests.indexed)
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: AlarmForm(
|
||||
request: alarmRequest,
|
||||
onChanged: (updated) {
|
||||
setState(() {
|
||||
alarmRequests[index] = updated;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => setState(() {
|
||||
alarmRequests.removeAt(index);
|
||||
}),
|
||||
icon: Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 120),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -175,20 +204,34 @@ class _TaskEditPageState extends State<TaskEditPage> {
|
||||
}
|
||||
|
||||
void onSavePressed() {
|
||||
Navigator.of(context).pop(
|
||||
CreateTaskRequest(
|
||||
title: titleController.text,
|
||||
description: descriptionController.text,
|
||||
start: null,
|
||||
due: DateTime.tryParse(
|
||||
'${dueDateController.text} ${dueTimeController.text}'.trim(),
|
||||
if (formKey.currentState!.validate()) {
|
||||
Navigator.of(context).pop(
|
||||
CreateTaskRequest(
|
||||
title: titleController.text,
|
||||
description: descriptionController.text,
|
||||
start: null,
|
||||
due: DateTime.tryParse(
|
||||
'${dueDateController.text} ${dueTimeController.text}'.trim(),
|
||||
),
|
||||
isCompleted: false,
|
||||
category: categoryController.text,
|
||||
subtasks: [],
|
||||
url: urlController.text,
|
||||
alarms: alarmRequests.map<Alarm>((e) {
|
||||
if (e is CreateFixedTimeAlarmRequest) {
|
||||
return e.toAlarm(generateId());
|
||||
}
|
||||
if (e is CreateRelativeTimeAlarmRequest) {
|
||||
return e.toAlarm(generateId());
|
||||
}
|
||||
if (e is LocationAlarm) {
|
||||
return e.toAlarm(generateId());
|
||||
}
|
||||
throw TypeError();
|
||||
}).toList(),
|
||||
),
|
||||
isCompleted: false,
|
||||
category: categoryController.text,
|
||||
subtasks: [],
|
||||
url: urlController.text,
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void onPopInvoked(bool didPop, Object? result) {
|
||||
@@ -222,12 +265,11 @@ class _TaskEditPageState extends State<TaskEditPage> {
|
||||
void onAddAlarmPressed(AlarmType alarmType) {
|
||||
switch (alarmType) {
|
||||
case AlarmType.location:
|
||||
alarms.add(CreateLocationAlarmRequest());
|
||||
alarmRequests.add(CreateLocationAlarmRequest());
|
||||
case AlarmType.timeFixed:
|
||||
alarms.add(CreateFixedTimeAlarmRequest());
|
||||
|
||||
alarmRequests.add(CreateFixedTimeAlarmRequest());
|
||||
case AlarmType.timeRelative:
|
||||
alarms.add(CreateFixedTimeAlarmRequest());
|
||||
alarmRequests.add(CreateRelativeTimeAlarmRequest());
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@@ -26,17 +26,26 @@ class _FixedTimeAlarmFormState extends State<FixedTimeAlarmForm> {
|
||||
bool isDueTimeEnabled = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
void didChangeDependencies() {
|
||||
if (widget.request.triggerAt != null) {
|
||||
dueDateController.text = getIsoDateString(widget.request.triggerAt!);
|
||||
dueTimeController.text = TimeOfDay.fromDateTime(
|
||||
widget.request.triggerAt!,
|
||||
).format(context);
|
||||
isDueTimeEnabled = true;
|
||||
}
|
||||
|
||||
dueDateController.addListener(onDueDateChanged);
|
||||
dueTimeController.addListener(onDueTimeChanged);
|
||||
|
||||
super.initState();
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Flex(
|
||||
direction: Axis.horizontal,
|
||||
spacing: AppTheme.formColumnSpacing,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 3,
|
||||
@@ -61,14 +70,13 @@ class _FixedTimeAlarmFormState extends State<FixedTimeAlarmForm> {
|
||||
icon: Icon(Icons.calendar_month),
|
||||
),
|
||||
),
|
||||
validator: dateTimeValidator,
|
||||
validator: (value) {
|
||||
return notEmptyValidator(value) ?? dateTimeValidator(value);
|
||||
},
|
||||
keyboardType: TextInputType.datetime,
|
||||
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 }
|
||||
|
||||
Reference in New Issue
Block a user