282 lines
10 KiB
Dart
282 lines
10 KiB
Dart
import 'package:diameter/components/detail.dart';
|
|
import 'package:diameter/components/dialogs.dart';
|
|
import 'package:diameter/config.dart';
|
|
import 'package:diameter/models/log_entry.dart';
|
|
import 'package:diameter/models/log_event.dart';
|
|
import 'package:diameter/models/log_meal.dart';
|
|
import 'package:diameter/navigation.dart';
|
|
import 'package:diameter/screens/log/log_entry_form.dart';
|
|
import 'package:diameter/screens/log/log_event_detail.dart';
|
|
import 'package:diameter/screens/log/log_event_list.dart';
|
|
import 'package:diameter/screens/log/log_meal_detail.dart';
|
|
import 'package:diameter/screens/log/log_meal_list.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
class LogEntryScreen extends StatefulWidget {
|
|
static const String routeName = '/log-entry';
|
|
final LogEntry? entry;
|
|
const LogEntryScreen({Key? key, this.entry}) : super(key: key);
|
|
|
|
@override
|
|
_LogEntryScreenState createState() => _LogEntryScreenState();
|
|
}
|
|
|
|
class _LogEntryScreenState extends State<LogEntryScreen> {
|
|
final GlobalKey<FormState> logEntryForm = GlobalKey<FormState>();
|
|
|
|
late FloatingActionButton addMealButton;
|
|
late FloatingActionButton addEventButton;
|
|
late IconButton refreshButton;
|
|
late IconButton closeButton;
|
|
late DetailBottomRow detailBottomRow;
|
|
|
|
FloatingActionButton? actionButton;
|
|
List<Widget> appBarActions = [];
|
|
DetailBottomRow? bottomNav;
|
|
|
|
bool _isSaving = false;
|
|
|
|
final formDataControllers = <String, TextEditingController>{
|
|
'time': TextEditingController(text: ''),
|
|
'mgPerDl': TextEditingController(text: ''),
|
|
'mmolPerL': TextEditingController(text: ''),
|
|
'bolusGlucose': TextEditingController(text: ''),
|
|
'delayedBolusRate': TextEditingController(text: ''),
|
|
'delayedBolusDuration': TextEditingController(text: ''),
|
|
'notes': TextEditingController(text: ''),
|
|
};
|
|
|
|
void refreshLists({String? message}) {
|
|
if (widget.entry != null) {
|
|
setState(() {
|
|
widget.entry!.meals = LogMeal.fetchAllForLogEntry(widget.entry!);
|
|
widget.entry!.events = LogEvent.fetchAllForLogEntry(widget.entry!);
|
|
widget.entry!.endedEvents =
|
|
LogEvent.fetchAllEndedByEntry(widget.entry!);
|
|
});
|
|
}
|
|
}
|
|
|
|
void handleSaveAction() async {
|
|
setState(() {
|
|
_isSaving = true;
|
|
});
|
|
if (logEntryForm.currentState!.validate()) {
|
|
bool isNew = widget.entry == null;
|
|
isNew
|
|
? await LogEntry.save(
|
|
time: DateTime.parse(formDataControllers['time']!.text),
|
|
mgPerDl: int.tryParse(formDataControllers['mgPerDl']!.text),
|
|
mmolPerL: double.tryParse(formDataControllers['mmolPerL']!.text),
|
|
bolusGlucose:
|
|
double.tryParse(formDataControllers['bolusGlucose']!.text),
|
|
delayedBolusDuration: int.tryParse(
|
|
formDataControllers['delayedBolusDuration']!.text),
|
|
delayedBolusRatio: double.tryParse(
|
|
formDataControllers['delayedBolusRate']!.text),
|
|
notes: formDataControllers['notes']!.text,
|
|
)
|
|
: await LogEntry.update(
|
|
widget.entry!.objectId!,
|
|
time: DateTime.parse(formDataControllers['time']!.text),
|
|
mgPerDl: int.tryParse(formDataControllers['mgPerDl']!.text),
|
|
mmolPerL: double.tryParse(formDataControllers['mmolPerL']!.text),
|
|
bolusGlucose: double.tryParse(
|
|
formDataControllers['delayedBolusRate']!.text),
|
|
delayedBolusDuration: int.tryParse(
|
|
formDataControllers['delayedBolusDuration']!.text),
|
|
delayedBolusRatio: double.tryParse(
|
|
formDataControllers['delayedBolusRate']!.text),
|
|
notes: formDataControllers['notes']!.text,
|
|
);
|
|
Navigator.pushReplacementNamed(context, '/log',
|
|
arguments: '${isNew ? 'New' : ''} Log Entry Saved');
|
|
}
|
|
setState(() {
|
|
_isSaving = false;
|
|
});
|
|
}
|
|
|
|
void handleCancelAction() {
|
|
bool isNew = widget.entry == null;
|
|
if (showConfirmationDialogOnCancel &&
|
|
((isNew &&
|
|
(int.tryParse(formDataControllers['mgPerDl']?.text ?? '') !=
|
|
null ||
|
|
double.tryParse(formDataControllers['mmolPerL']?.text ?? '') !=
|
|
null ||
|
|
double.tryParse(formDataControllers['bolusGlucose']?.text ?? '') !=
|
|
null ||
|
|
int.tryParse(formDataControllers['delayedBolusDuration']?.text ?? '') !=
|
|
null ||
|
|
double.tryParse(formDataControllers['delayedBolusRate']?.text ?? '') !=
|
|
null ||
|
|
formDataControllers['notes']?.text != '')) ||
|
|
(!isNew &&
|
|
(int.tryParse(formDataControllers['mgPerDl']?.text ?? '') !=
|
|
widget.entry!.mgPerDl ||
|
|
double.tryParse(formDataControllers['mmolPerL']?.text ?? '') !=
|
|
widget.entry!.mmolPerL ||
|
|
double.tryParse(formDataControllers['bolusGlucose']?.text ?? '') !=
|
|
widget.entry!.bolusGlucose ||
|
|
int.tryParse(
|
|
formDataControllers['delayedBolusDuration']?.text ??
|
|
'') !=
|
|
widget.entry!.delayedBolusDuration ||
|
|
double.tryParse(formDataControllers['delayedBolusRate']?.text ?? '') !=
|
|
widget.entry!.delayedBolusRatio ||
|
|
formDataControllers['notes']?.text !=
|
|
(widget.entry!.notes ?? ''))))) {
|
|
Dialogs.showCancelConfirmationDialog(
|
|
context: context,
|
|
isNew: isNew,
|
|
onSave: handleSaveAction,
|
|
onDiscard: (context) => Navigator.pushReplacementNamed(context, '/log'),
|
|
);
|
|
} else {
|
|
Navigator.pushReplacementNamed(context, '/log',
|
|
arguments: '${isNew ? 'New' : ''} Log Entry Saved');
|
|
}
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
if (widget.entry != null) {
|
|
formDataControllers['time']!.text = widget.entry!.time.toString();
|
|
formDataControllers['mgPerDl']!.text =
|
|
(widget.entry!.mgPerDl ?? '').toString();
|
|
formDataControllers['mmolPerL']!.text =
|
|
(widget.entry!.mmolPerL ?? '').toString();
|
|
formDataControllers['bolusGlucose']!.text =
|
|
(widget.entry!.bolusGlucose ?? '').toString();
|
|
formDataControllers['delayedBolusRate']!.text =
|
|
(widget.entry!.delayedBolusRatio ?? '').toString();
|
|
formDataControllers['delayedBolusDuration']!.text =
|
|
(widget.entry!.delayedBolusDuration ?? '').toString();
|
|
formDataControllers['notes']!.text = widget.entry!.notes ?? '';
|
|
} else {
|
|
formDataControllers['time']!.text = DateTime.now().toString();
|
|
}
|
|
|
|
addMealButton = FloatingActionButton(
|
|
onPressed: () {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) {
|
|
return LogMealDetailScreen(logEntry: widget.entry!);
|
|
},
|
|
),
|
|
).then((message) => refreshLists(message: message));
|
|
},
|
|
child: const Icon(Icons.add),
|
|
);
|
|
|
|
addEventButton = FloatingActionButton(
|
|
onPressed: () {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) {
|
|
return LogEventDetailScreen(logEntry: widget.entry!);
|
|
},
|
|
),
|
|
).then((message) => refreshLists(message: message));
|
|
},
|
|
child: const Icon(Icons.add),
|
|
);
|
|
|
|
refreshButton = IconButton(
|
|
icon: const Icon(Icons.refresh),
|
|
onPressed: refreshLists,
|
|
);
|
|
|
|
closeButton = IconButton(
|
|
onPressed: handleCancelAction,
|
|
icon: const Icon(Icons.close),
|
|
);
|
|
|
|
detailBottomRow = DetailBottomRow(
|
|
onCancel: handleCancelAction,
|
|
onSave: _isSaving ? null : handleSaveAction,
|
|
);
|
|
|
|
actionButton = null;
|
|
appBarActions = [closeButton];
|
|
bottomNav = detailBottomRow;
|
|
}
|
|
|
|
void renderTabButtons(index) {
|
|
if (widget.entry != null) {
|
|
setState(() {
|
|
switch (index) {
|
|
case 1:
|
|
actionButton = addMealButton;
|
|
appBarActions = [refreshButton, closeButton];
|
|
bottomNav = null;
|
|
break;
|
|
case 2:
|
|
actionButton = addEventButton;
|
|
appBarActions = [refreshButton, closeButton];
|
|
bottomNav = null;
|
|
break;
|
|
default:
|
|
actionButton = null;
|
|
appBarActions = [closeButton];
|
|
bottomNav = detailBottomRow;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
bool isNew = widget.entry == null;
|
|
|
|
return DefaultTabController(
|
|
length: isNew ? 1 : 3,
|
|
child: Builder(builder: (BuildContext context) {
|
|
final TabController tabController = DefaultTabController.of(context)!;
|
|
tabController.addListener(() {
|
|
renderTabButtons(tabController.index);
|
|
});
|
|
List<Widget> tabs = [
|
|
LogEntryForm(
|
|
formState: logEntryForm, controllers: formDataControllers),
|
|
];
|
|
|
|
if (!isNew) {
|
|
tabs.add(LogMealListScreen(logEntry: widget.entry));
|
|
tabs.add(LogEventListScreen(logEntry: widget.entry));
|
|
}
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(isNew ? 'New Log Entry' : 'Edit Log Entry'),
|
|
bottom: isNew
|
|
? PreferredSize(child: Container(), preferredSize: Size.zero)
|
|
: const TabBar(
|
|
tabs: [
|
|
Tab(text: 'GENERAL'),
|
|
Tab(text: 'MEALS'),
|
|
Tab(text: 'EVENTS'),
|
|
],
|
|
),
|
|
actions: appBarActions,
|
|
),
|
|
drawer: const Navigation(currentLocation: LogEntryScreen.routeName),
|
|
body: TabBarView(
|
|
children: tabs,
|
|
),
|
|
bottomNavigationBar: bottomNav,
|
|
floatingActionButton: actionButton,
|
|
floatingActionButtonLocation:
|
|
FloatingActionButtonLocation.centerDocked,
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
}
|