diameter/lib/screens/log/log_entry.dart

268 lines
9.7 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;
static FloatingActionButton? actionButton;
static List<Widget> appBarActions = [];
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 {
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');
}
}
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),
);
actionButton = null;
appBarActions = [closeButton];
}
void renderTabButtons(index) {
if (widget.entry != null) {
setState(() {
switch (index) {
case 1:
actionButton = addMealButton;
appBarActions = [refreshButton, closeButton];
break;
case 2:
actionButton = addEventButton;
appBarActions = [refreshButton, closeButton];
break;
default:
actionButton = null;
appBarActions = [closeButton];
}
});
}
}
@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(() {
if (tabController.indexIsChanging) {
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: DetailBottomRow(
onCancel: handleCancelAction,
onSave: handleSaveAction,
),
floatingActionButton: actionButton,
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
);
}),
);
}
}