various small improvements

This commit is contained in:
spinel 2021-12-06 23:09:40 +01:00
parent 9892d7870f
commit 6c987009dc
25 changed files with 817 additions and 421 deletions

26
TODO
View File

@ -2,9 +2,10 @@ BUGFIXES:
General/Framework: General/Framework:
☐ fix preloading of dropdown values (appear blank at first as of now) ☐ fix preloading of dropdown values (appear blank at first as of now)
☐ make sure 'null' isn't shown in text fields ☐ make sure 'null' isn't shown in text fields
Log Entry:
☐ glucose target isn't displaed correctly anymore
Basal/Bolus: Basal/Bolus:
☐ "no element" error on creating basal/bolus rates when working from apk ☐ "no element" error on creating basal/bolus rates when working from apk
☐ scrollbars in rate overview not showing
MAIN TASKS: MAIN TASKS:
Layout: Layout:
@ -20,23 +21,15 @@ MAIN TASKS:
☐ add clear button to dropdown (or all text fields?) ☐ add clear button to dropdown (or all text fields?)
☐ check through all detail forms and set required fields/according messages ☐ check through all detail forms and set required fields/according messages
☐ implement component for durations ☐ implement component for durations
order category lists (meals, meal sources,...) alphabetically change placement of delete and floating button because its very easy to accidentally hit delete
Basal/Bolus: Basal/Bolus:
☐ show daily Basal sum in overview
☐ show KI and stuff for Bolus in overview
☐ add save and close and next buttons on rate creations ☐ add save and close and next buttons on rate creations
Log Overview:
☐ apply target color settings to glucose
Log Entry: Log Entry:
☐ add save and close button ☐ add save and close button
☐ move on to newly created entry after saving ☐ move on to newly created entry after saving
☐ handle text overflow for log meal list
☐ add option to specify trend for blood sugar ☐ add option to specify trend for blood sugar
☐ recalculate bolus upon deactivating 'set manually' option ☐ recalculate bolus upon deactivating 'set manually' option
☐ account for delayed percentage setting on meals ☐ account for delayed percentage setting on meals
Meal:
☐ change delayed bolus rate to percentage
☐ add meal source as subtitle in list
Event Types: Event Types:
☐ add colors as indicators for log entries (and later graphs in reports) ☐ add colors as indicators for log entries (and later graphs in reports)
Settings: Settings:
@ -44,6 +37,7 @@ MAIN TASKS:
☐ add fields for preferred date and time formats ☐ add fields for preferred date and time formats
☐ add fields for glucose target (as map of cutoff glucose and colors) ☐ add fields for glucose target (as map of cutoff glucose and colors)
☐ add field for active insulin duration ☐ add field for active insulin duration
☐ add setting for carb units/bread units
☐ add option to switch 'save' and 'save & close' buttons ☐ add option to switch 'save' and 'save & close' buttons
FUTURE TASKS: FUTURE TASKS:
@ -52,14 +46,13 @@ FUTURE TASKS:
☐ find a better way to work with multiple glucose measurements (or disable it?) ☐ find a better way to work with multiple glucose measurements (or disable it?)
☐ evaluate if some fields should be readonly instead of completely hidden ☐ evaluate if some fields should be readonly instead of completely hidden
☐ alternate languages ☐ alternate languages
☐ log hba1c
Reports: Reports:
☐ evaluate what type of reports there should be ☐ evaluate what type of reports there should be
Basal/Bolus:
Log Overview: Log Overview:
☐ add pagination ☐ add pagination
Log Entry: Log Entry:
☐ check if there is still an active bolus when suggesting glucose bolus ☐ check if there is still an active bolus when suggesting glucose bolus
Meal:
Event Types: Event Types:
☐ add pagination ☐ add pagination
☐ implement reminders as push notifications ☐ implement reminders as push notifications
@ -67,6 +60,15 @@ FUTURE TASKS:
☐ add option to hide extra customization options (ie. changing pre calculated values)? ☐ add option to hide extra customization options (ie. changing pre calculated values)?
Archive: Archive:
✔ scrollbars in rate overview not showing @done(21-12-06 20:01) @project(BUGFIXES.Basal/Bolus)
✔ order category lists (meals, meal sources,...) alphabetically @done(21-12-06 20:34) @project(MAIN TASKS.General/Framework)
✔ add delay to auto conversions @done(21-12-06 20:25) @project(MAIN TASKS.General/Framework)
✔ show daily Basal sum in overview @done(21-12-06 21:09) @project(MAIN TASKS.Basal/Bolus)
✔ show KI and stuff for Bolus in overview @done(21-12-06 21:44) @project(MAIN TASKS.Basal/Bolus)
✔ apply target color settings to glucose @done(21-12-06 22:57) @project(MAIN TASKS.Log Overview)
✔ improve log meal list display @done(21-12-06 20:25) @project(MAIN TASKS.Log Entry)
✔ change delayed bolus rate to percentage @done(21-12-06 20:47) @project(MAIN TASKS.Meal)
✔ add meal source, carbs and portion size as subtitle in list @done(21-12-06 22:01) @project(MAIN TASKS.Meal)
✔ add option to hide warning dialogs on cancel, delete or event stop @done(21-12-05 19:18) @project(FUTURE TASKS.Settings) ✔ add option to hide warning dialogs on cancel, delete or event stop @done(21-12-05 19:18) @project(FUTURE TASKS.Settings)
✔ fix settings saving @done(21-12-05 19:08) @project(MAIN TASKS.Settings) ✔ fix settings saving @done(21-12-05 19:08) @project(MAIN TASKS.Settings)
✔ add objectbox settings class and use instead of shared preferences @done(21-12-05 00:41) @project(MAIN TASKS.Settings) ✔ add objectbox settings class and use instead of shared preferences @done(21-12-05 00:41) @project(MAIN TASKS.Settings)

View File

