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 { final GlobalKey logEntryForm = GlobalKey(); late FloatingActionButton addMealButton; late FloatingActionButton addEventButton; late IconButton refreshButton; late IconButton closeButton; static FloatingActionButton? actionButton; static List appBarActions = []; final formDataControllers = { '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: 3, child: Builder(builder: (BuildContext context) { final TabController tabController = DefaultTabController.of(context)!; tabController.addListener(() { if (tabController.indexIsChanging) { renderTabButtons(tabController.index); } }); 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: [ LogEntryForm( formState: logEntryForm, controllers: formDataControllers), LogMealListScreen(logEntry: widget.entry), LogEventListScreen(logEntry: widget.entry), ], ), bottomNavigationBar: DetailBottomRow( onCancel: handleCancelAction, onSave: handleSaveAction, ), floatingActionButton: actionButton, floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, ); }), ); } }