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:
☐ fix preloading of dropdown values (appear blank at first as of now)
☐ make sure 'null' isn't shown in text fields
Log Entry:
☐ glucose target isn't displaed correctly anymore
Basal/Bolus:
☐ "no element" error on creating basal/bolus rates when working from apk
☐ scrollbars in rate overview not showing
MAIN TASKS:
Layout:
@ -20,23 +21,15 @@ MAIN TASKS:
☐ add clear button to dropdown (or all text fields?)
☐ check through all detail forms and set required fields/according messages
☐ 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:
☐ show daily Basal sum in overview
☐ show KI and stuff for Bolus in overview
☐ add save and close and next buttons on rate creations
Log Overview:
☐ apply target color settings to glucose
Log Entry:
☐ add save and close button
☐ move on to newly created entry after saving
☐ handle text overflow for log meal list
☐ add option to specify trend for blood sugar
☐ recalculate bolus upon deactivating 'set manually' option
☐ account for delayed percentage setting on meals
Meal:
☐ change delayed bolus rate to percentage
☐ add meal source as subtitle in list
Event Types:
☐ add colors as indicators for log entries (and later graphs in reports)
Settings:
@ -44,6 +37,7 @@ MAIN TASKS:
☐ add fields for preferred date and time formats
☐ add fields for glucose target (as map of cutoff glucose and colors)
☐ add field for active insulin duration
☐ add setting for carb units/bread units
☐ add option to switch 'save' and 'save & close' buttons
FUTURE TASKS:
@ -52,14 +46,13 @@ FUTURE TASKS:
☐ find a better way to work with multiple glucose measurements (or disable it?)
☐ evaluate if some fields should be readonly instead of completely hidden
☐ alternate languages
☐ log hba1c
Reports:
☐ evaluate what type of reports there should be
Basal/Bolus:
Log Overview:
☐ add pagination
Log Entry:
☐ check if there is still an active bolus when suggesting glucose bolus
Meal:
Event Types:
☐ add pagination
☐ implement reminders as push notifications
@ -67,6 +60,15 @@ FUTURE TASKS:
☐ add option to hide extra customization options (ie. changing pre calculated values)?
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)
✔ 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)

View File

