fix objectbox meta model, update todo list, add date picker to log entry

This commit is contained in:
spinel 2021-11-09 01:17:35 +01:00
parent f7d727e070
commit ab0839bff3
43 changed files with 490 additions and 619 deletions

36
TODO
View File

@ -1,7 +1,37 @@
Todo:
General/Framework:
☐ add active/deleted flag to all data models
☐ account for deleted/disabled elements in dropdowns
☐ place dropdown items right below their input
✔ use local database instead of back4app @done(21-11-07 18:53)
☐ find a general way to deal with duration fields
☐ add explanations to each section
☐ use ids instead of passing entities around where possible
Accuracies:
☐ implement reordering
Basal/Bolus:
☐ create distinct visual mode for picking the active profile
Meal:
none
Log Overview:
☐ add active events view
☐ adjust/debug active events view
☐ display more information
☐ apply target color settings to glucose
☐ total bolus and carbs per entry
Log Entry:
☐ add tab for bolus overview
☐ calculate bolus suggestions according to active profile
☐ add time picker for entry date/time
Event Types:
☐ add option to change bolus/basal profile for event duration
Settings:
☐ add objectbox class and use instead of shared preferences
☐ add fields for date and time formats
☐ add fields for glucose target

View File

@ -1,43 +0,0 @@
import 'package:flutter/material.dart';
abstract class DataTableContent {
bool selected = false;
List<DataCell> asDataTableCells(List<Widget> actions) => [];
static List<DataColumn> asDataTableColumns() => [];
}
class DataTableSourceBuilder extends DataTableSource {
final List<DataTableContent> data;
final BuildContext context;
DataTableSourceBuilder(this.context, this.data);
@override
bool get isRowCountApproximate => false;
@override
int get rowCount => data.length;
@override
int get selectedRowCount {
int count = 0;
for (var element in data) {
if (element.selected) {
count++;
}
}
return count;
}
@override
DataRow? getRow(int index) {
assert(index >= 0);
if (index >= data.length) return null;
final rowData = data[index];
return DataRow.byIndex(
index: index,
selected: rowData.selected,
cells: rowData.asDataTableCells([]),
);
}
}

View File