@ -48,6 +48,25 @@ class Basal {
return builder.build().find(); return builder.build().find();
} }
static double getDailyTotalForProfile(int id) {
double sum = 0.0;
QueryBuilder<Basal> builder = box.query(Basal_.deleted.equals(false));
builder.link(Basal_.basalProfile, BasalProfile_.id.equals(id));
List<Basal> basalRates = builder.build().find();
for (Basal basal in basalRates) {
double rateDuration =
basal.endTime.difference(basal.startTime).inMinutes / 60;
if (rateDuration < 0) {
rateDuration += 24;
}
sum += basal.units * rateDuration;
}
return sum;
}
@override @override
String toString() { String toString() {
return DateTimeUtils.displayTime(startTime); return DateTimeUtils.displayTime(startTime);

View File

@ -28,7 +28,8 @@ class BasalProfile {
static void put(BasalProfile basalProfile) => box.put(basalProfile); static void put(BasalProfile basalProfile) => box.put(basalProfile);
static List<BasalProfile> getAll() { static List<BasalProfile> getAll() {
QueryBuilder<BasalProfile> all = box.query(BasalProfile_.deleted.equals(false)); QueryBuilder<BasalProfile> all = box.query(BasalProfile_.deleted.equals(false))
..order(BasalProfile_.name);
return all.build().find(); return all.build().find();
} }

View File

@ -29,7 +29,7 @@ class BolusProfile {
static List<BolusProfile> getAll() { static List<BolusProfile> getAll() {
QueryBuilder<BolusProfile> all = QueryBuilder<BolusProfile> all =
box.query(BolusProfile_.deleted.equals(false)); box.query(BolusProfile_.deleted.equals(false))..order(BolusProfile_.name);
return all.build().find(); return all.build().find();
} }

View File

@ -0,0 +1,121 @@
import 'package:diameter/main.dart';
import 'package:diameter/models/settings.dart';
import 'package:flutter/material.dart';
import 'package:objectbox/objectbox.dart';
import 'package:diameter/objectbox.g.dart' show GlucoseTarget_;
@Entity(uid: 5041265995704044399)
class GlucoseTarget {
static final Box<GlucoseTarget> box = objectBox.store.box<GlucoseTarget>();
// properties
int id;
bool deleted;
int fromMgPerDL;
int toMgPerDl;
double fromMmolPerL;
double toMmolPerL;
int color;
// constructor
GlucoseTarget({
this.id = 0,
this.deleted = false,
required this.fromMgPerDL,
required this.toMgPerDl,
required this.fromMmolPerL,
required this.toMmolPerL,
required this.color,
});
// methods
static GlucoseTarget? get(int id) => box.get(id);
// methods
static List<GlucoseTarget> getAll() {
if (box.getAll().isEmpty) {
reset();
}
return box.getAll();
}
static Color getColorForGlucose({int mgPerDl = 0, double mmolPerL = 0}) {
if (box.getAll().isEmpty) {
reset();
}
Condition<GlucoseTarget> condition;
if (mgPerDl > 0 &&
(mmolPerL == 0 ||
Settings.glucoseMeasurement == GlucoseMeasurement.mgPerDl)) {
condition = GlucoseTarget_.fromMgPerDL.lessOrEqual(mgPerDl).and(GlucoseTarget_.toMgPerDl.greaterOrEqual(mgPerDl));
} else if (mmolPerL > 0 &&
(mgPerDl == 0 ||
Settings.glucoseMeasurement == GlucoseMeasurement.mmolPerL)) {
condition = GlucoseTarget_.fromMmolPerL.lessOrEqual(mmolPerL).and(GlucoseTarget_.toMmolPerL.greaterOrEqual(mmolPerL));
} else {
return Colors.black;
}
List<GlucoseTarget> result = box
.query(GlucoseTarget_.deleted.equals(false) & condition)
.build()
.find();
if (result.length != 1) {
return Colors.black;
}
return Color(result.single.color);
}
static void put(GlucoseTarget glucoseTarget) => box.put(glucoseTarget);
static void remove(int id) {
final item = box.get(id);
if (item != null) {
item.deleted = true;
box.put(item);
}
}
static void reset() {
box.removeAll();
List<GlucoseTarget> defaultTargets = [
GlucoseTarget(
fromMgPerDL: 0,
toMgPerDl: 69,
fromMmolPerL: 0,
toMmolPerL: 3.83,
color: Colors.red.value,
),
GlucoseTarget(
fromMgPerDL: 70,
toMgPerDl: 99,
fromMmolPerL: 3.84,
toMmolPerL: 5.48,
color: Colors.orange.value,
),
GlucoseTarget(
fromMgPerDL: 100,
toMgPerDl: 140,
fromMmolPerL: 5.49,
toMmolPerL: 7.77,
color: Colors.green.value,
),
GlucoseTarget(
fromMgPerDL: 141,
toMgPerDl: 240,
fromMmolPerL: 7.78,
toMmolPerL: 13.32,
color: Colors.orange.value,
),
GlucoseTarget(
fromMgPerDL: 241,
toMgPerDl: 999,
fromMmolPerL: 13.33,
toMmolPerL: 55.44,
color: Colors.deepOrange.value,
),
];
box.putMany(defaultTargets);
}
}

View File

@ -43,8 +43,8 @@ class LogEntry {
static bool hasUncorrectedGlucose(int id) { static bool hasUncorrectedGlucose(int id) {
final entry = box.get(id); final entry = box.get(id);
if (((entry?.mgPerDl ?? 0) > Settings.get().moderateGlucoseMgPerDl || if (((entry?.mgPerDl ?? 0) > Settings.targetMgPerDl() ||
(entry?.mmolPerL ?? 0) > Settings.get().moderateGlucoseMmolPerL)) { (entry?.mmolPerL ?? 0) > Settings.targetMmolPerL())) {
return !LogBolus.glucoseBolusForEntryExists(id); return !LogBolus.glucoseBolusForEntryExists(id);
} }
return false; return false;

View File

@ -3,6 +3,7 @@ import 'package:diameter/models/accuracy.dart';
import 'package:diameter/models/meal_category.dart'; import 'package:diameter/models/meal_category.dart';
import 'package:diameter/models/meal_portion_type.dart'; import 'package:diameter/models/meal_portion_type.dart';
import 'package:diameter/models/meal_source.dart'; import 'package:diameter/models/meal_source.dart';
import 'package:diameter/objectbox.g.dart' show Meal_;
import 'package:objectbox/objectbox.dart'; import 'package:objectbox/objectbox.dart';
enum PortionCarbsParameter { carbsRatio, portionSize, carbsPerPortion } enum PortionCarbsParameter { carbsRatio, portionSize, carbsPerPortion }
@ -19,7 +20,7 @@ class Meal {
double? portionSize; double? portionSize;
double? carbsPerPortion; double? carbsPerPortion;
int? delayedBolusDuration; int? delayedBolusDuration;
double? delayedBolusRate; double? delayedBolusPercentage;
String? notes; String? notes;
// relations // relations
@ -38,7 +39,7 @@ class Meal {
this.portionSize, this.portionSize,
this.carbsPerPortion, this.carbsPerPortion,
this.delayedBolusDuration, this.delayedBolusDuration,
this.delayedBolusRate, this.delayedBolusPercentage,
this.notes, this.notes,
}); });
@ -46,7 +47,10 @@ class Meal {
static Meal? get(int id) => box.get(id); static Meal? get(int id) => box.get(id);
static void put(Meal meal) => box.put(meal); static void put(Meal meal) => box.put(meal);
static List<Meal> getAll() => box.getAll(); static List<Meal> getAll() {
QueryBuilder<Meal> builder = box.query(Meal_.deleted.equals(false))..order(Meal_.value);
return builder.build().find();
}
static void remove(int id) { static void remove(int id) {
final item = box.get(id); final item = box.get(id);

View File

@ -1,5 +1,6 @@
import 'package:diameter/main.dart'; import 'package:diameter/main.dart';
import 'package:objectbox/objectbox.dart'; import 'package:objectbox/objectbox.dart';
import 'package:diameter/objectbox.g.dart' show MealCategory_;
@Entity(uid: 3158200688796904913) @Entity(uid: 3158200688796904913)
class MealCategory { class MealCategory {
@ -23,7 +24,10 @@ class MealCategory {
static MealCategory? get(int id) => box.get(id); static MealCategory? get(int id) => box.get(id);
static void put(MealCategory mealCategory) => box.put(mealCategory); static void put(MealCategory mealCategory) => box.put(mealCategory);
static List<MealCategory> getAll() => box.getAll(); static List<MealCategory> getAll() {
QueryBuilder<MealCategory> builder = box.query(MealCategory_.deleted.equals(false))..order(MealCategory_.value);
return builder.build().find();
}
static void remove(int id) { static void remove(int id) {
final item = box.get(id); final item = box.get(id);

View File

@ -1,5 +1,6 @@
import 'package:diameter/main.dart'; import 'package:diameter/main.dart';
import 'package:objectbox/objectbox.dart'; import 'package:objectbox/objectbox.dart';
import 'package:diameter/objectbox.g.dart' show MealPortionType_;
@Entity(uid: 2111511899235985637) @Entity(uid: 2111511899235985637)
class MealPortionType { class MealPortionType {
@ -23,7 +24,10 @@ class MealPortionType {
static MealPortionType? get(int id) => box.get(id); static MealPortionType? get(int id) => box.get(id);
static void put(MealPortionType mealPortionType) => box.put(mealPortionType); static void put(MealPortionType mealPortionType) => box.put(mealPortionType);
static List<MealPortionType> getAll() => box.getAll(); static List<MealPortionType> getAll() {
QueryBuilder<MealPortionType> builder = box.query(MealPortionType_.deleted.equals(false))..order(MealPortionType_.value);
return builder.build().find();
}
static void remove(int id) { static void remove(int id) {
final item = box.get(id); final item = box.get(id);

View File

@ -3,6 +3,7 @@ import 'package:diameter/models/accuracy.dart';
import 'package:diameter/models/meal_category.dart'; import 'package:diameter/models/meal_category.dart';
import 'package:diameter/models/meal_portion_type.dart'; import 'package:diameter/models/meal_portion_type.dart';
import 'package:objectbox/objectbox.dart'; import 'package:objectbox/objectbox.dart';
import 'package:diameter/objectbox.g.dart' show MealSource_;
@Entity(uid: 1283034494527412242) @Entity(uid: 1283034494527412242)
class MealSource { class MealSource {
@ -32,7 +33,10 @@ class MealSource {
static MealSource? get(int id) => box.get(id); static MealSource? get(int id) => box.get(id);
static void put(MealSource mealSource) => box.put(mealSource); static void put(MealSource mealSource) => box.put(mealSource);
static List<MealSource> getAll() => box.getAll(); static List<MealSource> getAll() {
QueryBuilder<MealSource> builder = box.query(MealSource_.deleted.equals(false))..order(MealSource_.value);
return builder.build().find();
}
static void remove(int id) { static void remove(int id) {
final item = box.get(id); final item = box.get(id);

View File

@ -57,12 +57,8 @@ class Settings {
bool showConfirmationDialogOnDelete; bool showConfirmationDialogOnDelete;
bool showConfirmationDialogOnStopEvent; bool showConfirmationDialogOnStopEvent;
int lowGlucoseMgPerDl; int targetGlucoseMgPerDl;
int moderateGlucoseMgPerDl; double targetGlucoseMmolPerL;
int highGlucoseMgPerDl;
double lowGlucoseMmolPerL;
double moderateGlucoseMmolPerL;
double highGlucoseMmolPerDl;
// constructor // constructor
Settings({ Settings({
@ -77,12 +73,8 @@ class Settings {
this.showConfirmationDialogOnCancel = true, this.showConfirmationDialogOnCancel = true,
this.showConfirmationDialogOnDelete = true, this.showConfirmationDialogOnDelete = true,
this.showConfirmationDialogOnStopEvent = true, this.showConfirmationDialogOnStopEvent = true,
this.lowGlucoseMgPerDl = 80, this.targetGlucoseMgPerDl = 100,
this.moderateGlucoseMgPerDl = 140, this.targetGlucoseMmolPerL = 5.49,
this.highGlucoseMgPerDl = 240,
this.lowGlucoseMmolPerL = 4.44,
this.moderateGlucoseMmolPerL = 7.77,
this.highGlucoseMmolPerDl = 13.32,
}); });
// methods // methods
@ -105,6 +97,9 @@ class Settings {
static String get glucoseMeasurementSuffix => static String get glucoseMeasurementSuffix =>
glucoseMeasurementSuffixes[get().glucoseMeasurementIndex]; glucoseMeasurementSuffixes[get().glucoseMeasurementIndex];
static int targetMgPerDl() => get().targetGlucoseMgPerDl;
static double targetMmolPerL() => get().targetGlucoseMmolPerL;
static void put(Settings settings) => box.put(settings); static void put(Settings settings) => box.put(settings);
static void reset() { static void reset() {

View File

@ -439,7 +439,7 @@
}, },
{ {
"id": "10:382130101578692012", "id": "10:382130101578692012",
"lastPropertyId": "14:3567196286623536415", "lastPropertyId": "15:8283810711091063880",
"name": "Meal", "name": "Meal",
"properties": [ "properties": [
{ {
@ -473,11 +473,6 @@
"name": "delayedBolusDuration", "name": "delayedBolusDuration",
"type": 6 "type": 6
}, },
{
"id": "7:2172890064639236018",
"name": "delayedBolusRate",
"type": 8
},
{ {
"id": "8:6111684052388229887", "id": "8:6111684052388229887",
"name": "notes", "name": "notes",
@ -527,6 +522,11 @@
"id": "14:3567196286623536415", "id": "14:3567196286623536415",
"name": "deleted", "name": "deleted",
"type": 1 "type": 1
},
{
"id": "15:8283810711091063880",
"name": "delayedBolusPercentage",
"type": 8
} }
], ],
"relations": [] "relations": []
@ -794,7 +794,7 @@
}, },
{ {
"id": "16:3989341091218179227", "id": "16:3989341091218179227",
"lastPropertyId": "20:6560414475711071975", "lastPropertyId": "22:3595473653451456068",
"name": "Settings", "name": "Settings",
"properties": [ "properties": [
{ {
@ -838,36 +838,6 @@
"name": "showConfirmationDialogOnStopEvent", "name": "showConfirmationDialogOnStopEvent",
"type": 1 "type": 1
}, },
{
"id": "9:310032577683835406",
"name": "lowGlucoseMgPerDl",
"type": 6
},
{
"id": "10:596980591281311896",
"name": "moderateGlucoseMgPerDl",
"type": 6
},
{
"id": "11:5588897884422150510",
"name": "highGlucoseMgPerDl",
"type": 6
},
{
"id": "12:7638848982383620744",
"name": "lowGlucoseMmolPerL",
"type": 8
},
{
"id": "13:3633551763915044903",
"name": "moderateGlucoseMmolPerL",
"type": 8
},
{
"id": "14:3282706593658092097",
"name": "highGlucoseMmolPerDl",
"type": 8
},
{ {
"id": "18:1203593429961092769", "id": "18:1203593429961092769",
"name": "nutritionMeasurementIndex", "name": "nutritionMeasurementIndex",
@ -882,12 +852,66 @@
"id": "20:6560414475711071975", "id": "20:6560414475711071975",
"name": "glucoseMeasurementIndex", "name": "glucoseMeasurementIndex",
"type": 6 "type": 6
},
{
"id": "21:7934134105044248002",
"name": "targetGlucoseMgPerDl",
"type": 6
},
{
"id": "22:3595473653451456068",
"name": "targetGlucoseMmolPerL",
"type": 8
}
],
"relations": []
},
{
"id": "17:5041265995704044399",
"lastPropertyId": "7:1333487551279074696",
"name": "GlucoseTarget",
"properties": [
{
"id": "1:4322960567133959537",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:7533461804561299987",
"name": "deleted",
"type": 1
},
{
"id": "3:4949963248761074916",
"name": "fromMgPerDL",
"type": 6
},
{
"id": "4:8685380695305799464",
"name": "toMgPerDl",
"type": 6
},
{
"id": "5:2925449628924807050",
"name": "fromMmolPerL",
"type": 8
},
{
"id": "6:3244873743284485064",
"name": "toMmolPerL",
"type": 8
},
{
"id": "7:1333487551279074696",
"name": "color",
"type": 6
} }
], ],
"relations": [] "relations": []
} }
], ],
"lastEntityId": "16:3989341091218179227", "lastEntityId": "17:5041265995704044399",
"lastIndexId": "28:4563029809754152081", "lastIndexId": "28:4563029809754152081",
"lastRelationId": "0:0", "lastRelationId": "0:0",
"lastSequenceId": "0:0", "lastSequenceId": "0:0",
@ -918,7 +942,14 @@
8031421171668506924, 8031421171668506924,
1614362036318874174, 1614362036318874174,
1675040259141389754, 1675040259141389754,
7518219134349037920 7518219134349037920,
2172890064639236018,
310032577683835406,
5588897884422150510,
7638848982383620744,
3282706593658092097,
596980591281311896,
3633551763915044903
], ],
"retiredRelationUids": [], "retiredRelationUids": [],
"version": 1 "version": 1

View File

@ -14,6 +14,7 @@ import 'models/basal.dart';
import 'models/basal_profile.dart'; import 'models/basal_profile.dart';
import 'models/bolus.dart'; import 'models/bolus.dart';
import 'models/bolus_profile.dart'; import 'models/bolus_profile.dart';
import 'models/glucose_target.dart';
import 'models/log_bolus.dart'; import 'models/log_bolus.dart';
import 'models/log_entry.dart'; import 'models/log_entry.dart';
import 'models/log_event.dart'; import 'models/log_event.dart';
@ -451,7 +452,7 @@ final _entities = <ModelEntity>[
ModelEntity( ModelEntity(
id: const IdUid(10, 382130101578692012), id: const IdUid(10, 382130101578692012),
name: 'Meal', name: 'Meal',
lastPropertyId: const IdUid(14, 3567196286623536415), lastPropertyId: const IdUid(15, 8283810711091063880),
flags: 0, flags: 0,
properties: <ModelProperty>[ properties: <ModelProperty>[
ModelProperty( ModelProperty(
@ -484,11 +485,6 @@ final _entities = <ModelEntity>[
name: 'delayedBolusDuration', name: 'delayedBolusDuration',
type: 6, type: 6,
flags: 0), flags: 0),
ModelProperty(
id: const IdUid(7, 2172890064639236018),
name: 'delayedBolusRate',
type: 8,
flags: 0),
ModelProperty( ModelProperty(
id: const IdUid(8, 6111684052388229887), id: const IdUid(8, 6111684052388229887),
name: 'notes', name: 'notes',
@ -533,6 +529,11 @@ final _entities = <ModelEntity>[
id: const IdUid(14, 3567196286623536415), id: const IdUid(14, 3567196286623536415),
name: 'deleted', name: 'deleted',
type: 1, type: 1,
flags: 0),
ModelProperty(
id: const IdUid(15, 8283810711091063880),
name: 'delayedBolusPercentage',
type: 8,
flags: 0) flags: 0)
], ],
relations: <ModelRelation>[], relations: <ModelRelation>[],
@ -794,7 +795,7 @@ final _entities = <ModelEntity>[
ModelEntity( ModelEntity(
id: const IdUid(16, 3989341091218179227), id: const IdUid(16, 3989341091218179227),
name: 'Settings', name: 'Settings',
lastPropertyId: const IdUid(20, 6560414475711071975), lastPropertyId: const IdUid(22, 3595473653451456068),
flags: 0, flags: 0,
properties: <ModelProperty>[ properties: <ModelProperty>[
ModelProperty( ModelProperty(
@ -837,36 +838,6 @@ final _entities = <ModelEntity>[
name: 'showConfirmationDialogOnStopEvent', name: 'showConfirmationDialogOnStopEvent',
type: 1, type: 1,
flags: 0), flags: 0),
ModelProperty(
id: const IdUid(9, 310032577683835406),
name: 'lowGlucoseMgPerDl',
type: 6,
flags: 0),
ModelProperty(
id: const IdUid(10, 596980591281311896),
name: 'moderateGlucoseMgPerDl',
type: 6,
flags: 0),
ModelProperty(
id: const IdUid(11, 5588897884422150510),
name: 'highGlucoseMgPerDl',
type: 6,
flags: 0),
ModelProperty(
id: const IdUid(12, 7638848982383620744),
name: 'lowGlucoseMmolPerL',
type: 8,
flags: 0),
ModelProperty(
id: const IdUid(13, 3633551763915044903),
name: 'moderateGlucoseMmolPerL',
type: 8,
flags: 0),
ModelProperty(
id: const IdUid(14, 3282706593658092097),
name: 'highGlucoseMmolPerDl',
type: 8,
flags: 0),
ModelProperty( ModelProperty(
id: const IdUid(18, 1203593429961092769), id: const IdUid(18, 1203593429961092769),
name: 'nutritionMeasurementIndex', name: 'nutritionMeasurementIndex',
@ -881,6 +852,60 @@ final _entities = <ModelEntity>[
id: const IdUid(20, 6560414475711071975), id: const IdUid(20, 6560414475711071975),
name: 'glucoseMeasurementIndex', name: 'glucoseMeasurementIndex',
type: 6, type: 6,
flags: 0),
ModelProperty(
id: const IdUid(21, 7934134105044248002),
name: 'targetGlucoseMgPerDl',
type: 6,
flags: 0),
ModelProperty(
id: const IdUid(22, 3595473653451456068),
name: 'targetGlucoseMmolPerL',
type: 8,
flags: 0)
],
relations: <ModelRelation>[],
backlinks: <ModelBacklink>[]),
ModelEntity(
id: const IdUid(17, 5041265995704044399),
name: 'GlucoseTarget',
lastPropertyId: const IdUid(7, 1333487551279074696),
flags: 0,
properties: <ModelProperty>[
ModelProperty(
id: const IdUid(1, 4322960567133959537),
name: 'id',
type: 6,
flags: 1),
ModelProperty(
id: const IdUid(2, 7533461804561299987),
name: 'deleted',
type: 1,
flags: 0),
ModelProperty(
id: const IdUid(3, 4949963248761074916),
name: 'fromMgPerDL',
type: 6,
flags: 0),
ModelProperty(
id: const IdUid(4, 8685380695305799464),
name: 'toMgPerDl',
type: 6,
flags: 0),
ModelProperty(
id: const IdUid(5, 2925449628924807050),
name: 'fromMmolPerL',
type: 8,
flags: 0),
ModelProperty(
id: const IdUid(6, 3244873743284485064),
name: 'toMmolPerL',
type: 8,
flags: 0),
ModelProperty(
id: const IdUid(7, 1333487551279074696),
name: 'color',
type: 6,
flags: 0) flags: 0)
], ],
relations: <ModelRelation>[], relations: <ModelRelation>[],
@ -907,7 +932,7 @@ Future<Store> openStore(
ModelDefinition getObjectBoxModel() { ModelDefinition getObjectBoxModel() {
final model = ModelInfo( final model = ModelInfo(
entities: _entities, entities: _entities,
lastEntityId: const IdUid(16, 3989341091218179227), lastEntityId: const IdUid(17, 5041265995704044399),
lastIndexId: const IdUid(28, 4563029809754152081), lastIndexId: const IdUid(28, 4563029809754152081),
lastRelationId: const IdUid(0, 0), lastRelationId: const IdUid(0, 0),
lastSequenceId: const IdUid(0, 0), lastSequenceId: const IdUid(0, 0),
@ -931,7 +956,14 @@ ModelDefinition getObjectBoxModel() {
8031421171668506924, 8031421171668506924,
1614362036318874174, 1614362036318874174,
1675040259141389754, 1675040259141389754,
7518219134349037920 7518219134349037920,
2172890064639236018,
310032577683835406,
5588897884422150510,
7638848982383620744,
3282706593658092097,
596980591281311896,
3633551763915044903
], ],
retiredRelationUids: const [], retiredRelationUids: const [],
modelVersion: 5, modelVersion: 5,
@ -1346,14 +1378,13 @@ ModelDefinition getObjectBoxModel() {
final valueOffset = fbb.writeString(object.value); final valueOffset = fbb.writeString(object.value);
final notesOffset = final notesOffset =
object.notes == null ? null : fbb.writeString(object.notes!); object.notes == null ? null : fbb.writeString(object.notes!);
fbb.startTable(15); fbb.startTable(16);
fbb.addInt64(0, object.id); fbb.addInt64(0, object.id);
fbb.addOffset(1, valueOffset); fbb.addOffset(1, valueOffset);
fbb.addFloat64(2, object.carbsRatio); fbb.addFloat64(2, object.carbsRatio);
fbb.addFloat64(3, object.portionSize); fbb.addFloat64(3, object.portionSize);
fbb.addFloat64(4, object.carbsPerPortion); fbb.addFloat64(4, object.carbsPerPortion);
fbb.addInt64(5, object.delayedBolusDuration); fbb.addInt64(5, object.delayedBolusDuration);
fbb.addFloat64(6, object.delayedBolusRate);
fbb.addOffset(7, notesOffset); fbb.addOffset(7, notesOffset);
fbb.addInt64(8, object.mealSource.targetId); fbb.addInt64(8, object.mealSource.targetId);
fbb.addInt64(9, object.mealCategory.targetId); fbb.addInt64(9, object.mealCategory.targetId);
@ -1361,6 +1392,7 @@ ModelDefinition getObjectBoxModel() {
fbb.addInt64(11, object.portionSizeAccuracy.targetId); fbb.addInt64(11, object.portionSizeAccuracy.targetId);
fbb.addInt64(12, object.carbsRatioAccuracy.targetId); fbb.addInt64(12, object.carbsRatioAccuracy.targetId);
fbb.addBool(13, object.deleted); fbb.addBool(13, object.deleted);
fbb.addFloat64(14, object.delayedBolusPercentage);
fbb.finish(fbb.endTable()); fbb.finish(fbb.endTable());
return object.id; return object.id;
}, },
@ -1382,8 +1414,8 @@ ModelDefinition getObjectBoxModel() {
.vTableGetNullable(buffer, rootOffset, 12), .vTableGetNullable(buffer, rootOffset, 12),
delayedBolusDuration: const fb.Int64Reader() delayedBolusDuration: const fb.Int64Reader()
.vTableGetNullable(buffer, rootOffset, 14), .vTableGetNullable(buffer, rootOffset, 14),
delayedBolusRate: const fb.Float64Reader() delayedBolusPercentage: const fb.Float64Reader()
.vTableGetNullable(buffer, rootOffset, 16), .vTableGetNullable(buffer, rootOffset, 32),
notes: const fb.StringReader() notes: const fb.StringReader()
.vTableGetNullable(buffer, rootOffset, 18)); .vTableGetNullable(buffer, rootOffset, 18));
object.mealSource.targetId = object.mealSource.targetId =
@ -1662,7 +1694,7 @@ ModelDefinition getObjectBoxModel() {
final longTimeFormatOffset = object.longTimeFormat == null final longTimeFormatOffset = object.longTimeFormat == null
? null ? null
: fbb.writeString(object.longTimeFormat!); : fbb.writeString(object.longTimeFormat!);
fbb.startTable(21); fbb.startTable(23);
fbb.addInt64(0, object.id); fbb.addInt64(0, object.id);
fbb.addOffset(1, dateFormatOffset); fbb.addOffset(1, dateFormatOffset);
fbb.addOffset(2, longDateFormatOffset); fbb.addOffset(2, longDateFormatOffset);
@ -1671,15 +1703,11 @@ ModelDefinition getObjectBoxModel() {
fbb.addBool(5, object.showConfirmationDialogOnCancel); fbb.addBool(5, object.showConfirmationDialogOnCancel);
fbb.addBool(6, object.showConfirmationDialogOnDelete); fbb.addBool(6, object.showConfirmationDialogOnDelete);
fbb.addBool(7, object.showConfirmationDialogOnStopEvent); fbb.addBool(7, object.showConfirmationDialogOnStopEvent);
fbb.addInt64(8, object.lowGlucoseMgPerDl);
fbb.addInt64(9, object.moderateGlucoseMgPerDl);
fbb.addInt64(10, object.highGlucoseMgPerDl);
fbb.addFloat64(11, object.lowGlucoseMmolPerL);
fbb.addFloat64(12, object.moderateGlucoseMmolPerL);
fbb.addFloat64(13, object.highGlucoseMmolPerDl);
fbb.addInt64(17, object.nutritionMeasurementIndex); fbb.addInt64(17, object.nutritionMeasurementIndex);
fbb.addInt64(18, object.glucoseDisplayModeIndex); fbb.addInt64(18, object.glucoseDisplayModeIndex);
fbb.addInt64(19, object.glucoseMeasurementIndex); fbb.addInt64(19, object.glucoseMeasurementIndex);
fbb.addInt64(20, object.targetGlucoseMgPerDl);
fbb.addFloat64(21, object.targetGlucoseMmolPerL);
fbb.finish(fbb.endTable()); fbb.finish(fbb.endTable());
return object.id; return object.id;
}, },
@ -1709,14 +1737,51 @@ ModelDefinition getObjectBoxModel() {
.vTableGet(buffer, rootOffset, 16, false), .vTableGet(buffer, rootOffset, 16, false),
showConfirmationDialogOnStopEvent: const fb.BoolReader() showConfirmationDialogOnStopEvent: const fb.BoolReader()
.vTableGet(buffer, rootOffset, 18, false), .vTableGet(buffer, rootOffset, 18, false),
lowGlucoseMgPerDl: targetGlucoseMgPerDl:
const fb.Int64Reader().vTableGet(buffer, rootOffset, 20, 0), const fb.Int64Reader().vTableGet(buffer, rootOffset, 44, 0),
moderateGlucoseMgPerDl: targetGlucoseMmolPerL:
const fb.Int64Reader().vTableGet(buffer, rootOffset, 22, 0), const fb.Float64Reader().vTableGet(buffer, rootOffset, 46, 0));
highGlucoseMgPerDl: const fb.Int64Reader().vTableGet(buffer, rootOffset, 24, 0),
lowGlucoseMmolPerL: const fb.Float64Reader().vTableGet(buffer, rootOffset, 26, 0), return object;
moderateGlucoseMmolPerL: const fb.Float64Reader().vTableGet(buffer, rootOffset, 28, 0), }),
highGlucoseMmolPerDl: const fb.Float64Reader().vTableGet(buffer, rootOffset, 30, 0)); GlucoseTarget: EntityDefinition<GlucoseTarget>(
model: _entities[15],
toOneRelations: (GlucoseTarget object) => [],
toManyRelations: (GlucoseTarget object) => {},
getId: (GlucoseTarget object) => object.id,
setId: (GlucoseTarget object, int id) {
object.id = id;
},
objectToFB: (GlucoseTarget object, fb.Builder fbb) {
fbb.startTable(8);
fbb.addInt64(0, object.id);
fbb.addBool(1, object.deleted);
fbb.addInt64(2, object.fromMgPerDL);
fbb.addInt64(3, object.toMgPerDl);
fbb.addFloat64(4, object.fromMmolPerL);
fbb.addFloat64(5, object.toMmolPerL);
fbb.addInt64(6, object.color);
fbb.finish(fbb.endTable());
return object.id;
},
objectFromFB: (Store store, ByteData fbData) {
final buffer = fb.BufferContext(fbData);
final rootOffset = buffer.derefObject(0);
final object = GlucoseTarget(
id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0),
deleted:
const fb.BoolReader().vTableGet(buffer, rootOffset, 6, false),
fromMgPerDL:
const fb.Int64Reader().vTableGet(buffer, rootOffset, 8, 0),
toMgPerDl:
const fb.Int64Reader().vTableGet(buffer, rootOffset, 10, 0),
fromMmolPerL:
const fb.Float64Reader().vTableGet(buffer, rootOffset, 12, 0),
toMmolPerL:
const fb.Float64Reader().vTableGet(buffer, rootOffset, 14, 0),
color:
const fb.Int64Reader().vTableGet(buffer, rootOffset, 16, 0));
return object; return object;
}) })
@ -2018,36 +2083,36 @@ class Meal_ {
static final delayedBolusDuration = static final delayedBolusDuration =
QueryIntegerProperty<Meal>(_entities[8].properties[5]); QueryIntegerProperty<Meal>(_entities[8].properties[5]);
/// see [Meal.delayedBolusRate]
static final delayedBolusRate =
QueryDoubleProperty<Meal>(_entities[8].properties[6]);
/// see [Meal.notes] /// see [Meal.notes]
static final notes = QueryStringProperty<Meal>(_entities[8].properties[7]); static final notes = QueryStringProperty<Meal>(_entities[8].properties[6]);
/// see [Meal.mealSource] /// see [Meal.mealSource]
static final mealSource = static final mealSource =
QueryRelationToOne<Meal, MealSource>(_entities[8].properties[8]); QueryRelationToOne<Meal, MealSource>(_entities[8].properties[7]);
/// see [Meal.mealCategory] /// see [Meal.mealCategory]
static final mealCategory = static final mealCategory =
QueryRelationToOne<Meal, MealCategory>(_entities[8].properties[9]); QueryRelationToOne<Meal, MealCategory>(_entities[8].properties[8]);
/// see [Meal.mealPortionType] /// see [Meal.mealPortionType]
static final mealPortionType = static final mealPortionType =
QueryRelationToOne<Meal, MealPortionType>(_entities[8].properties[10]); QueryRelationToOne<Meal, MealPortionType>(_entities[8].properties[9]);
/// see [Meal.portionSizeAccuracy] /// see [Meal.portionSizeAccuracy]
static final portionSizeAccuracy = static final portionSizeAccuracy =
QueryRelationToOne<Meal, Accuracy>(_entities[8].properties[11]); QueryRelationToOne<Meal, Accuracy>(_entities[8].properties[10]);
/// see [Meal.carbsRatioAccuracy] /// see [Meal.carbsRatioAccuracy]
static final carbsRatioAccuracy = static final carbsRatioAccuracy =
QueryRelationToOne<Meal, Accuracy>(_entities[8].properties[12]); QueryRelationToOne<Meal, Accuracy>(_entities[8].properties[11]);
/// see [Meal.deleted] /// see [Meal.deleted]
static final deleted = static final deleted =
QueryBooleanProperty<Meal>(_entities[8].properties[13]); QueryBooleanProperty<Meal>(_entities[8].properties[12]);
/// see [Meal.delayedBolusPercentage]
static final delayedBolusPercentage =
QueryDoubleProperty<Meal>(_entities[8].properties[13]);
} }
/// [MealCategory] entity fields to define ObjectBox queries. /// [MealCategory] entity fields to define ObjectBox queries.
@ -2253,39 +2318,54 @@ class Settings_ {
static final showConfirmationDialogOnStopEvent = static final showConfirmationDialogOnStopEvent =
QueryBooleanProperty<Settings>(_entities[14].properties[7]); QueryBooleanProperty<Settings>(_entities[14].properties[7]);
/// see [Settings.lowGlucoseMgPerDl]
static final lowGlucoseMgPerDl =
QueryIntegerProperty<Settings>(_entities[14].properties[8]);
/// see [Settings.moderateGlucoseMgPerDl]
static final moderateGlucoseMgPerDl =
QueryIntegerProperty<Settings>(_entities[14].properties[9]);
/// see [Settings.highGlucoseMgPerDl]
static final highGlucoseMgPerDl =
QueryIntegerProperty<Settings>(_entities[14].properties[10]);
/// see [Settings.lowGlucoseMmolPerL]
static final lowGlucoseMmolPerL =
QueryDoubleProperty<Settings>(_entities[14].properties[11]);
/// see [Settings.moderateGlucoseMmolPerL]
static final moderateGlucoseMmolPerL =
QueryDoubleProperty<Settings>(_entities[14].properties[12]);
/// see [Settings.highGlucoseMmolPerDl]
static final highGlucoseMmolPerDl =
QueryDoubleProperty<Settings>(_entities[14].properties[13]);
/// see [Settings.nutritionMeasurementIndex] /// see [Settings.nutritionMeasurementIndex]
static final nutritionMeasurementIndex = static final nutritionMeasurementIndex =
QueryIntegerProperty<Settings>(_entities[14].properties[14]); QueryIntegerProperty<Settings>(_entities[14].properties[8]);
/// see [Settings.glucoseDisplayModeIndex] /// see [Settings.glucoseDisplayModeIndex]
static final glucoseDisplayModeIndex = static final glucoseDisplayModeIndex =
QueryIntegerProperty<Settings>(_entities[14].properties[15]); QueryIntegerProperty<Settings>(_entities[14].properties[9]);
/// see [Settings.glucoseMeasurementIndex] /// see [Settings.glucoseMeasurementIndex]
static final glucoseMeasurementIndex = static final glucoseMeasurementIndex =
QueryIntegerProperty<Settings>(_entities[14].properties[16]); QueryIntegerProperty<Settings>(_entities[14].properties[10]);
/// see [Settings.targetGlucoseMgPerDl]
static final targetGlucoseMgPerDl =
QueryIntegerProperty<Settings>(_entities[14].properties[11]);
/// see [Settings.targetGlucoseMmolPerL]
static final targetGlucoseMmolPerL =
QueryDoubleProperty<Settings>(_entities[14].properties[12]);
}
/// [GlucoseTarget] entity fields to define ObjectBox queries.
class GlucoseTarget_ {
/// see [GlucoseTarget.id]
static final id =
QueryIntegerProperty<GlucoseTarget>(_entities[15].properties[0]);
/// see [GlucoseTarget.deleted]
static final deleted =
QueryBooleanProperty<GlucoseTarget>(_entities[15].properties[1]);
/// see [GlucoseTarget.fromMgPerDL]
static final fromMgPerDL =
QueryIntegerProperty<GlucoseTarget>(_entities[15].properties[2]);
/// see [GlucoseTarget.toMgPerDl]
static final toMgPerDl =
QueryIntegerProperty<GlucoseTarget>(_entities[15].properties[3]);
/// see [GlucoseTarget.fromMmolPerL]
static final fromMmolPerL =
QueryDoubleProperty<GlucoseTarget>(_entities[15].properties[4]);
/// see [GlucoseTarget.toMmolPerL]
static final toMmolPerL =
QueryDoubleProperty<GlucoseTarget>(_entities[15].properties[5]);
/// see [GlucoseTarget.color]
static final color =
QueryIntegerProperty<GlucoseTarget>(_entities[15].properties[6]);
} }

View File

@ -108,51 +108,45 @@ class _BasalListScreenState extends State<BasalListScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return widget.basalRates.isNotEmpty ? SingleChildScrollView( return widget.basalRates.isNotEmpty ? ListView.builder(
child: Column( shrinkWrap: true,
children: [ itemCount: widget.basalRates.length,
ListView.builder( itemBuilder: (context, index) {
shrinkWrap: true, final basal = widget.basalRates[index];
itemCount: widget.basalRates.length, final error = validateTimePeriod(index);
itemBuilder: (context, index) { return ListTile(
final basal = widget.basalRates[index]; tileColor: error != null ? Colors.red.shade100 : null,
final error = validateTimePeriod(index); onTap: () {
return ListTile( handleEditAction(basal);
tileColor: error != null ? Colors.red.shade100 : null, },
onTap: () { title: Row(
handleEditAction(basal); mainAxisSize: MainAxisSize.max,
}, children: [
title: Row( Expanded(
mainAxisSize: MainAxisSize.max, child: Text(
children: [ '${DateTimeUtils.displayTime(basal.startTime)} - ${DateTimeUtils.displayTime(basal.endTime)}')),
Expanded( const Spacer(),
child: Text( Expanded(child: Text('${basal.units} U')),
'${DateTimeUtils.displayTime(basal.startTime)} - ${DateTimeUtils.displayTime(basal.endTime)}')), ],
const Spacer(),
Expanded(child: Text('${basal.units} U')),
],
),
subtitle: error != null
? Text(error, style: const TextStyle(color: Colors.red))
: Container(),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(
Icons.delete,
color: Colors.blue,
),
onPressed: () => handleDeleteAction(basal),
),
],
),
);
},
), ),
], subtitle: error != null
), ? Text(error, style: const TextStyle(color: Colors.red))
): const Center( : Container(),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(
Icons.delete,
color: Colors.blue,
),
onPressed: () => handleDeleteAction(basal),
),
],
),
);
},
) : const Center(
child: Text('You have not created any Basal Rates yet!'), child: Text('You have not created any Basal Rates yet!'),
); );
} }

View File

@ -1,5 +1,6 @@
import 'package:diameter/components/dialogs.dart'; import 'package:diameter/components/dialogs.dart';
import 'package:diameter/components/dropdown.dart'; import 'package:diameter/components/dropdown.dart';
import 'package:diameter/models/basal.dart';
import 'package:diameter/models/settings.dart'; import 'package:diameter/models/settings.dart';
import 'package:diameter/navigation.dart'; import 'package:diameter/navigation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -167,19 +168,38 @@ class _BasalProfileListScreenState extends State<BasalProfileListScreen> {
itemCount: _basalProfiles.length, itemCount: _basalProfiles.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final basalProfile = _basalProfiles[index]; final basalProfile = _basalProfiles[index];
double dailyTotal =
Basal.getDailyTotalForProfile(basalProfile.id);
String activeProfileText = basalProfile.active String activeProfileText = basalProfile.active
? 'Default Profile' ? 'Default Profile'
: basalProfile.id == _activeProfile?.id : basalProfile.id == _activeProfile?.id
? 'Current Active Profile' ? 'Current Active Profile'
: ''; : '';
if (activeProfileText != '' && (basalProfile.notes ?? '') != '') { if (activeProfileText != '' &&
(basalProfile.notes ?? '') != '') {
activeProfileText += '\n'; activeProfileText += '\n';
} }
return ListTile( return ListTile(
selected: basalProfile.active || basalProfile.id == _activeProfile?.id, selected: basalProfile.active ||
basalProfile.id == _activeProfile?.id,
onTap: () => onEdit(basalProfile), onTap: () => onEdit(basalProfile),
title: Text(basalProfile.name), title: Text(basalProfile.name),
subtitle: Text('$activeProfileText${basalProfile.notes ?? ''}'), subtitle: Row(
children: [
Text(
'$activeProfileText${basalProfile.notes ?? ''}'),
Expanded(
child: Column(
children: dailyTotal > 0
? [
Text(dailyTotal.toStringAsPrecision(3)),
const Text('U/day', textScaleFactor: 0.75),
]
: [],
),
),
],
),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

View File

@ -321,10 +321,12 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
suffixText: 'mg/dl', suffixText: 'mg/dl',
), ),
controller: _mgPerDlController, controller: _mgPerDlController,
onChanged: (_) => onChanged: (_) async {
convertBetweenMgPerDlAndMmolPerL( await Future.delayed(const Duration(seconds: 1));
convertBetweenMgPerDlAndMmolPerL(
calculateFrom: calculateFrom:
GlucoseMeasurement.mgPerDl), GlucoseMeasurement.mgPerDl);
},
keyboardType: keyboardType:
const TextInputType.numberWithOptions(), const TextInputType.numberWithOptions(),
validator: (value) { validator: (value) {
@ -355,10 +357,12 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
suffixText: 'mmol/l', suffixText: 'mmol/l',
), ),
controller: _mmolPerLController, controller: _mmolPerLController,
onChanged: (_) => onChanged: (_) async {
convertBetweenMgPerDlAndMmolPerL( await Future.delayed(const Duration(seconds: 1));
convertBetweenMgPerDlAndMmolPerL(
calculateFrom: calculateFrom:
GlucoseMeasurement.mmolPerL), GlucoseMeasurement.mmolPerL);
},
keyboardType: keyboardType:
const TextInputType.numberWithOptions( const TextInputType.numberWithOptions(
decimal: true), decimal: true),

View File

@ -104,52 +104,80 @@ class _BolusListScreenState extends State<BolusListScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return widget.bolusRates.isNotEmpty ? SingleChildScrollView( return widget.bolusRates.isNotEmpty ? ListView.builder(
padding: const EdgeInsets.only(top: 10.0), shrinkWrap: true,
child: Column( itemCount: widget.bolusRates.length,
children: [ itemBuilder: (context, index) {
ListView.builder( final bolus = widget.bolusRates[index];
shrinkWrap: true, final error = validateTimePeriod(index);
itemCount: widget.bolusRates.length, return ListTile(
itemBuilder: (context, index) { isThreeLine: true,
final bolus = widget.bolusRates[index]; tileColor: error != null ? Colors.red.shade100 : null,
final error = validateTimePeriod(index); onTap: () {
return ListTile( handleEditAction(bolus);
isThreeLine: true, },
tileColor: error != null ? Colors.red.shade100 : null, title: Text(
onTap: () { '${DateTimeUtils.displayTime(bolus.startTime)} - ${DateTimeUtils.displayTime(bolus.endTime)}'),
handleEditAction(bolus); subtitle: Column(
}, children: [
title: Text( error != null
'${DateTimeUtils.displayTime(bolus.startTime)} - ${DateTimeUtils.displayTime(bolus.endTime)}'), ? Text(error,
subtitle: Column( style: const TextStyle(color: Colors.red))
mainAxisSize: MainAxisSize.max, : const Text(''),
crossAxisAlignment: CrossAxisAlignment.start, Row(
children: [ mainAxisSize: MainAxisSize.max,
Text( crossAxisAlignment: CrossAxisAlignment.start,
'${bolus.units} U per ${bolus.carbs}${Settings.nutritionMeasurementSuffix} carbs/${Settings.glucoseMeasurement == GlucoseMeasurement.mgPerDl ? bolus.mgPerDl : bolus.mmolPerL} ${Settings.glucoseMeasurementSuffix}'),
error != null
? Text(error,
style: const TextStyle(color: Colors.red))
: const Text('')
]),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
IconButton( Expanded(
icon: const Icon( child: Column(
Icons.delete, children: (bolus.units > 0 && bolus.carbs > 0)
color: Colors.blue, ? [
Text((bolus.carbs / bolus.units).toStringAsPrecision(2)),
const Text('carbs per U',
textScaleFactor: 0.75),
]
: [],
), ),
onPressed: () => handleDeleteAction(bolus),
), ),
], Expanded(
), child: Column(
); children: (bolus.units > 0 && bolus.carbs > 0)
}, ? [
Text((bolus.units / bolus.carbs * 12).toStringAsPrecision(2)),
const Text('U per bread unit',
textScaleFactor: 0.75),
]
: [],
),
),
Expanded(
child: Column(
children: (bolus.units > 0 && (bolus.mgPerDl ?? bolus.mmolPerL ?? 0) > 0)
? [
Text((((Settings.glucoseMeasurement == GlucoseMeasurement.mgPerDl ? bolus.mgPerDl : bolus.mmolPerL)! / bolus.units)).toString()),
Text('${Settings.glucoseMeasurementSuffix} per unit',
textScaleFactor: 0.75),
]
: [],
),
),
]),
],
), ),
], trailing: Row(
), mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(
Icons.delete,
color: Colors.blue,
),
onPressed: () => handleDeleteAction(bolus),
),
],
),
);
},
) : const Center( ) : const Center(
child: Text('You have not created any Bolus Rates yet!'), child: Text('You have not created any Bolus Rates yet!'),
); );

View File

@ -1,4 +1,5 @@
import 'package:diameter/components/dialogs.dart'; import 'package:diameter/components/dialogs.dart';
import 'package:diameter/models/glucose_target.dart';
import 'package:diameter/models/log_bolus.dart'; import 'package:diameter/models/log_bolus.dart';
import 'package:diameter/models/log_entry.dart'; import 'package:diameter/models/log_entry.dart';
import 'package:diameter/models/log_meal.dart'; import 'package:diameter/models/log_meal.dart';
@ -87,6 +88,10 @@ class _LogScreenState extends State<LogScreen> {
LogBolus.getTotalBolusForEntry(logEntry.id); LogBolus.getTotalBolusForEntry(logEntry.id);
double carbs = double carbs =
LogMeal.getTotalCarbsForEntry(logEntry.id); LogMeal.getTotalCarbsForEntry(logEntry.id);
TextStyle glucoseStyle = TextStyle(
color: GlucoseTarget.getColorForGlucose(
mgPerDl: logEntry.mgPerDl ?? 0,
mmolPerL: logEntry.mmolPerL ?? 0));
tiles.add(ListTile( tiles.add(ListTile(
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -117,9 +122,11 @@ class _LogScreenState extends State<LogScreen> {
GlucoseDisplayMode GlucoseDisplayMode
.bothForList) .bothForList)
? [ ? [
Text(logEntry.mgPerDl.toString()), Text(logEntry.mgPerDl.toString(),
const Text( style: glucoseStyle),
Text(
'mg/dl', 'mg/dl',
style: glucoseStyle,
textScaleFactor: 0.75, textScaleFactor: 0.75,
), ),
] ]
@ -137,9 +144,10 @@ class _LogScreenState extends State<LogScreen> {
GlucoseDisplayMode GlucoseDisplayMode
.bothForList) .bothForList)
? [ ? [
Text(logEntry.mmolPerL.toString()), Text(logEntry.mmolPerL.toString(), style: glucoseStyle),
const Text( Text(
'mmol/l', 'mmol/l',
style: glucoseStyle,
textScaleFactor: 0.75, textScaleFactor: 0.75,
), ),
] ]
@ -163,8 +171,8 @@ class _LogScreenState extends State<LogScreen> {
? [ ? [
Text(carbs.toStringAsPrecision(3)), Text(carbs.toStringAsPrecision(3)),
Text( Text(
Settings.nutritionMeasurementSuffix, '${Settings.nutritionMeasurementSuffix} carbs',
textScaleFactor: 0.75), textScaleFactor: 0.75),
] ]
: [], : [],
), ),
@ -182,13 +190,14 @@ class _LogScreenState extends State<LogScreen> {
], ],
), ),
)); ));
} }
return ListBody( return ListBody(
children: <Widget>[Text(DateTimeUtils.displayDate(date))] + tiles, children: <Widget>[
); Text(DateTimeUtils.displayDate(date))
] +
tiles,
);
}, },
) )
: const Center( : const Center(
child: Text('You have not created any Log Entries yet!'), child: Text('You have not created any Log Entries yet!'),

View File

@ -96,7 +96,7 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
: 0)) : 0))
.toString(); .toString();
_mgPerDlTargetController.text = _mgPerDlTargetController.text =
(_logBolus?.mgPerDlTarget ?? Settings.get().moderateGlucoseMgPerDl).toString(); (_logBolus?.mgPerDlTarget ?? Settings.targetMgPerDl()).toString();
_mgPerDlCorrectionController.text = (_logBolus?.mgPerDlCorrection ?? _mgPerDlCorrectionController.text = (_logBolus?.mgPerDlCorrection ??
max( max(
(int.tryParse(_mgPerDlCurrentController.text) ?? 0) - (int.tryParse(_mgPerDlCurrentController.text) ?? 0) -
@ -109,7 +109,7 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
: 0)) : 0))
.toString(); .toString();
_mmolPerLTargetController.text = _mmolPerLTargetController.text =
(_logBolus?.mmolPerLTarget ?? Settings.get().moderateGlucoseMmolPerL).toString(); (_logBolus?.mmolPerLTarget ?? Settings.targetMmolPerL()).toString();
_mmolPerLCorrectionController.text = (_logBolus?.mmolPerLCorrection ?? _mmolPerLCorrectionController.text = (_logBolus?.mmolPerLCorrection ??
max( max(
(double.tryParse(_mmolPerLCurrentController.text) ?? 0) - (double.tryParse(_mmolPerLCurrentController.text) ?? 0) -
@ -349,9 +349,9 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
_mmolPerLCurrentController.text != _mmolPerLCurrentController.text !=
(_logEntry?.mmolPerL.toString() ?? ''))) || (_logEntry?.mmolPerL.toString() ?? ''))) ||
_mgPerDlTargetController.text != _mgPerDlTargetController.text !=
Settings.get().moderateGlucoseMgPerDl.toString() || Settings.targetMgPerDl().toString() ||
_mmolPerLTargetController.text != _mmolPerLTargetController.text !=
Settings.get().moderateGlucoseMmolPerL.toString() || Settings.targetMmolPerL().toString() ||
_delayController.text != '' || _delayController.text != '' ||
_setManually || _setManually ||
_notesController.text != '')) || _notesController.text != '')) ||
@ -475,9 +475,12 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
suffixText: 'mg/dl', suffixText: 'mg/dl',
), ),
controller: _mgPerDlCurrentController, controller: _mgPerDlCurrentController,
onChanged: (_) => onChangeGlucose( onChanged: (_) async {
await Future.delayed(const Duration(seconds: 1));
onChangeGlucose(
calculateFrom: calculateFrom:
GlucoseMeasurement.mgPerDl), GlucoseMeasurement.mgPerDl);
},
keyboardType: const TextInputType keyboardType: const TextInputType
.numberWithOptions(), .numberWithOptions(),
), ),
@ -493,9 +496,12 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
suffixText: 'mg/dl', suffixText: 'mg/dl',
), ),
controller: _mgPerDlTargetController, controller: _mgPerDlTargetController,
onChanged: (_) => onChangeGlucose( onChanged: (_) async {
await Future.delayed(const Duration(seconds: 1));
onChangeGlucose(
calculateFrom: calculateFrom:
GlucoseMeasurement.mgPerDl), GlucoseMeasurement.mgPerDl);
},
keyboardType: const TextInputType keyboardType: const TextInputType
.numberWithOptions(), .numberWithOptions(),
), ),
@ -543,9 +549,12 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
), ),
controller: controller:
_mmolPerLCurrentController, _mmolPerLCurrentController,
onChanged: (_) => onChangeGlucose( onChanged: (_) async {
await Future.delayed(const Duration(seconds: 1));
onChangeGlucose(
calculateFrom: calculateFrom:
GlucoseMeasurement.mmolPerL), GlucoseMeasurement.mmolPerL);
},
keyboardType: const TextInputType keyboardType: const TextInputType
.numberWithOptions(), .numberWithOptions(),
), ),
@ -561,9 +570,12 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
suffixText: 'mmol/l', suffixText: 'mmol/l',
), ),
controller: _mmolPerLTargetController, controller: _mmolPerLTargetController,
onChanged: (_) => onChangeGlucose( onChanged: (_) async {
await Future.delayed(const Duration(seconds: 1));
onChangeGlucose(
calculateFrom: calculateFrom:
GlucoseMeasurement.mmolPerL), GlucoseMeasurement.mmolPerL);
},
keyboardType: const TextInputType keyboardType: const TextInputType
.numberWithOptions(), .numberWithOptions(),
), ),

