diameter/lib/screens/bolus/bolus_detail.dart

336 lines
13 KiB
Dart
Raw Normal View History

2021-10-22 23:08:09 +00:00
import 'package:diameter/components/detail.dart';
import 'package:diameter/components/dialogs.dart';
import 'package:diameter/config.dart';
import 'package:diameter/navigation.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/services.dart';
import 'package:diameter/components/forms.dart';
import 'package:diameter/models/bolus.dart';
import 'package:diameter/models/bolus_profile.dart';
import 'package:flutter/widgets.dart';
class BolusDetailScreen extends StatefulWidget {
static const String routeName = '/bolus';
final BolusProfile bolusProfile;
final Bolus? bolus;
const BolusDetailScreen({Key? key, required this.bolusProfile, this.bolus})
: super(key: key);
@override
_BolusDetailScreenState createState() => _BolusDetailScreenState();
}
class _BolusDetailScreenState extends State<BolusDetailScreen> {
final GlobalKey<FormState> _bolusForm = GlobalKey<FormState>();
TimeOfDay _startTime = const TimeOfDay(hour: 0, minute: 0);
TimeOfDay _endTime = const TimeOfDay(hour: 0, minute: 0);
final _startTimeController = TextEditingController();
final _endTimeController = TextEditingController();
final _unitsController = TextEditingController();
final _carbsController = TextEditingController();
final _mgPerDlController = TextEditingController();
final _mmolPerLController = TextEditingController();
@override
void initState() {
super.initState();
if (widget.bolus != null) {
_startTime = TimeOfDay.fromDateTime(widget.bolus!.startTime);
_endTime = TimeOfDay.fromDateTime(widget.bolus!.endTime);
_unitsController.text = widget.bolus!.units.toString();
_carbsController.text = widget.bolus!.carbs.toString();
_mgPerDlController.text = widget.bolus!.mgPerDl.toString();
_mmolPerLController.text = widget.bolus!.mmolPerL.toString();
}
updateStartTime();
updateEndTime();
}
void updateStartTime() {
_startTimeController.text = DateTimeUtils.displayTimeOfDay(_startTime);
}
void updateEndTime() {
_endTimeController.text = DateTimeUtils.displayTimeOfDay(_endTime);
}
void updateMgPerDl() {
_mgPerDlController.text = Utils.convertMmolPerLToMgPerDl(
double.tryParse(_mmolPerLController.text) ?? 0)
.toString();
}
void updateMmolPerL() {
_mmolPerLController.text = Utils.convertMgPerDlToMmolPerL(
int.tryParse(_mgPerDlController.text) ?? 0)
.toString();
}
void handleSaveAction() async {
// TODO: add confirmation dialog in case time period is already covered
if (_bolusForm.currentState!.validate()) {
bool isNew = widget.bolus == null;
isNew
? await Bolus.save(
startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime),
units: double.parse(_unitsController.text),
bolusProfile: widget.bolusProfile.objectId!,
carbs: double.parse(_carbsController.text),
mgPerDl: int.tryParse(_mgPerDlController.text),
mmolPerL: double.tryParse(_mmolPerLController.text),
)
: await Bolus.update(
widget.bolus!.objectId!,
startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime),
units: double.tryParse(_unitsController.text),
carbs: double.tryParse(_carbsController.text),
mgPerDl: int.tryParse(_mgPerDlController.text),
mmolPerL: double.parse(_mmolPerLController.text),
);
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 ||
(double.tryParse(_unitsController.text) ?? 0) != 0.0 ||
(double.tryParse(_carbsController.text) ?? 0) != 0.0 ||
(int.tryParse(_mgPerDlController.text) ?? 0) != 0 ||
(double.tryParse(_mmolPerLController.text) ?? 0) != 0.0)) ||
(!isNew &&
(TimeOfDay.fromDateTime(widget.bolus!.startTime) !=
_startTime ||
TimeOfDay.fromDateTime(widget.bolus!.endTime) != _endTime ||
(double.tryParse(_unitsController.text) ?? 0) !=
widget.bolus!.units ||
(double.tryParse(_carbsController.text) ?? 0) !=
widget.bolus!.carbs ||
(double.tryParse(_mgPerDlController.text) ?? 0) !=
widget.bolus!.mgPerDl ||
(double.tryParse(_mmolPerLController.text) ?? 0) !=
widget.bolus!.mmolPerL)))) {
Dialogs.showCancelConfirmationDialog(
context: context,
isNew: isNew,
onSave: handleSaveAction,
);
} else {
Navigator.pop(context);
}
}
void convertBetweenMgPerDlAndMmolPerL({GlucoseMeasurement? calculateFrom}) {
// TODO figure out why this isnt happening automatically
int? mgPerDl;
double? mmolPerL;
if (calculateFrom != GlucoseMeasurement.mmolPerL &&
_mgPerDlController.text != '') {
mgPerDl = int.tryParse(_mgPerDlController.text);
}
if (calculateFrom != GlucoseMeasurement.mgPerDl &&
_mmolPerLController.text != '') {
mmolPerL = double.tryParse(_mmolPerLController.text);
}
if (mgPerDl != null && mmolPerL == null) {
setState(() {
_mmolPerLController.text =
Utils.convertMgPerDlToMmolPerL(mgPerDl!).toString();
});
}
if (mmolPerL != null && mgPerDl == null) {
setState(() {
_mgPerDlController.text =
Utils.convertMmolPerLToMgPerDl(mmolPerL!).toString();
});
}
}
2021-10-22 23:08:09 +00:00
@override
Widget build(BuildContext context) {
bool isNew = widget.bolus == null;
return Scaffold(
appBar: AppBar(
title: Text(
'${isNew ? 'New' : 'Edit'} Bolus Rate for ${widget.bolusProfile.name}'),
),
drawer: const Navigation(currentLocation: BolusDetailScreen.routeName),
body: SingleChildScrollView(
child: Column(
children: [
StyledForm(
formState: _bolusForm,
fields: [
Row(
children: [
Expanded(
child: StyledTimeOfDayFormField(
label: 'Start Time',
controller: _startTimeController,
time: _startTime,
onChanged: (newStartTime) {
if (newStartTime != null) {
setState(() {
_startTime = newStartTime;
});
updateStartTime();
}
},
),
),
Expanded(
child: StyledTimeOfDayFormField(
label: 'End Time',
controller: _endTimeController,
time: _endTime,
onChanged: (newEndTime) {
if (newEndTime != null) {
setState(() {
_endTime = newEndTime;
});
updateEndTime();
}
},
),
),
],
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Units',
suffixText: 'U',
),
controller: _unitsController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
validator: (value) {
if (value!.trim().isEmpty) {
return 'Empty amount of units';
}
return null;
},
),
TextFormField(
decoration: InputDecoration(
labelText: 'per carbs',
suffixText: nutritionMeasurement ==
NutritionMeasurement.grams
? 'g'
: nutritionMeasurement == NutritionMeasurement.ounces
? 'oz'
: '',
),
controller: _carbsController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
validator: (value) {
if (value!.trim().isEmpty) {
return 'How many carbs does the rate make up for?';
}
return null;
},
),
Row(
children: [
glucoseMeasurement == GlucoseMeasurement.mgPerDl ||
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? Expanded(
child: TextFormField(
decoration: const InputDecoration(
labelText: 'per mg/dl',
suffixText: 'mg/dl',
),
controller: _mgPerDlController,
onChanged: (_) =>
convertBetweenMgPerDlAndMmolPerL,
2021-10-22 23:08:09 +00:00
keyboardType:
const TextInputType.numberWithOptions(),
validator: (value) {
if (value!.trim().isEmpty &&
_mmolPerLController.text.trim().isEmpty) {
return 'How many mg/dl does the rate make up for?';
}
return null;
},
),
)
: Container(),
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? IconButton(
onPressed: () => convertBetweenMgPerDlAndMmolPerL(
calculateFrom: GlucoseMeasurement.mmolPerL),
icon: const Icon(Icons.calculate),
)
: Container(),
2021-10-22 23:08:09 +00:00
glucoseMeasurement == GlucoseMeasurement.mmolPerL ||
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? Expanded(
child: TextFormField(
decoration: const InputDecoration(
labelText: 'per mmol/l',
suffixText: 'mmol/l',
),
controller: _mmolPerLController,
onChanged: (_) =>
convertBetweenMgPerDlAndMmolPerL,
2021-10-22 23:08:09 +00:00
keyboardType:
const TextInputType.numberWithOptions(
decimal: true),
validator: (value) {
if (value!.trim().isEmpty &&
_mgPerDlController.text.trim().isEmpty) {
return 'How many mmol/l does rhe rate make up for?';
}
return null;
},
),
)
: Container(),
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? IconButton(
onPressed: () => convertBetweenMgPerDlAndMmolPerL(
calculateFrom: GlucoseMeasurement.mgPerDl),
icon: const Icon(Icons.calculate),
)
: Container(),
2021-10-22 23:08:09 +00:00
],
),
],
),
],
),
),
bottomNavigationBar: DetailBottomRow(
onCancel: handleCancelAction,
onSave: handleSaveAction,
),
);
}
}