validate time periods for bolus and basal and make auto suggestions
This commit is contained in:
parent
db023a94cf
commit
53fb4ac7fc
@ -1,5 +1,5 @@
|
||||
import 'package:diameter/utils/date_time_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:diameter/utils/date_time_utils.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
|
||||
import 'package:diameter/models/basal_profile.dart';
|
||||
import 'package:diameter/components/data_table.dart';
|
||||
@ -14,8 +14,8 @@ class Basal extends DataTableContent {
|
||||
Basal(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
startTime = object.get<DateTime>('startTime')!;
|
||||
endTime = object.get<DateTime>('endTime')!;
|
||||
startTime = object.get<DateTime>('startTime')!.toLocal();
|
||||
endTime = object.get<DateTime>('endTime')!.toLocal();
|
||||
units = object.get<num>('units')! / 100;
|
||||
basalProfile =
|
||||
object.get<ParseObject>('basalProfile')!.get<String>('objectId')!;
|
||||
@ -40,7 +40,8 @@ class Basal extends DataTableContent {
|
||||
..whereEqualTo(
|
||||
'basalProfile',
|
||||
(ParseObject('BasalProfile')..objectId = basalProfile.objectId!)
|
||||
.toPointer());
|
||||
.toPointer())
|
||||
..orderByAscending('startTime');
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
@ -57,8 +58,8 @@ class Basal extends DataTableContent {
|
||||
required String basalProfile,
|
||||
}) async {
|
||||
final basal = ParseObject('Basal')
|
||||
..set('startTime', startTime)
|
||||
..set('endTime', endTime)
|
||||
..set('startTime', startTime.toUtc())
|
||||
..set('endTime', endTime.toUtc())
|
||||
..set('units', units * 100)
|
||||
..set('basalProfile',
|
||||
(ParseObject('BasalProfile')..objectId = basalProfile).toPointer());
|
||||
@ -73,10 +74,10 @@ class Basal extends DataTableContent {
|
||||
}) async {
|
||||
var basal = ParseObject('Basal')..objectId = objectId;
|
||||
if (startTime != null) {
|
||||
basal.set('startTime', startTime);
|
||||
basal.set('startTime', startTime.toUtc());
|
||||
}
|
||||
if (endTime != null) {
|
||||
basal.set('endTime', endTime);
|
||||
basal.set('endTime', endTime.toUtc());
|
||||
}
|
||||
if (units != null) {
|
||||
basal.set('units', units * 100);
|
||||
@ -88,27 +89,27 @@ class Basal extends DataTableContent {
|
||||
var basal = ParseObject('Basal')..objectId = objectId;
|
||||
await basal.delete();
|
||||
}
|
||||
|
||||
@override
|
||||
List<DataCell> asDataTableCells(List<Widget>? actions) {
|
||||
return [
|
||||
DataCell(Text(DateTimeUtils.displayTime(startTime))),
|
||||
DataCell(Text(DateTimeUtils.displayTime(endTime))),
|
||||
DataCell(Text('${units.toString()} U')),
|
||||
DataCell(
|
||||
Row(
|
||||
children: actions ?? [],
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
static List<DataColumn> asDataTableColumns() {
|
||||
return [
|
||||
const DataColumn(label: Expanded(child: Text('Start Time'))),
|
||||
const DataColumn(label: Expanded(child: Text('End Time'))),
|
||||
const DataColumn(label: Expanded(child: Text('Units'))),
|
||||
const DataColumn(label: Expanded(child: Text('Actions'))),
|
||||
];
|
||||
}
|
||||
//
|
||||
// @override
|
||||
// List<DataCell> asDataTableCells(List<Widget>? actions) {
|
||||
// return [
|
||||
// DataCell(Text(DateTimeUtils.displayTime(startTime))),
|
||||
// DataCell(Text(DateTimeUtils.displayTime(endTime))),
|
||||
// DataCell(Text('${units.toString()} U')),
|
||||
// DataCell(
|
||||
// Row(
|
||||
// children: actions ?? [],
|
||||
// ),
|
||||
// ),
|
||||
// ];
|
||||
// }
|
||||
//
|
||||
// static List<DataColumn> asDataTableColumns() {
|
||||
// return [
|
||||
// const DataColumn(label: Expanded(child: Text('Start Time'))),
|
||||
// const DataColumn(label: Expanded(child: Text('End Time'))),
|
||||
// const DataColumn(label: Expanded(child: Text('Units'))),
|
||||
// const DataColumn(label: Expanded(child: Text('Actions'))),
|
||||
// ];
|
||||
// }
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:diameter/config.dart';
|
||||
import 'package:diameter/settings.dart';
|
||||
import 'package:diameter/utils/date_time_utils.dart';
|
||||
// import 'package:diameter/config.dart';
|
||||
// import 'package:diameter/settings.dart';
|
||||
// import 'package:diameter/utils/date_time_utils.dart';
|
||||
import 'package:diameter/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
|
||||
import 'package:diameter/components/data_table.dart';
|
||||
import 'package:diameter/models/bolus_profile.dart';
|
||||
@ -20,8 +20,8 @@ class Bolus extends DataTableContent {
|
||||
Bolus(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
startTime = object.get<DateTime>('startTime')!;
|
||||
endTime = object.get<DateTime>('endTime')!;
|
||||
startTime = object.get<DateTime>('startTime')!.toLocal();
|
||||
endTime = object.get<DateTime>('endTime')!.toLocal();
|
||||
units = object.get<num>('units')! / 100;
|
||||
carbs = object.get<num>('carbs')!.toDouble();
|
||||
mgPerDl = object.get<num>('mgPerDl') != null
|
||||
@ -39,6 +39,7 @@ class Bolus extends DataTableContent {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('Bolus'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
@ -53,7 +54,8 @@ class Bolus extends DataTableContent {
|
||||
..whereEqualTo(
|
||||
'bolusProfile',
|
||||
(ParseObject('BolusProfile')..objectId = bolusProfile.objectId!)
|
||||
.toPointer());
|
||||
.toPointer())
|
||||
..orderByAscending('startTime');
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
@ -73,8 +75,8 @@ class Bolus extends DataTableContent {
|
||||
required String bolusProfile,
|
||||
}) async {
|
||||
final bolus = ParseObject('Bolus')
|
||||
..set('startTime', startTime)
|
||||
..set('endTime', endTime)
|
||||
..set('startTime', startTime.toUtc())
|
||||
..set('endTime', endTime.toUtc())
|
||||
..set('units', units * 100)
|
||||
..set('carbs', carbs.round())
|
||||
..set('bolusProfile',
|
||||
@ -105,10 +107,10 @@ class Bolus extends DataTableContent {
|
||||
}) async {
|
||||
var bolus = ParseObject('Bolus')..objectId = objectId;
|
||||
if (startTime != null) {
|
||||
bolus.set('startTime', startTime);
|
||||
bolus.set('startTime', startTime.toUtc());
|
||||
}
|
||||
if (endTime != null) {
|
||||
bolus.set('endTime', endTime);
|
||||
bolus.set('endTime', endTime.toUtc());
|
||||
}
|
||||
if (units != null) {
|
||||
bolus.set('units', units * 100);
|
||||
@ -137,63 +139,63 @@ class Bolus extends DataTableContent {
|
||||
var bolus = ParseObject('Bolus')..objectId = objectId;
|
||||
await bolus.delete();
|
||||
}
|
||||
|
||||
@override
|
||||
List<DataCell> asDataTableCells(List<Widget>? actions) {
|
||||
var cols = [
|
||||
DataCell(Text(DateTimeUtils.displayTime(startTime))),
|
||||
DataCell(Text(DateTimeUtils.displayTime(endTime))),
|
||||
DataCell(Text('${units.toString()} U')),
|
||||
DataCell(Text('${carbs.toString()} g')),
|
||||
];
|
||||
|
||||
if (glucoseMeasurement == GlucoseMeasurement.mgPerDl ||
|
||||
glucoseDisplayMode == GlucoseDisplayMode.both ||
|
||||
glucoseDisplayMode == GlucoseDisplayMode.bothForList) {
|
||||
cols.add(DataCell(Text('${mgPerDl.toString()} mg/dl')));
|
||||
}
|
||||
|
||||
if (glucoseMeasurement == GlucoseMeasurement.mmolPerL ||
|
||||
glucoseDisplayMode == GlucoseDisplayMode.both ||
|
||||
glucoseDisplayMode == GlucoseDisplayMode.bothForList) {
|
||||
cols.add(DataCell(Text('${mmolPerL.toString()} mmol/l')));
|
||||
}
|
||||
|
||||
cols.add(
|
||||
DataCell(
|
||||
Row(
|
||||
children: actions ?? [],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return cols;
|
||||
}
|
||||
|
||||
static List<DataColumn> asDataTableColumns() {
|
||||
var cols = [
|
||||
const DataColumn(label: Expanded(child: Text('Start Time'))),
|
||||
const DataColumn(label: Expanded(child: Text('End Time'))),
|
||||
const DataColumn(label: Expanded(child: Text('Units'))),
|
||||
const DataColumn(label: Expanded(child: Text('per Carbs'))),
|
||||
];
|
||||
|
||||
if (glucoseMeasurement == GlucoseMeasurement.mgPerDl ||
|
||||
glucoseDisplayMode == GlucoseDisplayMode.both ||
|
||||
glucoseDisplayMode == GlucoseDisplayMode.bothForList) {
|
||||
cols.add(const DataColumn(label: Expanded(child: Text('per mg/dl'))));
|
||||
}
|
||||
|
||||
if (glucoseMeasurement == GlucoseMeasurement.mmolPerL ||
|
||||
glucoseDisplayMode == GlucoseDisplayMode.both ||
|
||||
glucoseDisplayMode == GlucoseDisplayMode.bothForList) {
|
||||
cols.add(const DataColumn(label: Expanded(child: Text('per mmol/l'))));
|
||||
}
|
||||
|
||||
cols.add(
|
||||
const DataColumn(label: Expanded(child: Text('Actions'))),
|
||||
);
|
||||
|
||||
return cols;
|
||||
}
|
||||
//
|
||||
// @override
|
||||
// List<DataCell> asDataTableCells(List<Widget>? actions) {
|
||||
// var cols = [
|
||||
// DataCell(Text(DateTimeUtils.displayTime(startTime))),
|
||||
// DataCell(Text(DateTimeUtils.displayTime(endTime))),
|
||||
// DataCell(Text('${units.toString()} U')),
|
||||
// DataCell(Text('${carbs.toString()} g')),
|
||||
// ];
|
||||
//
|
||||
// if (glucoseMeasurement == GlucoseMeasurement.mgPerDl ||
|
||||
// glucoseDisplayMode == GlucoseDisplayMode.both ||
|
||||
// glucoseDisplayMode == GlucoseDisplayMode.bothForList) {
|
||||
// cols.add(DataCell(Text('${mgPerDl.toString()} mg/dl')));
|
||||
// }
|
||||
//
|
||||
// if (glucoseMeasurement == GlucoseMeasurement.mmolPerL ||
|
||||
// glucoseDisplayMode == GlucoseDisplayMode.both ||
|
||||
// glucoseDisplayMode == GlucoseDisplayMode.bothForList) {
|
||||
// cols.add(DataCell(Text('${mmolPerL.toString()} mmol/l')));
|
||||
// }
|
||||
//
|
||||
// cols.add(
|
||||
// DataCell(
|
||||
// Row(
|
||||
// children: actions ?? [],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
//
|
||||
// return cols;
|
||||
// }
|
||||
//
|
||||
// static List<DataColumn> asDataTableColumns() {
|
||||
// var cols = [
|
||||
// const DataColumn(label: Expanded(child: Text('Start Time'))),
|
||||
// const DataColumn(label: Expanded(child: Text('End Time'))),
|
||||
// const DataColumn(label: Expanded(child: Text('Units'))),
|
||||
// const DataColumn(label: Expanded(child: Text('per Carbs'))),
|
||||
// ];
|
||||
//
|
||||
// if (glucoseMeasurement == GlucoseMeasurement.mgPerDl ||
|
||||
// glucoseDisplayMode == GlucoseDisplayMode.both ||
|
||||
// glucoseDisplayMode == GlucoseDisplayMode.bothForList) {
|
||||
// cols.add(const DataColumn(label: Expanded(child: Text('per mg/dl'))));
|
||||
// }
|
||||
//
|
||||
// if (glucoseMeasurement == GlucoseMeasurement.mmolPerL ||
|
||||
// glucoseDisplayMode == GlucoseDisplayMode.both ||
|
||||
// glucoseDisplayMode == GlucoseDisplayMode.bothForList) {
|
||||
// cols.add(const DataColumn(label: Expanded(child: Text('per mmol/l'))));
|
||||
// }
|
||||
//
|
||||
// cols.add(
|
||||
// const DataColumn(label: Expanded(child: Text('Actions'))),
|
||||
// );
|
||||
//
|
||||
// return cols;
|
||||
// }
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class LogEntry {
|
||||
|
||||
LogEntry(ParseObject object) {
|
||||
objectId = object.get<String>('objectId');
|
||||
time = object.get<DateTime>('time')!;
|
||||
time = object.get<DateTime>('time')!.toLocal();
|
||||
mgPerDl = object.get<num>('mgPerDl') != null
|
||||
? object.get<num>('mgPerDl')!.toInt()
|
||||
: null;
|
||||
@ -58,8 +58,8 @@ class LogEntry {
|
||||
static Future<List<LogEntry>> fetchAllForRange(DateTimeRange range) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('LogEntry'))
|
||||
..whereGreaterThanOrEqualsTo('time', range.start)
|
||||
..whereLessThanOrEqualTo('time', range.end)
|
||||
..whereGreaterThanOrEqualsTo('time', range.start.toUtc())
|
||||
..whereLessThanOrEqualTo('time', range.end.toUtc())
|
||||
..orderByAscending('time');
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
@ -110,7 +110,7 @@ class LogEntry {
|
||||
String? notes,
|
||||
}) async {
|
||||
final logEntry = ParseObject('LogEntry')
|
||||
..set('time', time)
|
||||
..set('time', time.toUtc())
|
||||
..set('bolusGlucose', bolusGlucose)
|
||||
..set('delayedBolusDuration', delayedBolusDuration)
|
||||
..set('delayedBolusRatio', delayedBolusRatio)
|
||||
@ -145,7 +145,7 @@ class LogEntry {
|
||||
final logEntry = ParseObject('LogEntry');
|
||||
|
||||
if (time != null) {
|
||||
logEntry.set('time', time);
|
||||
logEntry.set('time', time.toUtc());
|
||||
}
|
||||
|
||||
if (bolusGlucose != null) {
|
||||
|
@ -23,8 +23,8 @@ class LogEvent extends DataTableContent {
|
||||
object.get<ParseObject>('endLogEntry')?.get<String>('objectId');
|
||||
eventType =
|
||||
object.get<ParseObject>('eventType')!.get<String>('objectId')!;
|
||||
time = object.get<DateTime>('time')!;
|
||||
endTime = object.get<DateTime>('endTime');
|
||||
time = object.get<DateTime>('time')!.toLocal();
|
||||
endTime = object.get<DateTime>('endTime')?.toLocal();
|
||||
hasEndTime = object.get<bool>('hasEndTime')!;
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
@ -101,7 +101,7 @@ class LogEvent extends DataTableContent {
|
||||
(ParseObject('LogEntry')..objectId = logEntry).toPointer())
|
||||
..set('eventType',
|
||||
(ParseObject('LogEventType')..objectId = eventType).toPointer())
|
||||
..set('time', time)
|
||||
..set('time', time.toUtc())
|
||||
..set('hasEndTime', hasEndTime)
|
||||
..set('notes', notes);
|
||||
await logEvent.save();
|
||||
@ -126,10 +126,10 @@ class LogEvent extends DataTableContent {
|
||||
(ParseObject('LogEntry')..objectId = endLogEntry).toPointer());
|
||||
}
|
||||
if (time != null) {
|
||||
logEvent.set('time', time);
|
||||
logEvent.set('time', time.toUtc());
|
||||
}
|
||||
if (endTime != null) {
|
||||
logEvent.set('endTime', endTime);
|
||||
logEvent.set('endTime', endTime.toUtc());
|
||||
}
|
||||
if (hasEndTime != null) {
|
||||
logEvent.set('hasEndTime', hasEndTime);
|
||||
@ -144,33 +144,33 @@ class LogEvent extends DataTableContent {
|
||||
var logEvent = ParseObject('LogEvent')..objectId = objectId;
|
||||
await logEvent.delete();
|
||||
}
|
||||
|
||||
@override
|
||||
List<DataCell> asDataTableCells(List<Widget> actions,
|
||||
{List<LogEventType>? types}) {
|
||||
return [
|
||||
DataCell(Text(
|
||||
types?.firstWhere((element) => element.objectId == eventType).value ??
|
||||
types?.length.toString() ??
|
||||
'')),
|
||||
DataCell(Text(DateTimeUtils.displayDateTime(time))),
|
||||
DataCell(Text(hasEndTime
|
||||
? DateTimeUtils.displayDateTime(endTime, fallback: 'ongoing')
|
||||
: '-')),
|
||||
DataCell(
|
||||
Row(
|
||||
children: actions,
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
static List<DataColumn> asDataTableColumns() {
|
||||
return [
|
||||
const DataColumn(label: Expanded(child: Text('Event Type'))),
|
||||
const DataColumn(label: Expanded(child: Text('Start Time'))),
|
||||
const DataColumn(label: Expanded(child: Text('End Time'))),
|
||||
const DataColumn(label: Expanded(child: Text('Actions'))),
|
||||
];
|
||||
}
|
||||
//
|
||||
// @override
|
||||
// List<DataCell> asDataTableCells(List<Widget> actions,
|
||||
// {List<LogEventType>? types}) {
|
||||
// return [
|
||||
// DataCell(Text(
|
||||
// types?.firstWhere((element) => element.objectId == eventType).value ??
|
||||
// types?.length.toString() ??
|
||||
// '')),
|
||||
// DataCell(Text(DateTimeUtils.displayDateTime(time))),
|
||||
// DataCell(Text(hasEndTime
|
||||
// ? DateTimeUtils.displayDateTime(endTime, fallback: 'ongoing')
|
||||
// : '-')),
|
||||
// DataCell(
|
||||
// Row(
|
||||
// children: actions,
|
||||
// ),
|
||||
// ),
|
||||
// ];
|
||||
// }
|
||||
//
|
||||
// static List<DataColumn> asDataTableColumns() {
|
||||
// return [
|
||||
// const DataColumn(label: Expanded(child: Text('Event Type'))),
|
||||
// const DataColumn(label: Expanded(child: Text('Start Time'))),
|
||||
// const DataColumn(label: Expanded(child: Text('End Time'))),
|
||||
// const DataColumn(label: Expanded(child: Text('Actions'))),
|
||||
// ];
|
||||
// }
|
||||
}
|
||||
|
@ -13,8 +13,15 @@ class BasalDetailScreen extends StatefulWidget {
|
||||
|
||||
final BasalProfile basalProfile;
|
||||
final Basal? basal;
|
||||
final TimeOfDay? suggestedStartTime;
|
||||
final TimeOfDay? suggestedEndTime;
|
||||
|
||||
const BasalDetailScreen({Key? key, required this.basalProfile, this.basal})
|
||||
const BasalDetailScreen(
|
||||
{Key? key,
|
||||
required this.basalProfile,
|
||||
this.basal,
|
||||
this.suggestedStartTime,
|
||||
this.suggestedEndTime})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
@ -33,6 +40,12 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.suggestedStartTime != null) {
|
||||
_startTime = widget.suggestedStartTime!;
|
||||
}
|
||||
if (widget.suggestedEndTime != null) {
|
||||
_endTime = widget.suggestedEndTime!;
|
||||
}
|
||||
if (widget.basal != null) {
|
||||
_startTime = TimeOfDay.fromDateTime(widget.basal!.startTime);
|
||||
_endTime = TimeOfDay.fromDateTime(widget.basal!.endTime);
|
||||
@ -51,35 +64,90 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
_endTimeController.text = DateTimeUtils.displayTimeOfDay(_endTime);
|
||||
}
|
||||
|
||||
Future<String?> validateTimePeriod() async {
|
||||
String? error;
|
||||
List<Basal> basalRates =
|
||||
await Basal.fetchAllForBasalProfile(widget.basalProfile);
|
||||
|
||||
// check for duplicates
|
||||
if (basalRates
|
||||
.where((other) =>
|
||||
(widget.basal == null ||
|
||||
widget.basal!.objectId != other.objectId) &&
|
||||
_startTime.hour == other.startTime.hour &&
|
||||
_startTime.minute == other.startTime.minute)
|
||||
.isNotEmpty) {
|
||||
error = 'There\'s already a rate with this start time.';
|
||||
}
|
||||
|
||||
if (basalRates
|
||||
.where((other) =>
|
||||
(widget.basal == null ||
|
||||
widget.basal!.objectId != other.objectId) &&
|
||||
DateTimeUtils.convertTimeOfDayToDateTime(_startTime)
|
||||
.isBefore(other.startTime) &&
|
||||
DateTimeUtils.convertTimeOfDayToDateTime(_endTime)
|
||||
.isAfter(other.startTime))
|
||||
.isNotEmpty) {
|
||||
error = 'This rate\'s time period overlaps with another one.';
|
||||
}
|
||||
|
||||
return error == null
|
||||
? null
|
||||
: showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(error!),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, 'CANCEL'),
|
||||
child: const Text('GO BACK TO EDITING'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context, 'CONFIRM'),
|
||||
child: const Text('SAVE AS IS'),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
// TODO: add confirmation dialog in case time period is already covered
|
||||
if (_basalForm.currentState!.validate()) {
|
||||
await validateTimePeriod().then((value) async {
|
||||
if (value != 'CANCEL') {
|
||||
bool isNew = widget.basal == null;
|
||||
isNew
|
||||
? await Basal.save(
|
||||
startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
startTime:
|
||||
DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime),
|
||||
units: double.parse(_unitsController.text),
|
||||
basalProfile: widget.basalProfile.objectId!,
|
||||
)
|
||||
: await Basal.update(
|
||||
widget.basal!.objectId!,
|
||||
startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
startTime:
|
||||
DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime),
|
||||
units: double.parse(_unitsController.text),
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Basal Rate saved');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
bool isNew = widget.basal == null;
|
||||
if (showConfirmationDialogOnCancel &&
|
||||
((isNew &&
|
||||
(_startTime.hour != 0 ||
|
||||
_endTime.hour != 0 ||
|
||||
_startTime.minute != 0 ||
|
||||
_endTime.minute != 0 ||
|
||||
(_startTime.hour != (widget.suggestedStartTime?.hour ?? 0) ||
|
||||
_endTime.hour != (widget.suggestedEndTime?.hour ?? 0) ||
|
||||
_startTime.minute !=
|
||||
(widget.suggestedStartTime?.minute ?? 0) ||
|
||||
_endTime.minute != (widget.suggestedEndTime?.minute ?? 0) ||
|
||||
double.tryParse(_unitsController.text) != null)) ||
|
||||
(!isNew &&
|
||||
(TimeOfDay.fromDateTime(widget.basal!.startTime) !=
|
||||
@ -115,7 +183,6 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
// TODO fix handling of time zones!
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 5),
|
||||
child: StyledTimeOfDayFormField(
|
||||
|
@ -65,12 +65,12 @@ class _BasalListScreenState extends State<BasalListScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
String? checkBasalValidity(List<Basal> basalRates, int index) {
|
||||
String? validateTimePeriod(List<Basal> basalRates, int index) {
|
||||
Basal basal = basalRates[index];
|
||||
|
||||
// check for gaps
|
||||
if (index == 0 &&
|
||||
(basal.startTime.toLocal().hour != 0 || basal.startTime.minute != 0)) {
|
||||
(basal.startTime.hour != 0 || basal.startTime.minute != 0)) {
|
||||
return 'First Basal of the day needs to start at 00:00';
|
||||
}
|
||||
|
||||
@ -82,12 +82,11 @@ class _BasalListScreenState extends State<BasalListScreen> {
|
||||
}
|
||||
|
||||
if (index == basalRates.length - 1 &&
|
||||
(basal.endTime.toLocal().hour != 0 || basal.endTime.minute != 0)) {
|
||||
(basal.endTime.hour != 0 || basal.endTime.minute != 0)) {
|
||||
return 'Last Basal of the day needs to end at 00:00';
|
||||
}
|
||||
|
||||
// check for duplicates
|
||||
|
||||
if (basalRates
|
||||
.where((other) => basal != other && basal.startTime == other.startTime)
|
||||
.isNotEmpty) {
|
||||
@ -131,7 +130,7 @@ class _BasalListScreenState extends State<BasalListScreen> {
|
||||
itemBuilder: (context, index) {
|
||||
final basal = snapshot.data![index];
|
||||
final error =
|
||||
checkBasalValidity(snapshot.data!, index);
|
||||
validateTimePeriod(snapshot.data!, index);
|
||||
return ListTile(
|
||||
tileColor:
|
||||
error != null ? Colors.red.shade100 : null,
|
||||
|
@ -48,16 +48,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
}
|
||||
|
||||
addBasalButton = FloatingActionButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return BasalDetailScreen(basalProfile: widget.basalProfile!);
|
||||
},
|
||||
),
|
||||
).then((message) => refresh(message: message));
|
||||
},
|
||||
onPressed: handleAddNew,
|
||||
child: const Icon(Icons.add),
|
||||
);
|
||||
|
||||
@ -163,6 +154,46 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void handleAddNew() async {
|
||||
List<Basal> basalRates =
|
||||
await Basal.fetchAllForBasalProfile(widget.basalProfile!);
|
||||
TimeOfDay? suggestedStartTime;
|
||||
TimeOfDay? suggestedEndTime;
|
||||
|
||||
basalRates.asMap().forEach((index, basal) {
|
||||
if (suggestedStartTime == null && suggestedEndTime == null) {
|
||||
if (index == 0 &&
|
||||
(basal.startTime.hour != 0 || basal.startTime.minute != 0)) {
|
||||
suggestedStartTime = const TimeOfDay(hour: 0, minute: 0);
|
||||
suggestedEndTime = TimeOfDay.fromDateTime(basal.startTime);
|
||||
} else if ((index == basalRates.length - 1) &&
|
||||
(basal.endTime.hour != 0 || basal.endTime.minute != 0)) {
|
||||
suggestedStartTime = TimeOfDay.fromDateTime(basal.endTime);
|
||||
suggestedEndTime = const TimeOfDay(hour: 0, minute: 0);
|
||||
} else if (index != 0) {
|
||||
var lastEndTime = basalRates[index - 1].endTime;
|
||||
if (basal.startTime.isAfter(lastEndTime)) {
|
||||
suggestedStartTime = TimeOfDay.fromDateTime(lastEndTime);
|
||||
suggestedEndTime = TimeOfDay.fromDateTime(basal.startTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return BasalDetailScreen(
|
||||
basalProfile: widget.basalProfile!,
|
||||
suggestedStartTime: suggestedStartTime,
|
||||
suggestedEndTime: suggestedEndTime,
|
||||
);
|
||||
},
|
||||
),
|
||||
).then((message) => refresh(message: message));
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
if (_basalProfileForm.currentState!.validate()) {
|
||||
await checkActiveProfiles();
|
||||
@ -187,7 +218,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
|
||||
if (showConfirmationDialogOnCancel &&
|
||||
(isNew &&
|
||||
(_active ||
|
||||
(_active != widget.active ||
|
||||
_nameController.text != '' ||
|
||||
_notesController.text != '')) ||
|
||||
(!isNew &&
|
||||
|
@ -15,8 +15,15 @@ class BolusDetailScreen extends StatefulWidget {
|
||||
|
||||
final BolusProfile bolusProfile;
|
||||
final Bolus? bolus;
|
||||
final TimeOfDay? suggestedStartTime;
|
||||
final TimeOfDay? suggestedEndTime;
|
||||
|
||||
const BolusDetailScreen({Key? key, required this.bolusProfile, this.bolus})
|
||||
const BolusDetailScreen(
|
||||
{Key? key,
|
||||
required this.bolusProfile,
|
||||
this.bolus,
|
||||
this.suggestedStartTime,
|
||||
this.suggestedEndTime})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
@ -39,6 +46,12 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.suggestedStartTime != null) {
|
||||
_startTime = widget.suggestedStartTime!;
|
||||
}
|
||||
if (widget.suggestedEndTime != null) {
|
||||
_endTime = widget.suggestedEndTime!;
|
||||
}
|
||||
if (widget.bolus != null) {
|
||||
_startTime = TimeOfDay.fromDateTime(widget.bolus!.startTime);
|
||||
_endTime = TimeOfDay.fromDateTime(widget.bolus!.endTime);
|
||||
@ -60,25 +73,64 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
_endTimeController.text = DateTimeUtils.displayTimeOfDay(_endTime);
|
||||
}
|
||||
|
||||
void updateMgPerDl() {
|
||||
_mgPerDlController.text = Utils.convertMmolPerLToMgPerDl(
|
||||
double.tryParse(_mmolPerLController.text) ?? 0)
|
||||
.toString();
|
||||
Future<String?> validateTimePeriod() async {
|
||||
String? error;
|
||||
List<Bolus> bolusRates =
|
||||
await Bolus.fetchAllForBolusProfile(widget.bolusProfile);
|
||||
|
||||
// check for duplicates
|
||||
if (bolusRates
|
||||
.where((other) =>
|
||||
(widget.bolus == null ||
|
||||
widget.bolus!.objectId != other.objectId) &&
|
||||
_startTime.hour == other.startTime.hour &&
|
||||
_startTime.minute == other.startTime.minute)
|
||||
.isNotEmpty) {
|
||||
error = 'There\'s already a rate with this start time.';
|
||||
}
|
||||
|
||||
void updateMmolPerL() {
|
||||
_mmolPerLController.text = Utils.convertMgPerDlToMmolPerL(
|
||||
int.tryParse(_mgPerDlController.text) ?? 0)
|
||||
.toString();
|
||||
if (bolusRates
|
||||
.where((other) =>
|
||||
(widget.bolus == null ||
|
||||
widget.bolus!.objectId != other.objectId) &&
|
||||
DateTimeUtils.convertTimeOfDayToDateTime(_startTime)
|
||||
.isBefore(other.startTime) &&
|
||||
DateTimeUtils.convertTimeOfDayToDateTime(_endTime)
|
||||
.isAfter(other.startTime))
|
||||
.isNotEmpty) {
|
||||
error = 'This rate\'s time period overlaps with another one.';
|
||||
}
|
||||
|
||||
return error == null
|
||||
? null
|
||||
: showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
content: Text(error!),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, 'CANCEL'),
|
||||
child: const Text('GO BACK TO EDITING'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context, 'CONFIRM'),
|
||||
child: const Text('SAVE AS IS'),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
// TODO: add confirmation dialog in case time period is already covered
|
||||
if (_bolusForm.currentState!.validate()) {
|
||||
await validateTimePeriod().then((value) async {
|
||||
if (value != 'CANCEL') {
|
||||
bool isNew = widget.bolus == null;
|
||||
isNew
|
||||
? await Bolus.save(
|
||||
startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
startTime:
|
||||
DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime),
|
||||
units: double.parse(_unitsController.text),
|
||||
bolusProfile: widget.bolusProfile.objectId!,
|
||||
@ -88,7 +140,8 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
)
|
||||
: await Bolus.update(
|
||||
widget.bolus!.objectId!,
|
||||
startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
startTime:
|
||||
DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime),
|
||||
units: double.tryParse(_unitsController.text),
|
||||
carbs: double.tryParse(_carbsController.text),
|
||||
@ -97,16 +150,19 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Bolus Rate saved');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
bool isNew = widget.bolus == null;
|
||||
if (showConfirmationDialogOnCancel &&
|
||||
((isNew &&
|
||||
(_startTime.hour != 0 ||
|
||||
_endTime.hour != 0 ||
|
||||
_startTime.minute != 0 ||
|
||||
_endTime.minute != 0 ||
|
||||
(_startTime.hour != (widget.suggestedStartTime?.hour ?? 0) ||
|
||||
_endTime.hour != (widget.suggestedEndTime?.hour ?? 0) ||
|
||||
_startTime.minute !=
|
||||
(widget.suggestedStartTime?.minute ?? 0) ||
|
||||
_endTime.minute != (widget.suggestedEndTime?.minute ?? 0) ||
|
||||
(double.tryParse(_unitsController.text) ?? 0) != 0.0 ||
|
||||
(double.tryParse(_carbsController.text) ?? 0) != 0.0 ||
|
||||
(int.tryParse(_mgPerDlController.text) ?? 0) != 0 ||
|
||||
@ -181,7 +237,6 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 5),
|
||||
// TODO fix handling of time zones!
|
||||
child: StyledTimeOfDayFormField(
|
||||
label: 'Start Time',
|
||||
controller: _startTimeController,
|
||||
|
@ -66,7 +66,7 @@ class _BolusListScreenState extends State<BolusListScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
String? checkBolusValidity(List<Bolus> bolusRates, int index) {
|
||||
String? validateTimePeriod(List<Bolus> bolusRates, int index) {
|
||||
Bolus bolus = bolusRates[index];
|
||||
|
||||
// check for gaps
|
||||
@ -88,7 +88,6 @@ class _BolusListScreenState extends State<BolusListScreen> {
|
||||
}
|
||||
|
||||
// check for duplicates
|
||||
|
||||
if (bolusRates
|
||||
.where((other) => bolus != other && bolus.startTime == other.startTime)
|
||||
.isNotEmpty) {
|
||||
@ -133,31 +132,28 @@ class _BolusListScreenState extends State<BolusListScreen> {
|
||||
itemBuilder: (context, index) {
|
||||
final bolus = snapshot.data![index];
|
||||
final error =
|
||||
checkBolusValidity(snapshot.data!, index);
|
||||
validateTimePeriod(snapshot.data!, index);
|
||||
return ListTile(
|
||||
isThreeLine: true,
|
||||
tileColor:
|
||||
error != null ? Colors.red.shade100 : null,
|
||||
onTap: () {
|
||||
handleEditAction(bolus);
|
||||
},
|
||||
title: Row(
|
||||
title: Text(
|
||||
'${DateTimeUtils.displayTime(bolus.startTime)} - ${DateTimeUtils.displayTime(bolus.endTime)}'),
|
||||
subtitle: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${DateTimeUtils.displayTime(bolus.startTime)} - ${DateTimeUtils.displayTime(bolus.endTime)}')),
|
||||
// TODO: style this
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${bolus.units} U per ${bolus.carbs}${nutritionMeasurement == NutritionMeasurement.grams ? ' g' : ' oz'} carbs/${glucoseMeasurement == GlucoseMeasurement.mgPerDl ? bolus.mgPerDl : bolus.mmolPerL} ${glucoseMeasurement == GlucoseMeasurement.mgPerDl ? 'mg/dl' : 'mmol/l'}',
|
||||
style: const TextStyle(fontSize: 12.0)),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: error != null
|
||||
Text(
|
||||
'${bolus.units} U per ${bolus.carbs}${nutritionMeasurement == NutritionMeasurement.grams ? ' g' : ' oz'} carbs/${glucoseMeasurement == GlucoseMeasurement.mgPerDl ? bolus.mgPerDl : bolus.mmolPerL} ${glucoseMeasurement == GlucoseMeasurement.mgPerDl ? 'mg/dl' : 'mmol/l'}'),
|
||||
error != null
|
||||
? Text(error,
|
||||
style: const TextStyle(color: Colors.red))
|
||||
: Container(),
|
||||
style: const TextStyle(
|
||||
color: Colors.red))
|
||||
: const Text('')
|
||||
]),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
@ -48,16 +48,7 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
}
|
||||
|
||||
addBolusButton = FloatingActionButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return BolusDetailScreen(bolusProfile: widget.bolusProfile!);
|
||||
},
|
||||
),
|
||||
).then((message) => refresh(message: message));
|
||||
},
|
||||
onPressed: handleAddNew,
|
||||
child: const Icon(Icons.add),
|
||||
);
|
||||
|
||||
@ -163,6 +154,46 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void handleAddNew() async {
|
||||
List<Bolus> bolusRates =
|
||||
await Bolus.fetchAllForBolusProfile(widget.bolusProfile!);
|
||||
TimeOfDay? suggestedStartTime;
|
||||
TimeOfDay? suggestedEndTime;
|
||||
|
||||
bolusRates.asMap().forEach((index, bolus) {
|
||||
if (suggestedStartTime == null && suggestedEndTime == null) {
|
||||
if (index == 0 &&
|
||||
(bolus.startTime.hour != 0 || bolus.startTime.minute != 0)) {
|
||||
suggestedStartTime = const TimeOfDay(hour: 0, minute: 0);
|
||||
suggestedEndTime = TimeOfDay.fromDateTime(bolus.startTime);
|
||||
} else if ((index == bolusRates.length - 1) &&
|
||||
(bolus.endTime.hour != 0 || bolus.endTime.minute != 0)) {
|
||||
suggestedStartTime = TimeOfDay.fromDateTime(bolus.endTime);
|
||||
suggestedEndTime = const TimeOfDay(hour: 0, minute: 0);
|
||||
} else if (index != 0) {
|
||||
var lastEndTime = bolusRates[index - 1].endTime;
|
||||
if (bolus.startTime.isAfter(lastEndTime)) {
|
||||
suggestedStartTime = TimeOfDay.fromDateTime(lastEndTime);
|
||||
suggestedEndTime = TimeOfDay.fromDateTime(bolus.startTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return BolusDetailScreen(
|
||||
bolusProfile: widget.bolusProfile!,
|
||||
suggestedStartTime: suggestedStartTime,
|
||||
suggestedEndTime: suggestedEndTime,
|
||||
);
|
||||
},
|
||||
),
|
||||
).then((message) => refresh(message: message));
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
if (_bolusProfileForm.currentState!.validate()) {
|
||||
await checkActiveProfiles();
|
||||
@ -187,7 +218,7 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
|
||||
if (showConfirmationDialogOnCancel &&
|
||||
(isNew &&
|
||||
(_active ||
|
||||
(_active != widget.active ||
|
||||
_nameController.text != '' ||
|
||||
_notesController.text != '')) ||
|
||||
(!isNew &&
|
||||
|
@ -133,48 +133,46 @@ class _ActiveLogEventListScreenState extends State<ActiveLogEventListScreen> {
|
||||
return ViewWithProgressIndicator(
|
||||
snapshot: snapshot,
|
||||
child: snapshot.data == null || snapshot.data!.isEmpty
|
||||
? const Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Text('No Active Events'),
|
||||
)
|
||||
? Container()
|
||||
: ListBody(
|
||||
children: [
|
||||
// TODO: fix problems that this futurebuilder in futurebuilder creates
|
||||
FutureBuilder<List<LogEventType>>(
|
||||
future: _logEventTypes,
|
||||
builder: (context, types) {
|
||||
return DataTable(
|
||||
columnSpacing: 10.0,
|
||||
showCheckboxColumn: false,
|
||||
rows: snapshot.data != null
|
||||
? snapshot.data!.map((event) {
|
||||
return DataRow(
|
||||
cells: event.asDataTableCells(
|
||||
[
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.stop),
|
||||
iconSize: 16.0,
|
||||
onPressed: () =>
|
||||
handleStopAction(
|
||||
event),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.delete),
|
||||
iconSize: 16.0,
|
||||
onPressed: () =>
|
||||
handleDeleteAction(
|
||||
event),
|
||||
),
|
||||
],
|
||||
types: types.data,
|
||||
),
|
||||
);
|
||||
}).toList()
|
||||
: [],
|
||||
columns: LogEvent.asDataTableColumns(),
|
||||
);
|
||||
// return DataTable(
|
||||
// columnSpacing: 10.0,
|
||||
// showCheckboxColumn: false,
|
||||
// rows: snapshot.data != null
|
||||
// ? snapshot.data!.map((event) {
|
||||
// return DataRow(
|
||||
// cells: event.asDataTableCells(
|
||||
// [
|
||||
// IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.stop),
|
||||
// iconSize: 16.0,
|
||||
// onPressed: () =>
|
||||
// handleStopAction(
|
||||
// event),
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.delete),
|
||||
// iconSize: 16.0,
|
||||
// onPressed: () =>
|
||||
// handleDeleteAction(
|
||||
// event),
|
||||
// ),
|
||||
// ],
|
||||
// types: types.data,
|
||||
// ),
|
||||
// );
|
||||
// }).toList()
|
||||
// : [],
|
||||
// columns: LogEvent.asDataTableColumns(),
|
||||
// );
|
||||
return Container();
|
||||
})
|
||||
],
|
||||
),
|
||||
|
@ -5,6 +5,7 @@ import 'package:diameter/models/log_event.dart';
|
||||
import 'package:diameter/models/log_event_type.dart';
|
||||
import 'package:diameter/screens/log/active_log_event_list.dart';
|
||||
import 'package:diameter/screens/log/log_event_detail.dart';
|
||||
import 'package:diameter/utils/date_time_utils.dart';
|
||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:diameter/components/progress_indicator.dart';
|
||||
@ -80,7 +81,6 @@ class _LogEventListScreenState extends State<LogEventListScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isNew = widget.logEntry == null;
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
child: Column(
|
||||
@ -97,39 +97,51 @@ class _LogEventListScreenState extends State<LogEventListScreen> {
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Text('No Events for this Log Entry'),
|
||||
)
|
||||
: ListBody(
|
||||
children: [
|
||||
FutureBuilder<List<LogEventType>>(
|
||||
: FutureBuilder<List<LogEventType>>(
|
||||
future: _logEventTypes,
|
||||
builder: (context, types) {
|
||||
return DataTable(
|
||||
columnSpacing: 10.0,
|
||||
showCheckboxColumn: false,
|
||||
rows: snapshot.data != null
|
||||
? snapshot.data!.map((event) {
|
||||
return DataRow(
|
||||
cells: event.asDataTableCells([
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
iconSize: 16.0,
|
||||
onPressed: () =>
|
||||
handleEditAction(event)),
|
||||
IconButton(
|
||||
icon:
|
||||
const Icon(Icons.delete),
|
||||
iconSize: 16.0,
|
||||
onPressed: () =>
|
||||
handleDeleteAction(
|
||||
event)),
|
||||
], types: types.data),
|
||||
);
|
||||
}).toList()
|
||||
: [],
|
||||
columns: LogEvent.asDataTableColumns(),
|
||||
);
|
||||
})
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: snapshot.data != null
|
||||
? snapshot.data!.length
|
||||
: 0,
|
||||
itemBuilder: (context, index) {
|
||||
final event = snapshot.data![index];
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
handleEditAction(event);
|
||||
},
|
||||
title: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(types.data
|
||||
?.firstWhere((element) =>
|
||||
element.objectId ==
|
||||
event.eventType)
|
||||
.value ??
|
||||
'')),
|
||||
],
|
||||
),
|
||||
subtitle: Text(
|
||||
'${DateTimeUtils.displayDateTime(event.time)}${event.hasEndTime ? ' - ${DateTimeUtils.displayDateTime(event.endTime, fallback: '(ongoing)')}' : ''}'),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.delete,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () =>
|
||||
handleDeleteAction(event),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -140,39 +152,51 @@ class _LogEventListScreenState extends State<LogEventListScreen> {
|
||||
snapshot: snapshot,
|
||||
child: snapshot.data == null || snapshot.data!.isEmpty
|
||||
? Container()
|
||||
: ListBody(
|
||||
children: [
|
||||
FutureBuilder<List<LogEventType>>(
|
||||
: FutureBuilder<List<LogEventType>>(
|
||||
future: _logEventTypes,
|
||||
builder: (context, types) {
|
||||
return DataTable(
|
||||
columnSpacing: 10.0,
|
||||
showCheckboxColumn: false,
|
||||
rows: snapshot.data != null
|
||||
? snapshot.data!.map((event) {
|
||||
return DataRow(
|
||||
cells: event.asDataTableCells([
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
iconSize: 16.0,
|
||||
onPressed: () =>
|
||||
handleEditAction(event)),
|
||||
IconButton(
|
||||
icon:
|
||||
const Icon(Icons.delete),
|
||||
iconSize: 16.0,
|
||||
onPressed: () =>
|
||||
handleDeleteAction(
|
||||
event)),
|
||||
], types: types.data),
|
||||
);
|
||||
}).toList()
|
||||
: [],
|
||||
columns: LogEvent.asDataTableColumns(),
|
||||
);
|
||||
})
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: snapshot.data != null
|
||||
? snapshot.data!.length
|
||||
: 0,
|
||||
itemBuilder: (context, index) {
|
||||
final event = snapshot.data![index];
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
handleEditAction(event);
|
||||
},
|
||||
title: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(types.data
|
||||
?.firstWhere((element) =>
|
||||
element.objectId ==
|
||||
event.eventType)
|
||||
.value ??
|
||||
'')),
|
||||
],
|
||||
),
|
||||
subtitle: Text(
|
||||
'${DateTimeUtils.displayDateTime(event.time)}${event.hasEndTime ? ' - ${DateTimeUtils.displayDateTime(event.endTime)}' : ''}'),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.delete,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () =>
|
||||
handleDeleteAction(event),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -3,8 +3,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class DateTimeUtils {
|
||||
// TODO fix handling of time zones!
|
||||
|
||||
static String displayDateTime(DateTime? date, {String fallback = ''}) {
|
||||
if (date == null) {
|
||||
return fallback;
|
||||
|
Loading…
Reference in New Issue
Block a user