View File

@ -82,53 +82,47 @@ class _LogBolusListScreenState extends State<LogBolusListScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return widget.logBoli.isNotEmpty
children: <Widget>[ ? ListView.builder(
Expanded( shrinkWrap: true,
child: widget.logBoli.isNotEmpty itemCount: widget.logBoli.length,
? ListView.builder( itemBuilder: (context, index) {
shrinkWrap: true, final bolus = widget.logBoli[index];
itemCount: widget.logBoli.length, String titleText = '${bolus.units} U ${(bolus.delay ?? 0) != 0
itemBuilder: (context, index) { ? ' (delayed by ${bolus.delay} min)'
final bolus = widget.logBoli[index]; : ''}';
String titleText = '${bolus.units} U ${(bolus.delay ?? 0) != 0 return ListTile(
? ' (delayed by ${bolus.delay} min)' onTap: () => handleEditAction(bolus),
: ''}'; title: Text(titleText),
return ListTile( subtitle: Text(bolus.carbs != null ?
onTap: () => handleEditAction(bolus), 'for ${bolus.meal.target.toString()} (${bolus.carbs}${Settings.nutritionMeasurementSuffix} carbs)'
title: Text(titleText), : 'to correct ${Settings.glucoseMeasurement == GlucoseMeasurement.mgPerDl ? bolus.mgPerDlCorrection : bolus.mmolPerLCorrection} ${Settings.glucoseMeasurementSuffix}'),
subtitle: Text(bolus.carbs != null ? trailing: Row(
'for ${bolus.meal.target.toString()} (${bolus.carbs}${Settings.nutritionMeasurementSuffix} carbs)' mainAxisSize: MainAxisSize.min,
: 'to correct ${Settings.glucoseMeasurement == GlucoseMeasurement.mgPerDl ? bolus.mgPerDlCorrection : bolus.mmolPerLCorrection} ${Settings.glucoseMeasurementSuffix}'), children: [
trailing: Row( bolus.meal.target != null
mainAxisSize: MainAxisSize.min, ? IconButton(
children: [ icon: const Icon(Icons.restaurant),
bolus.meal.target != null onPressed: () =>
? IconButton( handleEditMealAction(bolus.meal.targetId),
icon: const Icon(Icons.restaurant), )
onPressed: () => : Container(),
handleEditMealAction(bolus.meal.targetId), const SizedBox(width: 24),
) IconButton(
: Container(), icon: const Icon(
const SizedBox(width: 24), Icons.delete,
IconButton( color: Colors.blue,
icon: const Icon(
Icons.delete,
color: Colors.blue,
),
onPressed: () => handleDeleteAction(bolus),
),
],
), ),
); onPressed: () => handleDeleteAction(bolus),
}, ),
) ],
: const Center(
child: Text(
'You have not added any Boli to this Log Entry yet!'),
), ),
), );
], },
); )
: const Center(
child: Text(
'You have not added any Boli to this Log Entry yet!'),
);
} }
} }