@ -48,6 +48,25 @@ class Basal {
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
String toString() {
return DateTimeUtils.displayTime(startTime);

View File

@ -28,7 +28,8 @@ class BasalProfile {
static void put(BasalProfile basalProfile) => box.put(basalProfile);
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();
}

View File

@ -29,7 +29,7 @@ class BolusProfile {
static List<BolusProfile> getAll() {
QueryBuilder<BolusProfile> all =
box.query(BolusProfile_.deleted.equals(false));
box.query(BolusProfile_.deleted.equals(false))..order(BolusProfile_.name);
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) {
final entry = box.get(id);
if (((entry?.mgPerDl ?? 0) > Settings.get().moderateGlucoseMgPerDl ||
(entry?.mmolPerL ?? 0) > Settings.get().moderateGlucoseMmolPerL)) {
if (((entry?.mgPerDl ?? 0) > Settings.targetMgPerDl() ||
(entry?.mmolPerL ?? 0) > Settings.targetMmolPerL())) {
return !LogBolus.glucoseBolusForEntryExists(id);
}
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_portion_type.dart';
import 'package:diameter/models/meal_source.dart';
import 'package:diameter/objectbox.g.dart' show Meal_;
import 'package:objectbox/objectbox.dart';
enum PortionCarbsParameter { carbsRatio, portionSize, carbsPerPortion }
@ -19,7 +20,7 @@ class Meal {
double? portionSize;
double? carbsPerPortion;
int? delayedBolusDuration;
double? delayedBolusRate;
double? delayedBolusPercentage;
String? notes;
// relations
@ -38,7 +39,7 @@ class Meal {
this.portionSize,
this.carbsPerPortion,
this.delayedBolusDuration,
this.delayedBolusRate,
this.delayedBolusPercentage,
this.notes,
});
@ -46,7 +47,10 @@ class Meal {
static Meal? get(int id) => box.get(id);
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) {
final item = box.get(id);

View File

@ -1,5 +1,6 @@
import 'package:diameter/main.dart';
import 'package:objectbox/objectbox.dart';
import 'package:diameter/objectbox.g.dart' show MealCategory_;
@Entity(uid: 3158200688796904913)
class MealCategory {
@ -23,7 +24,10 @@ class MealCategory {
static MealCategory? get(int id) => box.get(id);
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) {
final item = box.get(id);

View File

@ -1,5 +1,6 @@
import 'package:diameter/main.dart';
import 'package:objectbox/objectbox.dart';
import 'package:diameter/objectbox.g.dart' show MealPortionType_;
@Entity(uid: 2111511899235985637)
class MealPortionType {
@ -23,7 +24,10 @@ class MealPortionType {
static MealPortionType? get(int id) => box.get(id);
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) {
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_portion_type.dart';
import 'package:objectbox/objectbox.dart';
import 'package:diameter/objectbox.g.dart' show MealSource_;
@Entity(uid: 1283034494527412242)
class MealSource {
@ -32,7 +33,10 @@ class MealSource {
static MealSource? get(int id) => box.get(id);
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) {
final item = box.get(id);

View File

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

View File

@ -439,7 +439,7 @@
},
{
"id": "10:382130101578692012",
"lastPropertyId": "14:3567196286623536415",
"lastPropertyId": "15:8283810711091063880",
"name": "Meal",
"properties": [
{
@ -473,11 +473,6 @@
"name": "delayedBolusDuration",
"type": 6
},
{
"id": "7:2172890064639236018",
"name": "delayedBolusRate",
"type": 8
},
{
"id": "8:6111684052388229887",
"name": "notes",
@ -527,6 +522,11 @@
"id": "14:3567196286623536415",
"name": "deleted",
"type": 1
},
{
"id": "15:8283810711091063880",
"name": "delayedBolusPercentage",
"type": 8
}
],
"relations": []
@ -794,7 +794,7 @@
},
{
"id": "16:3989341091218179227",
"lastPropertyId": "20:6560414475711071975",
"lastPropertyId": "22:3595473653451456068",
"name": "Settings",
"properties": [
{
@ -838,36 +838,6 @@
"name": "showConfirmationDialogOnStopEvent",
"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",
"name": "nutritionMeasurementIndex",
@ -882,12 +852,66 @@
"id": "20:6560414475711071975",
"name": "glucoseMeasurementIndex",
"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": []
}
],
"lastEntityId": "16:3989341091218179227",
"lastEntityId": "17:5041265995704044399",
"lastIndexId": "28:4563029809754152081",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
@ -918,7 +942,14 @@
8031421171668506924,
1614362036318874174,
1675040259141389754,
7518219134349037920
7518219134349037920,
2172890064639236018,
310032577683835406,
5588897884422150510,
7638848982383620744,
3282706593658092097,
596980591281311896,
3633551763915044903
],
"retiredRelationUids": [],
"version": 1

View File

@ -14,6 +14,7 @@ import 'models/basal.dart';
import 'models/basal_profile.dart';
import 'models/bolus.dart';
import 'models/bolus_profile.dart';
import 'models/glucose_target.dart';
import 'models/log_bolus.dart';
import 'models/log_entry.dart';
import 'models/log_event.dart';
@ -451,7 +452,7 @@ final _entities = <ModelEntity>[
ModelEntity(
id: const IdUid(10, 382130101578692012),
name: 'Meal',
lastPropertyId: const IdUid(14, 3567196286623536415),
lastPropertyId: const IdUid(15, 8283810711091063880),
flags: 0,
properties: <ModelProperty>[
ModelProperty(
@ -484,11 +485,6 @@ final _entities = <ModelEntity>[
name: 'delayedBolusDuration',
type: 6,
flags: 0),
ModelProperty(
id: const IdUid(7, 2172890064639236018),
name: 'delayedBolusRate',
type: 8,
flags: 0),
ModelProperty(
id: const IdUid(8, 6111684052388229887),
name: 'notes',
@ -533,6 +529,11 @@ final _entities = <ModelEntity>[
id: const IdUid(14, 3567196286623536415),
name: 'deleted',
type: 1,
flags: 0),
ModelProperty(
id: const IdUid(15, 8283810711091063880),
name: 'delayedBolusPercentage',
type: 8,
flags: 0)
],
relations: <ModelRelation>[],
@ -794,7 +795,7 @@ final _entities = <ModelEntity>[
ModelEntity(
id: const IdUid(16, 3989341091218179227),
name: 'Settings',
lastPropertyId: const IdUid(20, 6560414475711071975),
lastPropertyId: const IdUid(22, 3595473653451456068),
flags: 0,
properties: <ModelProperty>[
ModelProperty(
@ -837,36 +838,6 @@ final _entities = <ModelEntity>[
name: 'showConfirmationDialogOnStopEvent',
type: 1,
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(
id: const IdUid(18, 1203593429961092769),
name: 'nutritionMeasurementIndex',
@ -881,6 +852,60 @@ final _entities = <ModelEntity>[
id: const IdUid(20, 6560414475711071975),
name: 'glucoseMeasurementIndex',
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)
],
relations: <ModelRelation>[],
@ -907,7 +932,7 @@ Future<Store> openStore(
ModelDefinition getObjectBoxModel() {
final model = ModelInfo(
entities: _entities,
lastEntityId: const IdUid(16, 3989341091218179227),
lastEntityId: const IdUid(17, 5041265995704044399),
lastIndexId: const IdUid(28, 4563029809754152081),
lastRelationId: const IdUid(0, 0),
lastSequenceId: const IdUid(0, 0),
@ -931,7 +956,14 @@ ModelDefinition getObjectBoxModel() {
8031421171668506924,
1614362036318874174,
1675040259141389754,
7518219134349037920
7518219134349037920,
2172890064639236018,
310032577683835406,
5588897884422150510,
7638848982383620744,
3282706593658092097,
596980591281311896,
3633551763915044903
],
retiredRelationUids: const [],
modelVersion: 5,
@ -1346,14 +1378,13 @@ ModelDefinition getObjectBoxModel() {
final valueOffset = fbb.writeString(object.value);
final notesOffset =
object.notes == null ? null : fbb.writeString(object.notes!);
fbb.startTable(15);
fbb.startTable(16);
fbb.addInt64(0, object.id);
fbb.addOffset(1, valueOffset);
fbb.addFloat64(2, object.carbsRatio);
fbb.addFloat64(3, object.portionSize);
fbb.addFloat64(4, object.carbsPerPortion);
fbb.addInt64(5, object.delayedBolusDuration);
fbb.addFloat64(6, object.delayedBolusRate);
fbb.addOffset(7, notesOffset);
fbb.addInt64(8, object.mealSource.targetId);
fbb.addInt64(9, object.mealCategory.targetId);
@ -1361,6 +1392,7 @@ ModelDefinition getObjectBoxModel() {
fbb.addInt64(11, object.portionSizeAccuracy.targetId);
fbb.addInt64(12, object.carbsRatioAccuracy.targetId);
fbb.addBool(13, object.deleted);
fbb.addFloat64(14, object.delayedBolusPercentage);
fbb.finish(fbb.endTable());
return object.id;
},
@ -1382,8 +1414,8 @@ ModelDefinition getObjectBoxModel() {
.vTableGetNullable(buffer, rootOffset, 12),
delayedBolusDuration: const fb.Int64Reader()
.vTableGetNullable(buffer, rootOffset, 14),
delayedBolusRate: const fb.Float64Reader()
.vTableGetNullable(buffer, rootOffset, 16),
delayedBolusPercentage: const fb.Float64Reader()
.vTableGetNullable(buffer, rootOffset, 32),
notes: const fb.StringReader()
.vTableGetNullable(buffer, rootOffset, 18));
object.mealSource.targetId =
@ -1662,7 +1694,7 @@ ModelDefinition getObjectBoxModel() {
final longTimeFormatOffset = object.longTimeFormat == null
? null
: fbb.writeString(object.longTimeFormat!);
fbb.startTable(21);
fbb.startTable(23);
fbb.addInt64(0, object.id);
fbb.addOffset(1, dateFormatOffset);
fbb.addOffset(2, longDateFormatOffset);
@ -1671,15 +1703,11 @@ ModelDefinition getObjectBoxModel() {
fbb.addBool(5, object.showConfirmationDialogOnCancel);
fbb.addBool(6, object.showConfirmationDialogOnDelete);
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(18, object.glucoseDisplayModeIndex);
fbb.addInt64(19, object.glucoseMeasurementIndex);
fbb.addInt64(20, object.targetGlucoseMgPerDl);
fbb.addFloat64(21, object.targetGlucoseMmolPerL);
fbb.finish(fbb.endTable());
return object.id;
},
@ -1709,14 +1737,51 @@ ModelDefinition getObjectBoxModel() {
.vTableGet(buffer, rootOffset, 16, false),
showConfirmationDialogOnStopEvent: const fb.BoolReader()
.vTableGet(buffer, rootOffset, 18, false),
lowGlucoseMgPerDl:
const fb.Int64Reader().vTableGet(buffer, rootOffset, 20, 0),
moderateGlucoseMgPerDl:
const fb.Int64Reader().vTableGet(buffer, rootOffset, 22, 0),
highGlucoseMgPerDl: const fb.Int64Reader().vTableGet(buffer, rootOffset, 24, 0),
lowGlucoseMmolPerL: const fb.Float64Reader().vTableGet(buffer, rootOffset, 26, 0),
moderateGlucoseMmolPerL: const fb.Float64Reader().vTableGet(buffer, rootOffset, 28, 0),
highGlucoseMmolPerDl: const fb.Float64Reader().vTableGet(buffer, rootOffset, 30, 0));
targetGlucoseMgPerDl:
const fb.Int64Reader().vTableGet(buffer, rootOffset, 44, 0),
targetGlucoseMmolPerL:
const fb.Float64Reader().vTableGet(buffer, rootOffset, 46, 0));
return object;
}),
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;
})
@ -2018,36 +2083,36 @@ class Meal_ {
static final delayedBolusDuration =
QueryIntegerProperty<Meal>(_entities[8].properties[5]);
/// see [Meal.delayedBolusRate]
static final delayedBolusRate =
QueryDoubleProperty<Meal>(_entities[8].properties[6]);
/// see [Meal.notes]
static final notes = QueryStringProperty<Meal>(_entities[8].properties[7]);
static final notes = QueryStringProperty<Meal>(_entities[8].properties[6]);
/// see [Meal.mealSource]
static final mealSource =
QueryRelationToOne<Meal, MealSource>(_entities[8].properties[8]);
QueryRelationToOne<Meal, MealSource>(_entities[8].properties[7]);
/// see [Meal.mealCategory]
static final mealCategory =
QueryRelationToOne<Meal, MealCategory>(_entities[8].properties[9]);
QueryRelationToOne<Meal, MealCategory>(_entities[8].properties[8]);
/// see [Meal.mealPortionType]
static final mealPortionType =
QueryRelationToOne<Meal, MealPortionType>(_entities[8].properties[10]);
QueryRelationToOne<Meal, MealPortionType>(_entities[8].properties[9]);
/// see [Meal.portionSizeAccuracy]
static final portionSizeAccuracy =
QueryRelationToOne<Meal, Accuracy>(_entities[8].properties[11]);
QueryRelationToOne<Meal, Accuracy>(_entities[8].properties[10]);
/// see [Meal.carbsRatioAccuracy]
static final carbsRatioAccuracy =
QueryRelationToOne<Meal, Accuracy>(_entities[8].properties[12]);
QueryRelationToOne<Meal, Accuracy>(_entities[8].properties[11]);
/// see [Meal.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.
@ -2253,39 +2318,54 @@ class Settings_ {
static final showConfirmationDialogOnStopEvent =
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]
static final nutritionMeasurementIndex =
QueryIntegerProperty<Settings>(_entities[14].properties[14]);
QueryIntegerProperty<Settings>(_entities[14].properties[8]);
/// see [Settings.glucoseDisplayModeIndex]
static final glucoseDisplayModeIndex =
QueryIntegerProperty<Settings>(_entities[14].properties[15]);
QueryIntegerProperty<Settings>(_entities[14].properties[9]);
/// see [Settings.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,10 +108,7 @@ class _BasalListScreenState extends State<BasalListScreen> {
@override
Widget build(BuildContext context) {
return widget.basalRates.isNotEmpty ? SingleChildScrollView(
child: Column(
children: [
ListView.builder(
return widget.basalRates.isNotEmpty ? ListView.builder(
shrinkWrap: true,
itemCount: widget.basalRates.length,
itemBuilder: (context, index) {
@ -149,10 +146,7 @@ class _BasalListScreenState extends State<BasalListScreen> {
),
);
},
),
],
),
): const Center(
) : const Center(
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/dropdown.dart';
import 'package:diameter/models/basal.dart';
import 'package:diameter/models/settings.dart';
import 'package:diameter/navigation.dart';
import 'package:flutter/material.dart';
@ -167,19 +168,38 @@ class _BasalProfileListScreenState extends State<BasalProfileListScreen> {
itemCount: _basalProfiles.length,
itemBuilder: (context, index) {
final basalProfile = _basalProfiles[index];
double dailyTotal =
Basal.getDailyTotalForProfile(basalProfile.id);
String activeProfileText = basalProfile.active
? 'Default Profile'
: basalProfile.id == _activeProfile?.id
? 'Current Active Profile'
: '';
if (activeProfileText != '' && (basalProfile.notes ?? '') != '') {
if (activeProfileText != '' &&
(basalProfile.notes ?? '') != '') {
activeProfileText += '\n';
}
return ListTile(
selected: basalProfile.active || basalProfile.id == _activeProfile?.id,
selected: basalProfile.active ||
basalProfile.id == _activeProfile?.id,
onTap: () => onEdit(basalProfile),
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(
mainAxisSize: MainAxisSize.min,
children: [

View File

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

View File

@ -104,11 +104,7 @@ class _BolusListScreenState extends State<BolusListScreen> {
@override
Widget build(BuildContext context) {
return widget.bolusRates.isNotEmpty ? SingleChildScrollView(
padding: const EdgeInsets.only(top: 10.0),
child: Column(
children: [
ListView.builder(
return widget.bolusRates.isNotEmpty ? ListView.builder(
shrinkWrap: true,
itemCount: widget.bolusRates.length,
itemBuilder: (context, index) {
@ -123,16 +119,51 @@ class _BolusListScreenState extends State<BolusListScreen> {
title: Text(
'${DateTimeUtils.displayTime(bolus.startTime)} - ${DateTimeUtils.displayTime(bolus.endTime)}'),
subtitle: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${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('')
: const Text(''),
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
children: (bolus.units > 0 && bolus.carbs > 0)
? [
Text((bolus.carbs / bolus.units).toStringAsPrecision(2)),
const Text('carbs per U',
textScaleFactor: 0.75),
]
: [],
),
),
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: [
@ -147,9 +178,6 @@ class _BolusListScreenState extends State<BolusListScreen> {
),
);
},
),
],
),
) : const Center(
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/models/glucose_target.dart';
import 'package:diameter/models/log_bolus.dart';
import 'package:diameter/models/log_entry.dart';
import 'package:diameter/models/log_meal.dart';
@ -87,6 +88,10 @@ class _LogScreenState extends State<LogScreen> {
LogBolus.getTotalBolusForEntry(logEntry.id);
double carbs =
LogMeal.getTotalCarbsForEntry(logEntry.id);
TextStyle glucoseStyle = TextStyle(
color: GlucoseTarget.getColorForGlucose(
mgPerDl: logEntry.mgPerDl ?? 0,
mmolPerL: logEntry.mmolPerL ?? 0));
tiles.add(ListTile(
onTap: () {
Navigator.push(
@ -117,9 +122,11 @@ class _LogScreenState extends State<LogScreen> {
GlucoseDisplayMode
.bothForList)
? [
Text(logEntry.mgPerDl.toString()),
const Text(
Text(logEntry.mgPerDl.toString(),
style: glucoseStyle),
Text(
'mg/dl',
style: glucoseStyle,
textScaleFactor: 0.75,
),
]
@ -137,9 +144,10 @@ class _LogScreenState extends State<LogScreen> {
GlucoseDisplayMode
.bothForList)
? [
Text(logEntry.mmolPerL.toString()),
const Text(
Text(logEntry.mmolPerL.toString(), style: glucoseStyle),
Text(
'mmol/l',
style: glucoseStyle,
textScaleFactor: 0.75,
),
]
@ -163,7 +171,7 @@ class _LogScreenState extends State<LogScreen> {
? [
Text(carbs.toStringAsPrecision(3)),
Text(
Settings.nutritionMeasurementSuffix,
'${Settings.nutritionMeasurementSuffix} carbs',
textScaleFactor: 0.75),
]
: [],
@ -182,13 +190,14 @@ class _LogScreenState extends State<LogScreen> {
],
),
));
}
return ListBody(
children: <Widget>[Text(DateTimeUtils.displayDate(date))] + tiles,
children: <Widget>[
Text(DateTimeUtils.displayDate(date))
] +
tiles,
);
},
)
: const Center(
child: Text('You have not created any Log Entries yet!'),

View File

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

View File

@ -82,10 +82,7 @@ class _LogBolusListScreenState extends State<LogBolusListScreen> {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: widget.logBoli.isNotEmpty
return widget.logBoli.isNotEmpty
? ListView.builder(
shrinkWrap: true,
itemCount: widget.logBoli.length,
@ -126,9 +123,6 @@ class _LogBolusListScreenState extends State<LogBolusListScreen> {
: 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(
children: [
Settings.glucoseMeasurement == GlucoseMeasurement.mgPerDl ||
[GlucoseDisplayMode.both, GlucoseDisplayMode.bothForDetail].contains(Settings.glucoseDisplayMode)
Settings.glucoseMeasurement ==
GlucoseMeasurement.mgPerDl ||
[
GlucoseDisplayMode.both,
GlucoseDisplayMode.bothForDetail
].contains(Settings.glucoseDisplayMode)
? Expanded(
child: TextFormField(
decoration: const InputDecoration(
@ -319,10 +323,13 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
suffixText: 'mg/dl',
),
controller: _mgPerDlController,
onChanged: (_) =>
onChanged: (_) async {
await Future.delayed(
const Duration(seconds: 1));
convertBetweenMgPerDlAndMmolPerL(
calculateFrom:
GlucoseMeasurement.mgPerDl),
GlucoseMeasurement.mgPerDl);
},
keyboardType:
const TextInputType.numberWithOptions(),
validator: (value) {
@ -337,7 +344,8 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
),
)
: Container(),
Settings.glucoseDisplayMode == GlucoseDisplayMode.both ||
Settings.glucoseDisplayMode ==
GlucoseDisplayMode.both ||
Settings.glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? IconButton(
@ -348,7 +356,8 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
icon: const Icon(Icons.calculate),
)
: Container(),
Settings.glucoseMeasurement == GlucoseMeasurement.mmolPerL ||
Settings.glucoseMeasurement ==
GlucoseMeasurement.mmolPerL ||
Settings.glucoseDisplayMode ==
GlucoseDisplayMode.both ||
Settings.glucoseDisplayMode ==
@ -360,10 +369,13 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
suffixText: 'mmol/l',
),
controller: _mmolPerLController,
onChanged: (_) =>
onChanged: (_) async {
await Future.delayed(
const Duration(seconds: 1));
convertBetweenMgPerDlAndMmolPerL(
calculateFrom:
GlucoseMeasurement.mmolPerL),
GlucoseMeasurement.mmolPerL);
},
keyboardType:
const TextInputType.numberWithOptions(
decimal: true),
@ -379,7 +391,8 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
),
)
: Container(),
Settings.glucoseDisplayMode == GlucoseDisplayMode.both ||
Settings.glucoseDisplayMode ==
GlucoseDisplayMode.both ||
Settings.glucoseDisplayMode ==
GlucoseDisplayMode.bothForDetail
? IconButton(

View File

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

View File

@ -66,10 +66,7 @@ class _LogMealListScreenState extends State<LogMealListScreen> {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: widget.logMeals.isNotEmpty
return widget.logMeals.isNotEmpty
? ListView.builder(
shrinkWrap: true,
itemCount: widget.logMeals.length,
@ -81,12 +78,17 @@ class _LogMealListScreenState extends State<LogMealListScreen> {
children: [
Expanded(child: Text(meal.value)),
Expanded(
child: Text(meal.carbsPerPortion != null
? '${meal.carbsPerPortion} g carbs'
: '')),
Expanded(
child: Text(
meal.bolus != null ? '${meal.bolus} U' : ''))
child: Column(
children: ((meal.carbsPerPortion ?? 0) > 0)
? [
Text(meal.carbsPerPortion!.toStringAsPrecision(3)),
Text(
'${Settings.nutritionMeasurementSuffix} carbs',
textScaleFactor: 0.75),
]
: [],
),
),
],
),
trailing: IconButton(
@ -102,9 +104,6 @@ class _LogMealListScreenState extends State<LogMealListScreen> {
: 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 _portionSizeController = TextEditingController(text: '');
final _carbsPerPortionController = TextEditingController(text: '');
final _delayedBolusRateController = TextEditingController(text: '');
final _delayedBolusDurationController = TextEditingController(text: '');
final _notesController = TextEditingController(text: '');
double _delayedBolusPercentage = 0;
MealSource? _mealSource;
MealCategory? _mealCategory;
MealPortionType? _mealPortionType;
@ -67,8 +68,8 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
_portionSizeController.text = (_meal!.portionSize ?? '').toString();
_carbsPerPortionController.text =
(_meal!.carbsPerPortion ?? '').toString();
_delayedBolusRateController.text =
(_meal!.delayedBolusRate ?? '').toString();
_delayedBolusPercentage =
_meal!.delayedBolusPercentage ?? 0;
_delayedBolusDurationController.text =
(_meal!.delayedBolusDuration ?? '').toString();
_notesController.text = _meal!.notes ?? '';
@ -103,7 +104,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
carbsPerPortion: double.tryParse(_carbsPerPortionController.text),
delayedBolusDuration:
int.tryParse(_delayedBolusDurationController.text),
delayedBolusRate: double.tryParse(_delayedBolusRateController.text),
delayedBolusPercentage: _delayedBolusPercentage,
notes: _notesController.text,
);
meal.mealSource.target = _mealSource;
@ -134,7 +135,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
_portionSizeAccuracy != null ||
int.tryParse(_delayedBolusDurationController.text) !=
null ||
double.tryParse(_delayedBolusRateController.text) != null ||
_delayedBolusPercentage != 0 ||
_notesController.text != '')) ||
(!_isNew &&
(_valueController.text != _meal!.value ||
@ -151,8 +152,8 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
_portionSizeAccuracy != _meal!.portionSizeAccuracy.target ||
int.tryParse(_delayedBolusDurationController.text) !=
_meal!.delayedBolusDuration ||
double.tryParse(_delayedBolusRateController.text) !=
_meal!.delayedBolusRate ||
_delayedBolusPercentage !=
_meal!.delayedBolusPercentage ||
_notesController.text != (_meal!.notes ?? ''))))) {
Dialogs.showCancelConfirmationDialog(
context: context,
@ -291,8 +292,10 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
controller: _carbsRatioController,
keyboardType: const TextInputType.numberWithOptions(
decimal: true),
onChanged: (_) =>
calculateThirdMeasurementOfPortionCarbsRelation(),
onChanged: (_) async {
await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
),
),
IconButton(
@ -311,15 +314,16 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
child: TextFormField(
decoration: InputDecoration(
labelText: 'Portion size',
suffixText:
Settings.nutritionMeasurementSuffix,
suffixText: Settings.nutritionMeasurementSuffix,
alignLabelWithHint: true,
),
controller: _portionSizeController,
keyboardType: const TextInputType.numberWithOptions(
decimal: true),
onChanged: (_) =>
calculateThirdMeasurementOfPortionCarbsRelation(),
onChanged: (_) async {
await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
),
),
IconButton(
@ -347,14 +351,15 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
child: TextFormField(
decoration: InputDecoration(
labelText: 'Carbs per portion',
suffixText:
Settings.nutritionMeasurementSuffix,
suffixText: Settings.nutritionMeasurementSuffix,
),
controller: _carbsPerPortionController,
keyboardType: const TextInputType.numberWithOptions(
decimal: true),
onChanged: (_) =>
calculateThirdMeasurementOfPortionCarbsRelation(),
onChanged: (_) async {
await Future.delayed(const Duration(seconds: 1));
calculateThirdMeasurementOfPortionCarbsRelation();
},
),
),
IconButton(
@ -386,14 +391,27 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
controller: _delayedBolusDurationController,
keyboardType: const TextInputType.numberWithOptions(),
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Delayed Bolus Units',
suffixText: ' U',
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Row(
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(
controller: _notesController,

View File

@ -73,8 +73,9 @@ class _MealListScreenState extends State<MealListScreen> {
itemCount: _meals.length,
itemBuilder: (context, index) {
final meal = _meals[index];
String portionType = meal.mealPortionType.hasValue ? ' per ${meal.mealPortionType.target!.value}' : '';
return ListTile(
isThreeLine: true,
onTap: () {
Navigator.push(
context,
@ -85,7 +86,40 @@ class _MealListScreenState extends State<MealListScreen> {
).then((message) => reload(message: message));
},
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(
mainAxisSize: MainAxisSize.min,
children: [