diameter/lib/screens/log/log_entry.dart

282 lines
9.2 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/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 int id;
const LogEntryScreen({Key? key, this.id = 0}) : super(key: key);
@override
_LogEntryScreenState createState() => _LogEntryScreenState();
}
class _LogEntryScreenState extends State<LogEntryScreen> {
LogEntry? _logEntry;
bool _isNew = true;
bool _isSaving = false;
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;
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: ''),
};
@override
void initState() {
super.initState();
reload();
if (_logEntry != null) {
formDataControllers['time']!.text = _logEntry!.time.toString();
formDataControllers['mgPerDl']!.text =
(_logEntry!.mgPerDl ?? '').toString();
formDataControllers['mmolPerL']!.text =
(_logEntry!.mmolPerL ?? '').toString();
formDataControllers['bolusGlucose']!.text =
(_logEntry!.bolusGlucose ?? '').toString();
formDataControllers['delayedBolusRate']!.text =
(_logEntry!.delayedBolusRate ?? '').toString();
formDataControllers['delayedBolusDuration']!.text =
(_logEntry!.delayedBolusDuration ?? '').toString();
formDataControllers['notes']!.text = _logEntry!.notes ?? '';
} else {
formDataControllers['time']!.text = DateTime.now().toString();
}
addMealButton = FloatingActionButton(
onPressed: handleAddNewMeal,
child: const Icon(Icons.add),
);
addEventButton = FloatingActionButton(
onPressed: handleAddNewEvent,
child: const Icon(Icons.add),
);
refreshButton = IconButton(
icon: const Icon(Icons.refresh),
onPressed: reload,
);
closeButton = IconButton(
onPressed: handleCancelAction,
icon: const Icon(Icons.close),
);
detailBottomRow = DetailBottomRow(
onCancel: handleCancelAction,
onSave: _isSaving ? null : handleSaveAction,
);
actionButton = null;
appBarActions = [closeButton];
bottomNav = detailBottomRow;
}
void reload({String? message}) {
if (widget.id != 0) {
setState(() {
_logEntry = LogEntry.get(widget.id);
});
_isNew = _logEntry == null;
}
setState(() {
if (message != null) {
var snackBar = SnackBar(
content: Text(message),
duration: const Duration(seconds: 2),
);
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(snackBar);
}
});
}
void handleAddNewMeal() async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LogMealDetailScreen(logEntry: _logEntry!);
},
),
).then((message) => reload(message: message));
}
void handleAddNewEvent() async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LogEventDetailScreen(logEntry: _logEntry!);
},
),
).then((message) => reload(message: message));
}
void handleSaveAction() async {
setState(() {
_isSaving = true;
});
if (logEntryForm.currentState!.validate()) {
LogEntry.put(LogEntry(
id: widget.id,
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),
delayedBolusRate:
double.tryParse(formDataControllers['delayedBolusRate']!.text),
notes: formDataControllers['notes']!.text,
));
Navigator.pushReplacementNamed(context, '/log',
arguments: '${_isNew ? 'New' : ''} Log Entry Saved');
}
setState(() {
_isSaving = false;
});
}
void handleCancelAction() {
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 ?? '') !=
_logEntry!.mgPerDl ||
double.tryParse(formDataControllers['mmolPerL']?.text ?? '') !=
_logEntry!.mmolPerL ||
double.tryParse(formDataControllers['bolusGlucose']?.text ?? '') !=
_logEntry!.bolusGlucose ||
int.tryParse(
formDataControllers['delayedBolusDuration']?.text ??
'') !=
_logEntry!.delayedBolusDuration ||
double.tryParse(formDataControllers['delayedBolusRate']?.text ?? '') !=
_logEntry!.delayedBolusRate ||
formDataControllers['notes']?.text !=
(_logEntry!.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');
}
}
void renderTabButtons(index) {
if (_logEntry != 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) {
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: _logEntry!, reload: reload));
tabs.add(LogEventListScreen(logEntry: _logEntry!, reload: reload));
}
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.endFloat,
);
}),
);
}
}