View File

@ -310,8 +310,12 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
), ),
Row( Row(
children: [ children: [
Settings.glucoseMeasurement == GlucoseMeasurement.mgPerDl || Settings.glucoseMeasurement ==
[GlucoseDisplayMode.both, GlucoseDisplayMode.bothForDetail].contains(Settings.glucoseDisplayMode) GlucoseMeasurement.mgPerDl ||
[
GlucoseDisplayMode.both,
GlucoseDisplayMode.bothForDetail
].contains(Settings.glucoseDisplayMode)
? Expanded( ? Expanded(
child: TextFormField( child: TextFormField(
decoration: const InputDecoration( decoration: const InputDecoration(
@ -319,10 +323,13 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
suffixText: 'mg/dl', suffixText: 'mg/dl',
), ),
controller: _mgPerDlController, controller: _mgPerDlController,
onChanged: (_) => onChanged: (_) async {
convertBetweenMgPerDlAndMmolPerL( await Future.delayed(
calculateFrom: const Duration(seconds: 1));
GlucoseMeasurement.mgPerDl), convertBetweenMgPerDlAndMmolPerL(
calculateFrom:
GlucoseMeasurement.mgPerDl);
},
keyboardType: keyboardType:
const TextInputType.numberWithOptions(), const TextInputType.numberWithOptions(),
validator: (value) { validator: (value) {
@ -337,7 +344,8 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
), ),
) )
: Container(), : Container(),
Settings.glucoseDisplayMode == GlucoseDisplayMode.both || Settings.glucoseDisplayMode ==
GlucoseDisplayMode.both ||
Settings.glucoseDisplayMode == Settings.glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail GlucoseDisplayMode.bothForDetail
? IconButton( ? IconButton(
@ -348,7 +356,8 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
icon: const Icon(Icons.calculate), icon: const Icon(Icons.calculate),
) )
: Container(), : Container(),
Settings.glucoseMeasurement == GlucoseMeasurement.mmolPerL || Settings.glucoseMeasurement ==
GlucoseMeasurement.mmolPerL ||
Settings.glucoseDisplayMode == Settings.glucoseDisplayMode ==
GlucoseDisplayMode.both || GlucoseDisplayMode.both ||
Settings.glucoseDisplayMode == Settings.glucoseDisplayMode ==
@ -360,10 +369,13 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
suffixText: 'mmol/l', suffixText: 'mmol/l',
), ),
controller: _mmolPerLController, controller: _mmolPerLController,
onChanged: (_) => onChanged: (_) async {
convertBetweenMgPerDlAndMmolPerL( await Future.delayed(
calculateFrom: const Duration(seconds: 1));
GlucoseMeasurement.mmolPerL), convertBetweenMgPerDlAndMmolPerL(
calculateFrom:
GlucoseMeasurement.mmolPerL);
},
keyboardType: keyboardType:
const TextInputType.numberWithOptions( const TextInputType.numberWithOptions(
decimal: true), decimal: true),
@ -379,7 +391,8 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
), ),
) )
: Container(), : Container(),
Settings.glucoseDisplayMode == GlucoseDisplayMode.both || Settings.glucoseDisplayMode ==
GlucoseDisplayMode.both ||
Settings.glucoseDisplayMode == Settings.glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail GlucoseDisplayMode.bothForDetail
? IconButton( ? IconButton(

View File

@ -303,8 +303,10 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
controller: _carbsRatioController, controller: _carbsRatioController,
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
decimal: true), decimal: true),
onChanged: (_) => onChanged: (_) async {
calculateThirdMeasurementOfPortionCarbsRelation(), await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
), ),
), ),
IconButton( IconButton(
@ -330,8 +332,10 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
controller: _portionSizeController, controller: _portionSizeController,
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
decimal: true), decimal: true),
onChanged: (_) => onChanged: (_) async {
calculateThirdMeasurementOfPortionCarbsRelation(), await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
), ),
), ),
IconButton( IconButton(
@ -365,8 +369,10 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
controller: _carbsPerPortionController, controller: _carbsPerPortionController,
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
decimal: true), decimal: true),
onChanged: (_) => onChanged: (_) async {
calculateThirdMeasurementOfPortionCarbsRelation(), await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
), ),
), ),
IconButton( IconButton(

View File

@ -66,45 +66,44 @@ class _LogMealListScreenState extends State<LogMealListScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return widget.logMeals.isNotEmpty
children: <Widget>[ ? ListView.builder(
Expanded( shrinkWrap: true,
child: widget.logMeals.isNotEmpty itemCount: widget.logMeals.length,
? ListView.builder( itemBuilder: (context, index) {
shrinkWrap: true, final meal = widget.logMeals[index];
itemCount: widget.logMeals.length, return ListTile(
itemBuilder: (context, index) { onTap: () => handleEditAction(meal),
final meal = widget.logMeals[index]; title: Row(
return ListTile( children: [
onTap: () => handleEditAction(meal), Expanded(child: Text(meal.value)),
title: Row( Expanded(
children: [ child: Column(
Expanded(child: Text(meal.value)), children: ((meal.carbsPerPortion ?? 0) > 0)
Expanded( ? [
child: Text(meal.carbsPerPortion != null Text(meal.carbsPerPortion!.toStringAsPrecision(3)),
? '${meal.carbsPerPortion} g carbs' Text(
: '')), '${Settings.nutritionMeasurementSuffix} carbs',
Expanded( textScaleFactor: 0.75),
child: Text( ]
meal.bolus != null ? '${meal.bolus} U' : '')) : [],
],
),
trailing: IconButton(
icon: const Icon(
Icons.delete,
color: Colors.blue,
), ),
onPressed: () => handleDeleteAction(meal),
), ),
); ],
},
)
: const Center(
child: Text(
'You have not added any Meals to this Log Entry yet!'),
), ),
), trailing: IconButton(
], icon: const Icon(
); Icons.delete,
color: Colors.blue,
),
onPressed: () => handleDeleteAction(meal),
),
);
},
)
: const Center(
child: Text(
'You have not added any Meals to this Log Entry yet!'),
);
} }
} }