@ -1,19 +1,18 @@
import 'package:diameter/components/progress_indicator.dart';
import 'package:flutter/material.dart';
class StyledForm extends StatefulWidget {
class FormWrapper extends StatefulWidget {
final List<Widget>? fields;
final List<Widget>? buttons;
final GlobalKey<FormState>? formState;
const StyledForm({Key? key, this.formState, this.fields, this.buttons})
const FormWrapper({Key? key, this.formState, this.fields, this.buttons})
: super(key: key);
@override
_StyledFormState createState() => _StyledFormState();
_FormWrapperState createState() => _FormWrapperState();
}
class _StyledFormState extends State<StyledForm> {
class _FormWrapperState extends State<FormWrapper> {
@override
Widget build(BuildContext context) {
return Padding(
@ -45,13 +44,13 @@ class _StyledFormState extends State<StyledForm> {
}
}
class StyledBooleanFormField extends StatefulWidget {
class BooleanFormField extends StatefulWidget {
final bool value;
final String label;
final void Function(bool) onChanged;
final bool? enabled;
const StyledBooleanFormField(
const BooleanFormField(
{Key? key,
required this.value,
required this.label,
@ -60,10 +59,10 @@ class StyledBooleanFormField extends StatefulWidget {
: super(key: key);
@override
_StyledBooleanFormFieldState createState() => _StyledBooleanFormFieldState();
_BooleanFormFieldState createState() => _BooleanFormFieldState();
}
class _StyledBooleanFormFieldState extends State<StyledBooleanFormField> {
class _BooleanFormFieldState extends State<BooleanFormField> {
@override
Widget build(BuildContext context) {
return FormField<bool>(builder: (context) {
@ -80,13 +79,58 @@ class _StyledBooleanFormFieldState extends State<StyledBooleanFormField> {
}
}
class StyledTimeOfDayFormField extends StatefulWidget {
class DateTimeFormField extends StatefulWidget {
final DateTime date;
final DateTime? minDate;
final DateTime? maxDate;
final TextEditingController controller;
final String label;
final void Function(DateTime?) onChanged;
const DateTimeFormField(
{Key? key,
required this.date,
this.minDate,
this.maxDate,
required this.controller,
required this.label,
required this.onChanged})
: super(key: key);
@override
_DateTimeFormFieldState createState() =>
_DateTimeFormFieldState();
}
class _DateTimeFormFieldState extends State<DateTimeFormField> {
@override
Widget build(BuildContext context) {
return TextFormField(
readOnly: true,
controller: widget.controller,
decoration: InputDecoration(
labelText: widget.label,
),
onTap: () async {
final newTime = await showDatePicker(
context: context,
initialDate: widget.date,
firstDate: widget.minDate ?? DateTime(2000,1,1),
lastDate: widget.maxDate ?? DateTime.now(),
);
widget.onChanged(newTime);
},
);
}
}
class TimeOfDayFormField extends StatefulWidget {
final TimeOfDay time;
final TextEditingController controller;
final String label;
final void Function(TimeOfDay?) onChanged;
const StyledTimeOfDayFormField(
const TimeOfDayFormField(
{Key? key,
required this.time,
required this.controller,
@ -95,11 +139,11 @@ class StyledTimeOfDayFormField extends StatefulWidget {
: super(key: key);
@override
_StyledTimeOfDayFormFieldState createState() =>
_StyledTimeOfDayFormFieldState();
_TimeOfDayFormFieldState createState() =>
_TimeOfDayFormFieldState();
}
class _StyledTimeOfDayFormFieldState extends State<StyledTimeOfDayFormField> {
class _TimeOfDayFormFieldState extends State<TimeOfDayFormField> {
@override
Widget build(BuildContext context) {
return TextFormField(
@ -119,14 +163,14 @@ class _StyledTimeOfDayFormFieldState extends State<StyledTimeOfDayFormField> {
}
}
class StyledDropdownButton<T> extends StatefulWidget {
class LabeledDropdownButton<T> extends StatefulWidget {
final String label;
final T? selectedItem;
final List<T> items;
final Widget Function(T item) renderItem;
final void Function(T? value) onChanged;
const StyledDropdownButton(
const LabeledDropdownButton(
{Key? key,
this.selectedItem,
required this.label,
@ -136,10 +180,10 @@ class StyledDropdownButton<T> extends StatefulWidget {
: super(key: key);
@override
_StyledDropdownButtonState<T> createState() => _StyledDropdownButtonState();
_LabeledDropdownButtonState<T> createState() => _LabeledDropdownButtonState();
}
class _StyledDropdownButtonState<T> extends State<StyledDropdownButton<T>> {
class _LabeledDropdownButtonState<T> extends State<LabeledDropdownButton<T>> {
@override
Widget build(BuildContext context) {
return DropdownButtonFormField<T>(
@ -158,65 +202,3 @@ class _StyledDropdownButtonState<T> extends State<StyledDropdownButton<T>> {
}
}
class StyledFutureDropdownButton<T> extends StatefulWidget {
final String label;
final String? selectedItem;
final Future<List<T>> items;
final String? Function(T item) getItemValue;
final Widget Function(T item) renderItem;
final void Function(String? value) onChanged;
const StyledFutureDropdownButton(
{Key? key,
this.selectedItem,
required this.label,
required this.items,
required this.getItemValue,
required this.renderItem,
required this.onChanged})
: super(key: key);
@override
_StyledFutureDropdownButtonState<T> createState() =>
_StyledFutureDropdownButtonState();
}
class _StyledFutureDropdownButtonState<T>
extends State<StyledFutureDropdownButton<T>> {
@override
Widget build(BuildContext context) {
return FutureBuilder<List<T>>(
future: widget.items,
builder: (context, snapshot) {
return ViewWithProgressIndicator(
snapshot: snapshot,
padding: const EdgeInsets.all(10.0),
progressIndicatorSize: 44,
child: snapshot.data == null || snapshot.data!.isEmpty
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Padding(
padding: EdgeInsets.all(10.0),
child: Text('No Meal Sources'),
)
],
)
: DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: widget.label,
),
value: widget.selectedItem,
onChanged: widget.onChanged,
items: snapshot.data!
.map((item) => DropdownMenuItem<String>(
value: widget.getItemValue(item),
child: widget.renderItem(item),
))
.toList(),
),
);
},
);
}
}

View File

@ -1,65 +0,0 @@
import 'package:flutter/material.dart';
// import 'package:flutter/widgets.dart';
class ViewWithProgressIndicator extends StatefulWidget {
final AsyncSnapshot snapshot;
final Widget child;
final double progressIndicatorSize;
final EdgeInsets padding;
const ViewWithProgressIndicator(
{Key? key,
required this.snapshot,
required this.child,
this.progressIndicatorSize = 100,
this.padding = const EdgeInsets.all(0)})
: super(key: key);
@override
_ViewWithProgressIndicatorState createState() =>
_ViewWithProgressIndicatorState();
}
class _ViewWithProgressIndicatorState extends State<ViewWithProgressIndicator> {
@override
Widget build(BuildContext context) {
switch (widget.snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Container(
alignment: Alignment.center,
padding: widget.padding,
child: Center(
child: SizedBox(
width: widget.progressIndicatorSize,
height: widget.progressIndicatorSize,
child: FutureBuilder(
future: Future.delayed(const Duration(seconds: 1)),
builder: (context, wait) {
if (wait.connectionState != ConnectionState.waiting) {
return const CircularProgressIndicator();
}
return Container();
}
),
),
),
);
default:
if (widget.snapshot.hasError) {
return Center(
child: Text(widget.snapshot.error.toString()),
);
}
if (!widget.snapshot.hasData) {
return const Center(
child: Text("No data"),
);
} else {
return widget.child;
}
}
}
}

View File

@ -21,7 +21,7 @@ import 'package:flutter/material.dart';
import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
import 'package:diameter/screens/accuracy_list.dart';
import 'package:diameter/config.dart';
import 'package:diameter/screens/basal/basal_profiles_list.dart';
import 'package:diameter/screens/basal/basal_profile_list.dart';
import 'package:diameter/screens/bolus/bolus_profile_list.dart';
import 'package:diameter/navigation.dart';

View File

@ -1,7 +1,7 @@
import 'package:diameter/main.dart';
import 'package:diameter/objectbox.g.dart';
@Entity()
@Entity(uid: 3095978685310268382)
class Accuracy {
static final Box<Accuracy> box = objectBox.store.box<Accuracy>();

View File

@ -2,7 +2,7 @@ import 'package:diameter/main.dart';
import 'package:diameter/models/basal_profile.dart';
import 'package:diameter/objectbox.g.dart';
@Entity()
@Entity(uid: 1467758525778521891)
class Basal {
static final Box<Basal> box = objectBox.store.box<Basal>();

View File

@ -1,7 +1,7 @@
import 'package:diameter/main.dart';
import 'package:diameter/objectbox.g.dart';
@Entity()
@Entity(uid: 3613736032926903785)
class BasalProfile {
static final Box<BasalProfile> box = objectBox.store.box<BasalProfile>();

View File

@ -2,7 +2,7 @@ import 'package:diameter/main.dart';
import 'package:diameter/models/bolus_profile.dart';
import 'package:diameter/objectbox.g.dart';
@Entity()
@Entity(uid: 3417770529060202389)
class Bolus {
static final Box<Bolus> box = objectBox.store.box<Bolus>();

View File

@ -1,7 +1,7 @@
import 'package:diameter/main.dart';
import 'package:diameter/objectbox.g.dart';
@Entity()
@Entity(uid: 8812452529027052317)
class BolusProfile {
static final Box<BolusProfile> box = objectBox.store.box<BolusProfile>();

View File

@ -2,9 +2,8 @@ import 'package:diameter/main.dart';
import 'package:diameter/models/log_event.dart';
import 'package:diameter/models/log_meal.dart';
import 'package:diameter/objectbox.g.dart';
import 'package:objectbox/objectbox.dart';
@Entity()
@Entity(uid: 752131069307970560)
class LogEntry {
static final Box<LogEntry> box = objectBox.store.box<LogEntry>();

View File

@ -3,7 +3,7 @@ import 'package:diameter/models/log_entry.dart';
import 'package:diameter/models/log_event_type.dart';
import 'package:diameter/objectbox.g.dart';
@Entity()
@Entity(uid: 4303325892753185970)
class LogEvent {
static final Box<LogEvent> box = objectBox.store.box<LogEvent>();

View File

@ -1,7 +1,7 @@
import 'package:diameter/main.dart';
import 'package:objectbox/objectbox.dart';
@Entity()
@Entity(uid: 8362795406595606110)
class LogEventType {
static final Box<LogEventType> box = objectBox.store.box<LogEventType>();

View File

@ -7,7 +7,7 @@ import 'package:diameter/models/meal_source.dart';
import 'package:diameter/models/accuracy.dart';
import 'package:objectbox/objectbox.dart';
@Entity()
@Entity(uid: 411177866700467286)
class LogMeal {
static final Box<LogMeal> box = objectBox.store.box<LogMeal>();

View File

@ -7,7 +7,7 @@ import 'package:objectbox/objectbox.dart';
enum PortionCarbsParameter { carbsRatio, portionSize, carbsPerPortion }
@Entity()
@Entity(uid: 382130101578692012)
class Meal {
static final Box<Meal> box = objectBox.store.box<Meal>();

View File

@ -1,7 +1,7 @@
import 'package:diameter/main.dart';
import 'package:objectbox/objectbox.dart';
@Entity()
@Entity(uid: 3158200688796904913)
class MealCategory {
static final Box<MealCategory> box = objectBox.store.box<MealCategory>();

View File

@ -1,7 +1,7 @@
import 'package:diameter/main.dart';
import 'package:objectbox/objectbox.dart';
@Entity()
@Entity(uid: 2111511899235985637)
class MealPortionType {
static final Box<MealPortionType> box = objectBox.store.box<MealPortionType>();

View File

@ -4,7 +4,7 @@ import 'package:diameter/models/meal_category.dart';
import 'package:diameter/models/meal_portion_type.dart';
import 'package:objectbox/objectbox.dart';
@Entity()
@Entity(uid: 1283034494527412242)
class MealSource {
static final Box<MealSource> box = objectBox.store.box<MealSource>();

View File

@ -2,7 +2,7 @@ import 'package:diameter/screens/accuracy_detail.dart';
import 'package:diameter/screens/accuracy_list.dart';
import 'package:diameter/screens/basal/basal_detail.dart';
import 'package:diameter/screens/basal/basal_profile_detail.dart';
import 'package:diameter/screens/basal/basal_profiles_list.dart';
import 'package:diameter/screens/basal/basal_profile_list.dart';
import 'package:diameter/screens/bolus/bolus_detail.dart';
import 'package:diameter/screens/bolus/bolus_profile_detail.dart';
import 'package:diameter/screens/bolus/bolus_profile_list.dart';

View File

@ -665,8 +665,8 @@ Future<Store> openStore(
ModelDefinition getObjectBoxModel() {
final model = ModelInfo(
entities: _entities,
lastEntityId: const IdUid(18, 1283034494527412242),
lastIndexId: const IdUid(25, 1931330716440762729),
lastEntityId: const IdUid(13, 1283034494527412242),
lastIndexId: const IdUid(21, 1931330716440762729),
lastRelationId: const IdUid(0, 0),
lastSequenceId: const IdUid(0, 0),
retiredEntityUids: const [],

View File

@ -108,7 +108,7 @@ class _AccuracyDetailScreenState extends State<AccuracyDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _accuracyForm,
fields: [
TextFormField(
@ -123,7 +123,7 @@ class _AccuracyDetailScreenState extends State<AccuracyDetailScreen> {
return null;
},
),
StyledBooleanFormField(
BooleanFormField(
value: _forCarbsRatio,
label: 'for carbs ratio',
onChanged: (value) {
@ -132,7 +132,7 @@ class _AccuracyDetailScreenState extends State<AccuracyDetailScreen> {
});
},
),
StyledBooleanFormField(
BooleanFormField(
value: _forPortionSize,
label: 'for portion size',
onChanged: (value) {

View File

@ -105,6 +105,7 @@ class _AccuracyListScreenState extends State<AccuracyListScreen> {
IconButton(
icon: const Icon(Icons.reorder),
onPressed: () {
// ignore: todo
// TODO: implement reordering
},
),

View File

@ -85,8 +85,6 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
String? error;
List<Basal> basalRates = Basal.getAllForProfile(widget.basalProfileId);
// TODO use a query for the following checks instead?
// check for duplicates
if (basalRates
.where((other) =>
(widget.id != other.id) &&
@ -187,7 +185,7 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
drawer: const Navigation(currentLocation: BasalDetailScreen.routeName),
body: Column(
children: [
StyledForm(
FormWrapper(
formState: _basalForm,
fields: [
Row(
@ -195,7 +193,7 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 5),
child: StyledTimeOfDayFormField(
child: TimeOfDayFormField(
label: 'Start Time',
controller: _startTimeController,
time: _startTime,
@ -213,7 +211,7 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: StyledTimeOfDayFormField(
child: TimeOfDayFormField(
label: 'End Time',
controller: _endTimeController,
time: _endTime,

View File

@ -72,7 +72,6 @@ class _BasalListScreenState extends State<BasalListScreen> {
List<Basal> basalRates = widget.basalRates;
Basal basal = basalRates[index];
// TODO: use queries for all this
// check for gaps
if (index == 0 &&
(basal.startTime.hour != 0 || basal.startTime.minute != 0)) {

View File

@ -27,7 +27,6 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
BasalProfile? _basalProfile;
List<Basal> _basalRates = [];
bool _isNew = true;
bool _isSaving = false;
final GlobalKey<FormState> _basalProfileForm = GlobalKey<FormState>();
@ -35,6 +34,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
late IconButton refreshButton;
late IconButton closeButton;
late DetailBottomRow detailBottomRow;
late DetailBottomRow detailBottomRowWhileSaving;
FloatingActionButton? actionButton;
List<Widget> appBarActions = [];
@ -77,7 +77,12 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
detailBottomRow = DetailBottomRow(
onCancel: handleCancelAction,
onSave: _isSaving ? null : handleSaveAction,
onSave: handleSaveAction,
);
detailBottomRowWhileSaving = DetailBottomRow(
onCancel: handleCancelAction,
onSave: null,
);
actionButton = null;
@ -146,7 +151,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
});
} else if (!_active &&
((_isNew && _activeCount == 0) ||
(_activeCount == 1 && _basalProfile!.active))) {
(!_isNew && _activeCount == 1 && _basalProfile!.active))) {
await showDialog(
context: context,
builder: (BuildContext context) {
@ -214,7 +219,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
void handleSaveAction() async {
setState(() {
_isSaving = true;
bottomNav = detailBottomRowWhileSaving;
});
if (_basalProfileForm.currentState!.validate()) {
await checkActiveProfiles();
@ -227,7 +232,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
Navigator.pop(context, '${_isNew ? 'New' : ''} Basal Profile saved');
}
setState(() {
_isSaving = false;
bottomNav = detailBottomRow;
});
}
@ -283,7 +288,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
StyledForm(
FormWrapper(
formState: _basalProfileForm,
fields: [
TextFormField(
@ -307,7 +312,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
alignLabelWithHint: true,
),
),
StyledBooleanFormField(
BooleanFormField(
value: _active,
onChanged: (value) {
setState(() {

View File

@ -93,9 +93,7 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
Future<String?> validateTimePeriod() async {
String? error;
List<Bolus> bolusRates = Bolus.getAllForProfile(widget.bolusProfileId);
// BolusProfile.get(widget.bolusProfileId)?.bolusRates ?? [];
// TODO use a query for the following checks instead?
// check for duplicates
if (bolusRates
.where((other) =>
@ -238,7 +236,7 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
body: SingleChildScrollView(
child: Column(
children: [
StyledForm(
FormWrapper(
formState: _bolusForm,
fields: [
Row(
@ -246,7 +244,7 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 5),
child: StyledTimeOfDayFormField(
child: TimeOfDayFormField(
label: 'Start Time',
controller: _startTimeController,
time: _startTime,
@ -264,7 +262,7 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: StyledTimeOfDayFormField(
child: TimeOfDayFormField(
label: 'End Time',
controller: _endTimeController,
time: _endTime,

View File

@ -70,8 +70,6 @@ class _BolusListScreenState extends State<BolusListScreen> {
List<Bolus> bolusRates = widget.bolusRates;
Bolus bolus = bolusRates[index];
// TODO: use queries for all this
// check for gaps
if (index == 0 &&
(bolus.startTime.toLocal().hour != 0 || bolus.startTime.minute != 0)) {
return 'First Bolus of the day needs to start at 00:00';

View File

@ -26,7 +26,6 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
BolusProfile? _bolusProfile;
List<Bolus> _bolusRates = [];
bool _isNew = true;
bool _isSaving = false;
final GlobalKey<FormState> _bolusProfileForm = GlobalKey<FormState>();
@ -34,6 +33,7 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
late IconButton refreshButton;
late IconButton closeButton;
late DetailBottomRow detailBottomRow;
late DetailBottomRow detailBottomRowWhileSaving;
FloatingActionButton? actionButton;
List<Widget> appBarActions = [];
@ -73,10 +73,14 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
icon: const Icon(Icons.close),
);
// TODO: fix (saving button doesnt get disabled)
detailBottomRow = DetailBottomRow(
onCancel: handleCancelAction,
onSave: _isSaving ? null : handleSaveAction,
onSave: handleSaveAction,
);
detailBottomRowWhileSaving = DetailBottomRow(
onCancel: handleCancelAction,
onSave: null,
);
actionButton = null;
@ -144,7 +148,7 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
});
} else if (!_active &&
((_isNew && _activeCount == 0) ||
(_activeCount == 1 && _bolusProfile!.active))) {
(!_isNew && _activeCount == 1 && _bolusProfile!.active))) {
await showDialog(
context: context,
builder: (BuildContext context) {
@ -212,7 +216,7 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
void handleSaveAction() async {
setState(() {
_isSaving = true;
bottomNav = detailBottomRowWhileSaving;
});
if (_bolusProfileForm.currentState!.validate()) {
@ -229,9 +233,9 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
}
setState(() {
_isSaving = false;
bottomNav = detailBottomRow;
});
}
}
void handleCancelAction() {
if (showConfirmationDialogOnCancel &&
@ -286,7 +290,7 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
StyledForm(
FormWrapper(
formState: _bolusProfileForm,
fields: [
TextFormField(
@ -309,7 +313,7 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
controller: _notesController,
keyboardType: TextInputType.multiline,
),
StyledBooleanFormField(
BooleanFormField(
value: _active,
onChanged: (value) {
setState(() {
@ -326,8 +330,10 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
];
if (!_isNew) {
tabs.add(
BolusListScreen(bolusProfile: _bolusProfile!, bolusRates: _bolusRates, reload: reload));
tabs.add(BolusListScreen(
bolusProfile: _bolusProfile!,
bolusRates: _bolusRates,
reload: reload));
}
return Scaffold(

View File

@ -165,7 +165,6 @@ class _BolusProfileListScreenState extends State<BolusProfileListScreen> {
? Colors.green.shade100
: null,
onTap: () {
// TODO: make pick active profile visually distinct
pickActiveProfileMode
? onPickActive(bolusProfile)
: onEdit(bolusProfile);

View File

@ -96,7 +96,6 @@ class _ActiveLogEventListScreenState extends State<ActiveLogEventListScreen> {
padding: const EdgeInsets.only(top: 10.0),
child: Column(
children: [
// TODO: make action button instead of appbar
AppBar(
title: const Text('Active Events'),
primary: false,

View File

@ -107,8 +107,8 @@ class _LogScreenState extends State<LogScreen> {
title: Text(
DateTimeUtils.displayTime(
logEntry.time)),
// TODO: add additional fields (event icons...)
// TODO: display glucose in colors according to target settings
// ignore: todo
// TODO: add more data (event, glucose color...)
subtitle: Text(logEntry
.mgPerDl !=
null
@ -141,6 +141,7 @@ class _LogScreenState extends State<LogScreen> {
),
],
),
// ignore: todo
// TODO: add button for active events
floatingActionButton: FloatingActionButton(
onPressed: () {

View File

@ -1,13 +1,16 @@
import 'package:diameter/components/detail.dart';
import 'package:diameter/components/dialogs.dart';
import 'package:diameter/components/forms.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:diameter/settings.dart';
import 'package:diameter/utils/date_time_utils.dart';
import 'package:diameter/utils/utils.dart';
import 'package:flutter/material.dart';
class LogEntryScreen extends StatefulWidget {
@ -27,6 +30,17 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
final GlobalKey<FormState> logEntryForm = GlobalKey<FormState>();
DateTime _time = DateTime.now();
final _timeController = TextEditingController(text: '');
final _dateController = TextEditingController(text: '');
final _mgPerDlController = TextEditingController(text: '');
final _mmolPerLController = TextEditingController(text: '');
final _bolusGlucoseController = TextEditingController(text: '');
final _delayedBolusRateController = TextEditingController(text: '');
final _delayedBolusDurationController = TextEditingController(text: '');
final _notesController = TextEditingController(text: '');
late FloatingActionButton addMealButton;
late FloatingActionButton addEventButton;
late IconButton refreshButton;
@ -37,39 +51,12 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
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),
@ -98,6 +85,20 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
actionButton = null;
appBarActions = [closeButton];
bottomNav = detailBottomRow;
if (_logEntry != null) {
_time = _logEntry!.time;
_mgPerDlController.text = (_logEntry!.mgPerDl ?? '').toString();
_mmolPerLController.text = (_logEntry!.mmolPerL ?? '').toString();
_bolusGlucoseController.text = (_logEntry!.bolusGlucose ?? '').toString();
_delayedBolusRateController.text =
(_logEntry!.delayedBolusRate ?? '').toString();
_delayedBolusDurationController.text =
(_logEntry!.delayedBolusDuration ?? '').toString();
_notesController.text = _logEntry!.notes ?? '';
}
updateTime();
}
void reload({String? message}) {
@ -121,6 +122,95 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
});
}
void updateTime() {
_timeController.text = DateTimeUtils.displayTime(_time);
_dateController.text = DateTimeUtils.displayDate(_time);
}
void convertBetweenMgPerDlAndMmolPerL({GlucoseMeasurement? calculateFrom}) {
int? mgPerDl;
double? mmolPerL;
if (calculateFrom != GlucoseMeasurement.mmolPerL &&
_mgPerDlController.text != '') {
mgPerDl = int.tryParse(_mgPerDlController.text);
}
if (calculateFrom != GlucoseMeasurement.mgPerDl &&
_mmolPerLController.text != '') {
mmolPerL = double.tryParse(_mmolPerLController.text);
}
if (mgPerDl != null && mmolPerL == null) {
setState(() {
_mmolPerLController.text =
Utils.convertMgPerDlToMmolPerL(mgPerDl!).toString();
});
}
if (mmolPerL != null && mgPerDl == null) {
setState(() {
_mgPerDlController.text =
Utils.convertMmolPerLToMgPerDl(mmolPerL!).toString();
});
}
}
void handleSaveAction() async {
setState(() {
_isSaving = true;
});
if (logEntryForm.currentState!.validate()) {
LogEntry.put(LogEntry(
id: widget.id,
time: _time,
mgPerDl: int.tryParse(_mgPerDlController.text),
mmolPerL: double.tryParse(_mmolPerLController.text),
bolusGlucose: double.tryParse(_bolusGlucoseController.text),
delayedBolusDuration:
int.tryParse(_delayedBolusDurationController.text),
delayedBolusRate: double.tryParse(_delayedBolusRateController.text),
notes: _notesController.text,
));
Navigator.pushReplacementNamed(context, '/log',
arguments: '${_isNew ? 'New' : ''} Log Entry Saved');
}
setState(() {
_isSaving = false;
});
}
void handleCancelAction() {
if (showConfirmationDialogOnCancel &&
((_isNew &&
(int.tryParse(_mgPerDlController.text) != null ||
double.tryParse(_mmolPerLController.text) != null ||
double.tryParse(_bolusGlucoseController.text) != null ||
int.tryParse(_delayedBolusDurationController.text) !=
null ||
double.tryParse(_delayedBolusRateController.text) != null ||
_notesController.text != '')) ||
(!_isNew &&
(int.tryParse(_mgPerDlController.text) != _logEntry!.mgPerDl ||
double.tryParse(_mmolPerLController.text) !=
_logEntry!.mmolPerL ||
double.tryParse(_bolusGlucoseController.text) !=
_logEntry!.bolusGlucose ||
int.tryParse(_delayedBolusDurationController.text) !=
_logEntry!.delayedBolusDuration ||
double.tryParse(_delayedBolusRateController.text) !=
_logEntry!.delayedBolusRate ||
_notesController.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 handleAddNewMeal() async {
Navigator.push(
context,
@ -143,73 +233,6 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
).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(() {
@ -243,8 +266,189 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
renderTabButtons(tabController.index);
});
List<Widget> tabs = [
LogEntryForm(
formState: logEntryForm, controllers: formDataControllers),
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
FormWrapper(
formState: logEntryForm,
fields: [
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 5),
child: DateTimeFormField(
date: _time,
label: 'Date',
controller: _dateController,
onChanged: (newTime) {
if (newTime != null) {
setState(() {
_time = DateTime(
newTime.year,
newTime.month,
newTime.day,
_time.hour,
_time.minute);
});
updateTime();
}
},
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: TimeOfDayFormField(
time: TimeOfDay.fromDateTime(_time),
label: 'Time',
controller: _timeController,
onChanged: (newTime) {
if (newTime != null) {
setState(() {
_time = DateTime(
_time.year,
_time.month,
_time.day,
newTime.hour,
newTime.minute);
});
updateTime();
}
},
),
),
),
],
),
Row(
children: [
glucoseMeasurement == GlucoseMeasurement.mgPerDl ||
glucoseDisplayMode ==
GlucoseDisplayMode.both ||
glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? Expanded(
child: TextFormField(
decoration: const InputDecoration(
labelText: 'mg/dl',
suffixText: 'mg/dl',
),
controller: _mgPerDlController,
onChanged: (_) =>
convertBetweenMgPerDlAndMmolPerL(
calculateFrom:
GlucoseMeasurement.mgPerDl),
keyboardType:
const TextInputType.numberWithOptions(),
validator: (value) {
if (value!.trim().isEmpty &&
_mmolPerLController.text
.trim()
.isEmpty) {
return 'How many mg/dl or mmol/l does the rate make up for?';
}
return null;
},
),
)
: Container(),
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? IconButton(
onPressed: () =>
convertBetweenMgPerDlAndMmolPerL(
calculateFrom:
GlucoseMeasurement.mmolPerL),
icon: const Icon(Icons.calculate),
)
: Container(),
glucoseMeasurement == GlucoseMeasurement.mmolPerL ||
glucoseDisplayMode ==
GlucoseDisplayMode.both ||
glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? Expanded(
child: TextFormField(
decoration: const InputDecoration(
labelText: 'mmol/l',
suffixText: 'mmol/l',
),
controller: _mmolPerLController,
onChanged: (_) =>
convertBetweenMgPerDlAndMmolPerL(
calculateFrom:
GlucoseMeasurement.mmolPerL),
keyboardType:
const TextInputType.numberWithOptions(
decimal: true),
validator: (value) {
if (value!.trim().isEmpty &&
_mgPerDlController.text
.trim()
.isEmpty) {
return 'How many mg/dl or mmol/l does rhe rate make up for?';
}
return null;
},
),
)
: Container(),
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? IconButton(
onPressed: () =>
convertBetweenMgPerDlAndMmolPerL(
calculateFrom:
GlucoseMeasurement.mgPerDl),
icon: const Icon(Icons.calculate),
)
: Container(),
],
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Bolus Units',
suffixText: 'U',
),
controller: _bolusGlucoseController,
keyboardType: const TextInputType.numberWithOptions(
decimal: true),
),
// ignore: todo
// TODO: change field functionality according to time format
TextFormField(
decoration: const InputDecoration(
labelText: 'Delayed Bolus Duration',
suffixText: ' min',
),
controller: _delayedBolusDurationController,
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Delayed Bolus Units',
),
controller: _delayedBolusRateController,
keyboardType: const TextInputType.numberWithOptions(
decimal: true),
),
TextFormField(
controller: _notesController,
decoration: const InputDecoration(
labelText: 'Notes',
alignLabelWithHint: true,
),
keyboardType: TextInputType.multiline,
),
],
),
]),
),
];
if (!_isNew) {
@ -272,8 +476,7 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
),
bottomNavigationBar: bottomNav,
floatingActionButton: actionButton,
floatingActionButtonLocation:
FloatingActionButtonLocation.endFloat,
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
);
}),
);

View File

@ -1,185 +0,0 @@
import 'package:diameter/components/forms.dart';
import 'package:diameter/config.dart';
import 'package:diameter/settings.dart';
import 'package:diameter/utils/utils.dart';
import 'package:flutter/material.dart';
class LogEntryForm extends StatefulWidget {
final GlobalKey<FormState> formState;
final Map<String, TextEditingController> controllers;
const LogEntryForm(
{Key? key, required this.formState, required this.controllers})
: super(key: key);
@override
_LogEntryFormState createState() => _LogEntryFormState();
}
class _LogEntryFormState extends State<LogEntryForm> {
void convertBetweenMgPerDlAndMmolPerL({GlucoseMeasurement? calculateFrom}) {
int? mgPerDl;
double? mmolPerL;
final _mgPerDlController = widget.controllers['mgPerDl'];
final _mmolPerLController = widget.controllers['mmolPerL'];
if (calculateFrom != GlucoseMeasurement.mmolPerL &&
_mgPerDlController!.text != '') {
mgPerDl = int.tryParse(_mgPerDlController.text);
}
if (calculateFrom != GlucoseMeasurement.mgPerDl &&
_mmolPerLController!.text != '') {
mmolPerL = double.tryParse(_mmolPerLController.text);
}
if (mgPerDl != null && mmolPerL == null) {
setState(() {
_mmolPerLController!.text =
Utils.convertMgPerDlToMmolPerL(mgPerDl!).toString();
});
}
if (mmolPerL != null && mgPerDl == null) {
setState(() {
_mgPerDlController!.text =
Utils.convertMmolPerLToMgPerDl(mmolPerL!).toString();
});
}
}
@override
Widget build(BuildContext context) {
// final _timeController = widget.controllers['time'];
final _mgPerDlController = widget.controllers['mgPerDl'];
final _mmolPerLController = widget.controllers['mmolPerL'];
final _bolusGlucoseController = widget.controllers['bolusGlucose'];
final _delayedBolusRateController = widget.controllers['delayedBolusRate'];
final _delayedBolusDurationController =
widget.controllers['delayedBolusDuration'];
final _notesController = widget.controllers['notes'];
return SingleChildScrollView(
child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: <
Widget>[
StyledForm(
formState: widget.formState,
fields: [
// TODO: insert time picker
// Expanded(
// child: StyledTimeOfDayFormField(
// label: 'Time',
// controller: _timeController,
// onChanged: (newEndTime) {
// if (newEndTime != null) {
// setState(() {
// _endTime = newEndTime;
// });
// updateEndTime();
// }
//),
Row(
children: [
glucoseMeasurement == GlucoseMeasurement.mgPerDl ||
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode == GlucoseDisplayMode.bothForDetail
? Expanded(
child: TextFormField(
decoration: const InputDecoration(
labelText: 'mg/dl',
suffixText: 'mg/dl',
),
controller: _mgPerDlController,
onChanged: (_) => convertBetweenMgPerDlAndMmolPerL(
calculateFrom: GlucoseMeasurement.mgPerDl),
keyboardType: const TextInputType.numberWithOptions(),
validator: (value) {
if (value!.trim().isEmpty &&
_mmolPerLController!.text.trim().isEmpty) {
return 'How many mg/dl or mmol/l does the rate make up for?';
}
return null;
},
),
)
: Container(),
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode == GlucoseDisplayMode.bothForDetail
? IconButton(
onPressed: () => convertBetweenMgPerDlAndMmolPerL(
calculateFrom: GlucoseMeasurement.mmolPerL),
icon: const Icon(Icons.calculate),
)
: Container(),
glucoseMeasurement == GlucoseMeasurement.mmolPerL ||
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode == GlucoseDisplayMode.bothForDetail
? Expanded(
child: TextFormField(
decoration: const InputDecoration(
labelText: 'mmol/l',
suffixText: 'mmol/l',
),
controller: _mmolPerLController,
onChanged: (_) => convertBetweenMgPerDlAndMmolPerL(
calculateFrom: GlucoseMeasurement.mmolPerL),
keyboardType: const TextInputType.numberWithOptions(
decimal: true),
validator: (value) {
if (value!.trim().isEmpty &&
_mgPerDlController!.text.trim().isEmpty) {
return 'How many mg/dl or mmol/l does rhe rate make up for?';
}
return null;
},
),
)
: Container(),
glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode == GlucoseDisplayMode.bothForDetail
? IconButton(
onPressed: () => convertBetweenMgPerDlAndMmolPerL(
calculateFrom: GlucoseMeasurement.mgPerDl),
icon: const Icon(Icons.calculate),
)
: Container(),
],
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Bolus Units',
suffixText: 'U',
),
controller: _bolusGlucoseController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
),
// TODO: change field functionality according to time format
TextFormField(
decoration: const InputDecoration(
labelText: 'Delayed Bolus Duration',
suffixText: ' min',
),
controller: _delayedBolusDurationController,
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Delayed Bolus Units',
),
controller: _delayedBolusRateController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
),
TextFormField(
controller: _notesController,
decoration: const InputDecoration(
labelText: 'Notes',
alignLabelWithHint: true,
),
keyboardType: TextInputType.multiline,
),
],
),
]),
);
}
}

View File

@ -114,10 +114,10 @@ class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _logEventForm,
fields: [
StyledDropdownButton<LogEventType>(
LabeledDropdownButton<LogEventType>(
selectedItem: _eventType,
label: 'Event Type',
items: _logEventTypes,
@ -128,26 +128,14 @@ class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
});
},
),
// StyledFutureDropdownButton<LogEventType>(
// selectedItem: _eventType,
// label: 'Event Type',
// items: _logEventTypes,
// getItemValue: (item) => item.objectId,
// renderItem: (item) => Text(item.value),
// onChanged: (value) {
// setState(() {
// _eventType = value;
// });
// },
// ),
StyledBooleanFormField(
BooleanFormField(
value: _hasEndTime,
onChanged: (value) {
setState(() {
_hasEndTime = value;
});
},
label: 'active',
label: 'has end time',
),
TextFormField(
controller: _notesController,

View File

@ -68,7 +68,6 @@ class _LogEventListScreenState extends State<LogEventListScreen> {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// TODO: add button for active events
Expanded(
child: (widget.logEntry.events.isNotEmpty || widget.logEntry.endedEvents.isNotEmpty)
? ListView.builder(

View File

@ -45,22 +45,6 @@ class _LogEventTypeDetailScreenState extends State<LogEventTypeDetailScreen> {
});
if (_logEventTypeForm.currentState!.validate()) {
bool isNew = widget.logEventType == null;
// isNew
// ? await LogEventType.save(
// value: _valueController.text,
// notes: _notesController.text,
// defaultReminderDuration:
// int.tryParse(_defaultReminderDurationController.text),
// hasEndTime: _hasEndTime,
// )
// : await LogEventType.update(
// widget.logEventType!.objectId!,
// value: _valueController.text,
// notes: _notesController.text,
// defaultReminderDuration:
// int.tryParse(_defaultReminderDurationController.text),
// hasEndTime: _hasEndTime,
// );
LogEventType.put(LogEventType(
id: widget.logEventType?.id ?? 0,
value: _valueController.text,
@ -115,7 +99,7 @@ class _LogEventTypeDetailScreenState extends State<LogEventTypeDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _logEventTypeForm,
fields: [
TextFormField(
@ -131,7 +115,7 @@ class _LogEventTypeDetailScreenState extends State<LogEventTypeDetailScreen> {
return null;
},
),
StyledBooleanFormField(
BooleanFormField(
value: _hasEndTime,
label: 'has end time',
onChanged: (value) {

View File

@ -315,7 +315,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _logMealForm,
fields: [
TextFormField(
@ -330,7 +330,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
return null;
},
),
StyledDropdownButton<Meal>(
LabeledDropdownButton<Meal>(
selectedItem: _meal,
label: 'Meal',
items: _meals,
@ -342,7 +342,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
}
},
),
StyledDropdownButton<MealSource>(
LabeledDropdownButton<MealSource>(
selectedItem: _mealSource,
label: 'Meal Source',
items: _mealSources,
@ -354,7 +354,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
});
},
),
StyledDropdownButton<MealCategory>(
LabeledDropdownButton<MealCategory>(
selectedItem: _mealCategory,
label: 'Meal Category',
items: _mealCategories,
@ -366,7 +366,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
});
},
),
StyledDropdownButton<MealPortionType>(
LabeledDropdownButton<MealPortionType>(
selectedItem: _mealPortionType,
label: 'Meal Portion Type',
items: _mealPortionTypes,
@ -434,7 +434,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
),
],
),
StyledDropdownButton<Accuracy>(
LabeledDropdownButton<Accuracy>(
selectedItem: _portionSizeAccuracy,
label: 'Portion Size Accuracy',
items: _portionSizeAccuracies,
@ -488,7 +488,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
),
],
),
StyledDropdownButton<Accuracy>(
LabeledDropdownButton<Accuracy>(
selectedItem: _carbsRatioAccuracy,
label: 'Carbs Ratio Accuracy',
items: _carbsRatioAccuracies,

View File

@ -78,7 +78,7 @@ class _MealCategoryDetailScreenState extends State<MealCategoryDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _mealCategoryForm,
fields: [
TextFormField(

View File

@ -266,7 +266,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _mealForm,
fields: [
TextFormField(
@ -281,7 +281,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
return null;
},
),
StyledDropdownButton<MealSource>(
LabeledDropdownButton<MealSource>(
selectedItem: _mealSource,
label: 'Meal Source',
items: _mealSources,
@ -293,7 +293,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
}
},
),
StyledDropdownButton<MealCategory>(
LabeledDropdownButton<MealCategory>(
selectedItem: _mealCategory,
label: 'Meal Category',
items: _mealCategories,
@ -305,7 +305,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
});
},
),
StyledDropdownButton<MealPortionType>(
LabeledDropdownButton<MealPortionType>(
selectedItem: _mealPortionType,
label: 'Meal Portion Type',
items: _mealPortionTypes,
@ -373,7 +373,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
),
],
),
StyledDropdownButton<Accuracy>(
LabeledDropdownButton<Accuracy>(
selectedItem: _portionSizeAccuracy,
label: 'Portion Size Accuracy',
items: _portionSizeAccuracies,
@ -385,18 +385,6 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
});
},
),
// StyledFutureDropdownButton<Accuracy>(
// selectedItem: _portionSizeAccuracy,
// label: 'Portion Size Accuracy',
// items: _portionSizeAccuracies,
// getItemValue: (item) => item.objectId,
// renderItem: (item) => Text(item.value),
// onChanged: (value) {
// setState(() {
// _portionSizeAccuracy = value;
// });
// },
// ),
Row(
children: [
Expanded(
@ -427,7 +415,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
),
],
),
StyledDropdownButton<Accuracy>(
LabeledDropdownButton<Accuracy>(
selectedItem: _carbsRatioAccuracy,
label: 'Carbs Ratio Accuracy',
items: _carbsRatioAccuracies,
@ -439,18 +427,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
});
},
),
// StyledFutureDropdownButton<Accuracy>(
// selectedItem: _carbsRatioAccuracy,
// label: 'Carbs Ratio Accuracy',
// items: _carbsRatioAccuracies,
// getItemValue: (item) => item.objectId,
// renderItem: (item) => Text(item.value),
// onChanged: (value) {
// setState(() {
// _carbsRatioAccuracy = value;
// });
// },
// ),
// ignore: todo
// TODO: display according to time format
TextFormField(
decoration: const InputDecoration(

View File

@ -89,7 +89,7 @@ class _MealPortionTypeDetailScreenState
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _mealPortionTypeForm,
fields: [
TextFormField(

View File

@ -145,7 +145,7 @@ class _MealSourceDetailScreenState extends State<MealSourceDetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _mealSourceForm,
fields: [
TextFormField(
@ -160,7 +160,7 @@ class _MealSourceDetailScreenState extends State<MealSourceDetailScreen> {
return null;
},
),
StyledDropdownButton<Accuracy>(
LabeledDropdownButton<Accuracy>(
selectedItem: _defaultCarbsRatioAccuracy,
label: 'Default Carbs Ratio Accuracy',
items: _carbsRatioAccuracies,
@ -171,7 +171,7 @@ class _MealSourceDetailScreenState extends State<MealSourceDetailScreen> {
});
},
),
StyledDropdownButton<Accuracy>(
LabeledDropdownButton<Accuracy>(
selectedItem: _defaultPortionSizeAccuracy,
label: 'Default Portion Size Accuracy',
items: _portionSizeAccuracies,
@ -206,7 +206,7 @@ class _MealSourceDetailScreenState extends State<MealSourceDetailScreen> {
// });
// },
// ),
StyledDropdownButton<MealCategory>(
LabeledDropdownButton<MealCategory>(
selectedItem: _defaultMealCategory,
label: 'Default Meal Category',
items: _mealCategories,
@ -218,7 +218,7 @@ class _MealSourceDetailScreenState extends State<MealSourceDetailScreen> {
});
},
),
StyledDropdownButton<MealPortionType>(
LabeledDropdownButton<MealPortionType>(
selectedItem: _defaultMealPortionType,
label: 'Default Meal Portion Type',
items: _mealPortionTypes,

View File

@ -127,10 +127,10 @@ class _SettingsScreenState extends State<SettingsScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StyledForm(
FormWrapper(
formState: _settingsForm,
fields: [
StyledDropdownButton<NutritionMeasurement>(
LabeledDropdownButton<NutritionMeasurement>(
selectedItem: nutritionMeasurement,
label: 'Preferred Nutrition Measurement',
items: NutritionMeasurement.values,
@ -144,7 +144,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
}
},
),
StyledDropdownButton<GlucoseMeasurement>(
LabeledDropdownButton<GlucoseMeasurement>(
selectedItem: glucoseMeasurement,
label: 'Preferred Glucose Measurement',
items: GlucoseMeasurement.values,
@ -158,7 +158,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
}
},
),
StyledBooleanFormField(
BooleanFormField(
value: glucoseDisplayMode == GlucoseDisplayMode.activeOnly,
label: 'only display active glucose measurement',
onChanged: (_) {
@ -172,7 +172,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
});
},
),
StyledBooleanFormField(
BooleanFormField(
value: glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode == GlucoseDisplayMode.bothForDetail,
enabled: glucoseDisplayMode != GlucoseDisplayMode.activeOnly,
@ -190,7 +190,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
});
},
),
StyledBooleanFormField(
BooleanFormField(
value: glucoseDisplayMode == GlucoseDisplayMode.both ||
glucoseDisplayMode == GlucoseDisplayMode.bothForList,
enabled: glucoseDisplayMode != GlucoseDisplayMode.activeOnly,
@ -208,8 +208,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
});
},
),
// TODO: add fields for date and time formats
// TODO: add fields for glucose target
],
),
],