282 lines
9.2 KiB
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,
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
}
|