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 { LogEntry? _logEntry; bool _isNew = true; bool _isSaving = false; final GlobalKey logEntryForm = GlobalKey(); late FloatingActionButton addMealButton; late FloatingActionButton addEventButton; late IconButton refreshButton; late IconButton closeButton; late DetailBottomRow detailBottomRow; FloatingActionButton? actionButton; List appBarActions = []; DetailBottomRow? bottomNav; final formDataControllers = { '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 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, ); }), ); } }