View File

@ -33,10 +33,11 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
final _carbsRatioController = TextEditingController(text: ''); final _carbsRatioController = TextEditingController(text: '');
final _portionSizeController = TextEditingController(text: ''); final _portionSizeController = TextEditingController(text: '');
final _carbsPerPortionController = TextEditingController(text: ''); final _carbsPerPortionController = TextEditingController(text: '');
final _delayedBolusRateController = TextEditingController(text: '');
final _delayedBolusDurationController = TextEditingController(text: ''); final _delayedBolusDurationController = TextEditingController(text: '');
final _notesController = TextEditingController(text: ''); final _notesController = TextEditingController(text: '');
double _delayedBolusPercentage = 0;
MealSource? _mealSource; MealSource? _mealSource;
MealCategory? _mealCategory; MealCategory? _mealCategory;
MealPortionType? _mealPortionType; MealPortionType? _mealPortionType;
@ -67,8 +68,8 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
_portionSizeController.text = (_meal!.portionSize ?? '').toString(); _portionSizeController.text = (_meal!.portionSize ?? '').toString();
_carbsPerPortionController.text = _carbsPerPortionController.text =
(_meal!.carbsPerPortion ?? '').toString(); (_meal!.carbsPerPortion ?? '').toString();
_delayedBolusRateController.text = _delayedBolusPercentage =
(_meal!.delayedBolusRate ?? '').toString(); _meal!.delayedBolusPercentage ?? 0;
_delayedBolusDurationController.text = _delayedBolusDurationController.text =
(_meal!.delayedBolusDuration ?? '').toString(); (_meal!.delayedBolusDuration ?? '').toString();
_notesController.text = _meal!.notes ?? ''; _notesController.text = _meal!.notes ?? '';
@ -103,7 +104,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
carbsPerPortion: double.tryParse(_carbsPerPortionController.text), carbsPerPortion: double.tryParse(_carbsPerPortionController.text),
delayedBolusDuration: delayedBolusDuration:
int.tryParse(_delayedBolusDurationController.text), int.tryParse(_delayedBolusDurationController.text),
delayedBolusRate: double.tryParse(_delayedBolusRateController.text), delayedBolusPercentage: _delayedBolusPercentage,
notes: _notesController.text, notes: _notesController.text,
); );
meal.mealSource.target = _mealSource; meal.mealSource.target = _mealSource;
@ -134,7 +135,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
_portionSizeAccuracy != null || _portionSizeAccuracy != null ||
int.tryParse(_delayedBolusDurationController.text) != int.tryParse(_delayedBolusDurationController.text) !=
null || null ||
double.tryParse(_delayedBolusRateController.text) != null || _delayedBolusPercentage != 0 ||
_notesController.text != '')) || _notesController.text != '')) ||
(!_isNew && (!_isNew &&
(_valueController.text != _meal!.value || (_valueController.text != _meal!.value ||
@ -151,8 +152,8 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
_portionSizeAccuracy != _meal!.portionSizeAccuracy.target || _portionSizeAccuracy != _meal!.portionSizeAccuracy.target ||
int.tryParse(_delayedBolusDurationController.text) != int.tryParse(_delayedBolusDurationController.text) !=
_meal!.delayedBolusDuration || _meal!.delayedBolusDuration ||
double.tryParse(_delayedBolusRateController.text) != _delayedBolusPercentage !=
_meal!.delayedBolusRate || _meal!.delayedBolusPercentage ||
_notesController.text != (_meal!.notes ?? ''))))) { _notesController.text != (_meal!.notes ?? ''))))) {
Dialogs.showCancelConfirmationDialog( Dialogs.showCancelConfirmationDialog(
context: context, context: context,
@ -284,15 +285,17 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
children: [ children: [
Expanded( Expanded(
child: TextFormField( child: TextFormField(
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Carbs ratio', labelText: 'Carbs ratio',
suffixText: '%', suffixText: '%',
), ),
controller: _carbsRatioController, controller: _carbsRatioController,
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
decimal: true), decimal: true),
onChanged: (_) => onChanged: (_) async {
calculateThirdMeasurementOfPortionCarbsRelation(), await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
), ),
), ),
IconButton( IconButton(
@ -311,15 +314,16 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
child: TextFormField( child: TextFormField(
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Portion size', labelText: 'Portion size',
suffixText: suffixText: Settings.nutritionMeasurementSuffix,
Settings.nutritionMeasurementSuffix,
alignLabelWithHint: true, alignLabelWithHint: true,
), ),
controller: _portionSizeController, controller: _portionSizeController,
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
decimal: true), decimal: true),
onChanged: (_) => onChanged: (_) async {
calculateThirdMeasurementOfPortionCarbsRelation(), await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
), ),
), ),
IconButton( IconButton(
@ -347,14 +351,15 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
child: TextFormField( child: TextFormField(
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Carbs per portion', labelText: 'Carbs per portion',
suffixText: suffixText: Settings.nutritionMeasurementSuffix,
Settings.nutritionMeasurementSuffix,
), ),
controller: _carbsPerPortionController, controller: _carbsPerPortionController,
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
decimal: true), decimal: true),
onChanged: (_) => onChanged: (_) async {
calculateThirdMeasurementOfPortionCarbsRelation(), await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
), ),
), ),
IconButton( IconButton(
@ -386,14 +391,27 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
controller: _delayedBolusDurationController, controller: _delayedBolusDurationController,
keyboardType: const TextInputType.numberWithOptions(), keyboardType: const TextInputType.numberWithOptions(),
), ),
TextFormField( Padding(
decoration: const InputDecoration( padding: const EdgeInsets.symmetric(horizontal: 5.0),
labelText: 'Delayed Bolus Units', child: Row(
suffixText: ' U', children: [
const Text('Delayed Bolus Percentage:'),
Expanded(
child: Slider(
label: '${_delayedBolusPercentage.floor().toString()}%',
divisions: 100,
value: _delayedBolusPercentage,
min: 0,
max: 100,
onChanged: (value) {
setState(() {
_delayedBolusPercentage = value;
});
}
),
),
],
), ),
controller: _delayedBolusRateController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
), ),
TextFormField( TextFormField(
controller: _notesController, controller: _notesController,

View File

@ -73,8 +73,9 @@ class _MealListScreenState extends State<MealListScreen> {
itemCount: _meals.length, itemCount: _meals.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final meal = _meals[index]; final meal = _meals[index];
String portionType = meal.mealPortionType.hasValue ? ' per ${meal.mealPortionType.target!.value}' : '';
return ListTile( return ListTile(
isThreeLine: true,
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
@ -85,7 +86,40 @@ class _MealListScreenState extends State<MealListScreen> {
).then((message) => reload(message: message)); ).then((message) => reload(message: message));
}, },
title: Text(meal.value), title: Text(meal.value),
subtitle: Text(meal.notes ?? ''), subtitle: Row(
children: [
Column(
children: [
Text(meal.mealSource.target?.value ?? ''),
Text(meal.notes ?? ''),
],
),
Expanded(
child: Column(
children: ((meal.carbsPerPortion ?? 0) > 0)
? [
Text(meal.carbsPerPortion!.toStringAsPrecision(3)),
Text(
'${Settings.nutritionMeasurementSuffix} carbs',
textScaleFactor: 0.75),
]
: [],
),
),
Expanded(
child: Column(
children: (meal.mealPortionType.hasValue)
? [
Text(meal.portionSize!.toStringAsPrecision(3)),
Text(
'${Settings.nutritionMeasurementSuffix}$portionType',
textScaleFactor: 0.75),
]
: [],
),
),
],
),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [