usability tweaks, number form field component, amount for log meals, models for recipe and ingredients
This commit is contained in:
parent
575130aba0
commit
5e60ea09ce
35
TODO
35
TODO
@ -1,10 +1,5 @@
|
||||
BUGFIXES:
|
||||
|
||||
MAIN TASKS:
|
||||
Layout:
|
||||
✔ make components rounder/nicer/closer to new material style @done(21-12-10 04:10)
|
||||
General/Framework:
|
||||
✔ make sure 'null' isn't shown in text fields @done(21-12-10 04:23)
|
||||
☐ show indicator and make all fields readonly if user somehow gets to a deleted record detail view
|
||||
☐ clean up controllers (dispose method of each stateful widget)
|
||||
☐ account for deleted/disabled elements in dropdowns
|
||||
@ -12,17 +7,15 @@ MAIN TASKS:
|
||||
☐ set name properties as unique (and add checks to forms)
|
||||
☐ implement component for durations
|
||||
☐ change placement of delete and floating button because its very easy to accidentally hit delete
|
||||
✔ hide details like accuracies etc when picking meals @done(21-12-10 06:12)
|
||||
Basal/Bolus:
|
||||
✔ add save and close and next buttons on rate creations @done(21-12-10 06:12)
|
||||
✔ always calculate other glucose measurement from active one and make other one readonly @done(21-12-10 04:33)
|
||||
Recipe:
|
||||
✔ add model for recipe @done(21-12-11 02:23)
|
||||
✔ add model for ingredient (relation betweeen recipe and meal) @done(21-12-11 02:23)
|
||||
☐ recipe list screen
|
||||
☐ recipe detail screen
|
||||
☐ add functionality to create a meal from a recipe
|
||||
Log Entry:
|
||||
✔ add save and close button @done(21-12-10 06:11)
|
||||
✔ move on to newly created entry after saving @done(21-12-10 06:11)
|
||||
☐ recalculate bolus upon deactivating 'set manually' option
|
||||
☐ account for delayed percentage setting on choosing meals
|
||||
☐ give option to specify quantity
|
||||
☐ give option to pick meal from a different log entry (that doesn't have an associated bolus yet and within certain time span)
|
||||
✔ give option to specify quantity @done(21-12-11 01:28)
|
||||
✔ give option to pick meal from a different log entry (that doesn't have an associated bolus yet and within certain time span) @done(21-12-11 02:22)
|
||||
Event Types:
|
||||
☐ add colors as indicators for log entries (and later graphs in reports)
|
||||
Settings:
|
||||
@ -38,11 +31,10 @@ FUTURE TASKS:
|
||||
General/Framework:
|
||||
☐ setup objectbox sync server
|
||||
☐ add explanations to each section
|
||||
☐ find a better way to work with multiple glucose measurements (or disable it?)
|
||||
✔ find a better way to work with multiple glucose measurements @done(21-12-11 02:23)
|
||||
☐ evaluate if some fields should be readonly instead of completely hidden
|
||||
☐ alternate languages
|
||||
☐ log hba1c
|
||||
☐ add recipe calculator
|
||||
Reports:
|
||||
☐ evaluate what type of reports there should be
|
||||
Log Overview:
|
||||
@ -58,6 +50,15 @@ FUTURE TASKS:
|
||||
☐ option to switch theme
|
||||
|
||||
Archive:
|
||||
✔ make components rounder/nicer/closer to new material style @done(21-12-10 04:10) @project(MAIN TASKS.Layout)
|
||||
✔ make sure 'null' isn't shown in text fields @done(21-12-10 04:23) @project(MAIN TASKS.General/Framework)
|
||||
✔ hide details like accuracies etc when picking meals @done(21-12-10 06:12) @project(MAIN TASKS.General/Framework)
|
||||
✔ add save and close and next buttons on rate creations @done(21-12-10 06:12) @project(MAIN TASKS.Basal/Bolus)
|
||||
✔ always calculate other glucose measurement from active one and make other one readonly @done(21-12-10 04:33) @project(MAIN TASKS.Basal/Bolus)
|
||||
✔ add save and close button @done(21-12-10 06:11) @project(MAIN TASKS.Log Entry)
|
||||
✔ move on to newly created entry after saving @done(21-12-10 06:11) @project(MAIN TASKS.Log Entry)
|
||||
✔ recalculate bolus upon deactivating 'set manually' option @done(21-12-10 06:18) @project(MAIN TASKS.Log Entry)
|
||||
✔ account for delayed percentage setting on choosing meals @done(21-12-10 06:39) @project(MAIN TASKS.Log Entry)
|
||||
✔ fix preloading of dropdown values (appear blank at first as of now) @done(21-12-09 05:31) @project(BUGFIXES.General/Framework)
|
||||
✔ glucose target isn't displayed correctly anymore @done(21-12-09 05:31) @project(BUGFIXES.Log Entry)
|
||||
✔ hide dropdown overlay on tapping anywhere else (especially menu) @done(21-12-07 21:04) @project(MAIN TASKS.General/Framework)
|
||||
|
@ -164,3 +164,76 @@ class _TimeOfDayFormFieldState extends State<TimeOfDayFormField> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NumberFormField extends StatefulWidget {
|
||||
final TextEditingController controller;
|
||||
final String label;
|
||||
final String? suffix;
|
||||
final void Function(double?) onChanged;
|
||||
final double? min;
|
||||
final double? max;
|
||||
final double step;
|
||||
|
||||
const NumberFormField(
|
||||
{Key? key,
|
||||
required this.controller,
|
||||
required this.label,
|
||||
this.suffix,
|
||||
required this.onChanged,
|
||||
this.min,
|
||||
this.max,
|
||||
this.step = 1})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_NumberFormFieldState createState() => _NumberFormFieldState();
|
||||
}
|
||||
|
||||
class _NumberFormFieldState extends State<NumberFormField> {
|
||||
void onIncrease() {
|
||||
double value = double.tryParse(widget.controller.text) ?? 0;
|
||||
if (widget.max == null || value + widget.step <= widget.max!) {
|
||||
value += widget.step;
|
||||
widget.onChanged(value);
|
||||
}
|
||||
}
|
||||
|
||||
void onDecrease() {
|
||||
double value = double.tryParse(widget.controller.text) ?? 0;
|
||||
if (widget.min == null || value - widget.step >= widget.min!) {
|
||||
value -= widget.step;
|
||||
widget.onChanged(value);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: onDecrease,
|
||||
icon: const Icon(Icons.remove),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: widget.controller,
|
||||
decoration: InputDecoration(
|
||||
labelText: widget.label,
|
||||
suffixText: widget.suffix,
|
||||
),
|
||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||
onChanged: (value) async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
widget.onChanged(double.tryParse(value));
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: onIncrease,
|
||||
icon: const Icon(Icons.add),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
33
lib/models/ingredient.dart
Normal file
33
lib/models/ingredient.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:diameter/main.dart';
|
||||
import 'package:diameter/models/meal.dart';
|
||||
import 'package:diameter/models/recipe.dart';
|
||||
import 'package:objectbox/objectbox.dart';
|
||||
import 'package:diameter/objectbox.g.dart' show Ingredient_, Recipe_;
|
||||
|
||||
@Entity(uid: 6950311793136068892)
|
||||
@Sync()
|
||||
class Ingredient {
|
||||
static final Box<Ingredient> box = objectBox.store.box<Ingredient>();
|
||||
|
||||
// properties
|
||||
int id;
|
||||
bool deleted;
|
||||
double amount;
|
||||
|
||||
// relations
|
||||
final recipe = ToOne<Recipe>();
|
||||
final ingredient = ToOne<Meal>();
|
||||
|
||||
// constructor
|
||||
Ingredient({
|
||||
this.id = 0,
|
||||
this.deleted = false,
|
||||
required this.amount,
|
||||
});
|
||||
|
||||
static List<Ingredient> getAllForRecipe(int id) {
|
||||
QueryBuilder<Ingredient> builder = box.query(Ingredient_.deleted.equals(false));
|
||||
builder.link(Ingredient_.recipe, Recipe_.id.equals(id));
|
||||
return builder.build().find();
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import 'package:diameter/models/bolus.dart';
|
||||
import 'package:diameter/models/log_entry.dart';
|
||||
import 'package:diameter/models/log_meal.dart';
|
||||
import 'package:objectbox/objectbox.dart';
|
||||
import 'package:diameter/objectbox.g.dart' show LogBolus_, LogEntry_;
|
||||
import 'package:diameter/objectbox.g.dart' show LogBolus_, LogEntry_, LogMeal_;
|
||||
|
||||
@Entity(uid: 8033487006694871160)
|
||||
@Sync()
|
||||
@ -67,7 +67,14 @@ class LogBolus {
|
||||
QueryBuilder<LogBolus> builder = box.query(LogBolus_.deleted
|
||||
.equals(false)
|
||||
.and(LogBolus_.mgPerDlCorrection.notNull()));
|
||||
builder.link(LogBolus_.logEntry, LogEntry_.id.equals(id));
|
||||
builder.link(LogBolus_.meal, LogMeal_.id.equals(id));
|
||||
return builder.build().find().isNotEmpty;
|
||||
}
|
||||
|
||||
static bool bolusForMealExists(int id) {
|
||||
QueryBuilder<LogBolus> builder = box.query(LogBolus_.deleted
|
||||
.equals(false));
|
||||
builder.link(LogBolus_.meal, LogMeal_.id.equals(id));
|
||||
return builder.build().find().isNotEmpty;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:diameter/main.dart';
|
||||
import 'package:diameter/models/log_bolus.dart';
|
||||
import 'package:diameter/models/log_entry.dart';
|
||||
import 'package:diameter/models/meal.dart';
|
||||
import 'package:diameter/models/meal_category.dart';
|
||||
@ -19,9 +20,10 @@ class LogMeal {
|
||||
String value;
|
||||
double? carbsRatio;
|
||||
double? portionSize;
|
||||
double? carbsPerPortion;
|
||||
double? totalCarbs;
|
||||
String? notes;
|
||||
double? bolus;
|
||||
double amount;
|
||||
|
||||
// relations
|
||||
final logEntry = ToOne<LogEntry>();
|
||||
@ -37,9 +39,10 @@ class LogMeal {
|
||||
this.id = 0,
|
||||
this.deleted = false,
|
||||
this.value = '',
|
||||
this.amount = 1,
|
||||
this.carbsRatio,
|
||||
this.portionSize,
|
||||
this.carbsPerPortion,
|
||||
this.totalCarbs,
|
||||
this.notes,
|
||||
});
|
||||
|
||||
@ -60,10 +63,23 @@ class LogMeal {
|
||||
return builder.build().find();
|
||||
}
|
||||
|
||||
static List<LogMeal> getRecentWithoutBolus(int id) {
|
||||
final dateTime = LogEntry.get(id)?.time ?? DateTime.now();
|
||||
QueryBuilder<LogMeal> builder = box.query(LogMeal_.deleted.equals(false));
|
||||
builder.link(LogMeal_.logEntry);
|
||||
List<LogMeal> results = builder.build().find();
|
||||
results.retainWhere((logMeal) {
|
||||
final entryTime = logMeal.logEntry.target!.time;
|
||||
return entryTime.isAfter(dateTime.subtract(const Duration(hours: 12))) &&
|
||||
entryTime.isBefore(dateTime.add(const Duration(hours: 12))) && !LogBolus.bolusForMealExists(logMeal.id);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
static double getTotalCarbsForEntry(int id) {
|
||||
QueryBuilder<LogMeal> builder = box.query(LogMeal_.deleted.equals(false));
|
||||
builder.link(LogMeal_.logEntry, LogEntry_.id.equals(id));
|
||||
return builder.build().property(LogMeal_.carbsPerPortion).sum();
|
||||
return builder.build().property(LogMeal_.totalCarbs).sum();
|
||||
}
|
||||
|
||||
@override
|
||||
|
59
lib/models/recipe.dart
Normal file
59
lib/models/recipe.dart
Normal file
@ -0,0 +1,59 @@
|
||||
import 'package:diameter/main.dart';
|
||||
import 'package:diameter/models/meal.dart';
|
||||
import 'package:objectbox/objectbox.dart';
|
||||
import 'package:diameter/objectbox.g.dart' show Recipe_;
|
||||
|
||||
@Entity(uid: 6497942314956341514)
|
||||
@Sync()
|
||||
class Recipe {
|
||||
static final Box<Recipe> box = objectBox.store.box<Recipe>();
|
||||
|
||||
// properties
|
||||
int id;
|
||||
bool deleted;
|
||||
String name;
|
||||
double? carbsRatio;
|
||||
double? portionSize;
|
||||
double? carbsPerPortion;
|
||||
int? delayedBolusDuration;
|
||||
double? delayedBolusPercentage;
|
||||
String? notes;
|
||||
|
||||
// relations
|
||||
final portion = ToOne<Meal>();
|
||||
|
||||
// constructor
|
||||
Recipe({
|
||||
this.id = 0,
|
||||
this.deleted = false,
|
||||
this.name = '',
|
||||
this.carbsRatio,
|
||||
this.portionSize,
|
||||
this.carbsPerPortion,
|
||||
this.delayedBolusDuration,
|
||||
this.delayedBolusPercentage,
|
||||
this.notes,
|
||||
});
|
||||
|
||||
// methods
|
||||
static Recipe? get(int id) => box.get(id);
|
||||
static void put(Recipe recipe) => box.put(recipe);
|
||||
|
||||
static List<Recipe> getAll() {
|
||||
QueryBuilder<Recipe> builder = box.query(Recipe_.deleted.equals(false))..order(Recipe_.name);
|
||||
return builder.build().find();
|
||||
}
|
||||
|
||||
static void remove(int id) {
|
||||
final item = box.get(id);
|
||||
if (item != null) {
|
||||
item.deleted = true;
|
||||
box.put(item);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -346,7 +346,7 @@
|
||||
},
|
||||
{
|
||||
"id": "9:411177866700467286",
|
||||
"lastPropertyId": "17:7341439841011629937",
|
||||
"lastPropertyId": "19:8965198821438347033",
|
||||
"name": "LogMeal",
|
||||
"flags": 2,
|
||||
"properties": [
|
||||
@ -371,11 +371,6 @@
|
||||
"name": "portionSize",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"id": "5:2215708755581938580",
|
||||
"name": "carbsPerPortion",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"id": "6:8074052538574863399",
|
||||
"name": "bolus",
|
||||
@ -446,6 +441,16 @@
|
||||
"id": "17:7341439841011629937",
|
||||
"name": "deleted",
|
||||
"type": 1
|
||||
},
|
||||
{
|
||||
"id": "18:7405129785654054238",
|
||||
"name": "amount",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"id": "19:8965198821438347033",
|
||||
"name": "totalCarbs",
|
||||
"type": 8
|
||||
}
|
||||
],
|
||||
"relations": []
|
||||
@ -935,10 +940,114 @@
|
||||
}
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
{
|
||||
"id": "18:6497942314956341514",
|
||||
"lastPropertyId": "10:4370359747396560337",
|
||||
"name": "Recipe",
|
||||
"flags": 2,
|
||||
"properties": [
|
||||
{
|
||||
"id": "1:6426741154282018946",
|
||||
"name": "id",
|
||||
"type": 6,
|
||||
"flags": 1
|
||||
},
|
||||
{
|
||||
"id": "2:1167304402395485629",
|
||||
"name": "deleted",
|
||||
"type": 1
|
||||
},
|
||||
{
|
||||
"id": "3:1244733840071626966",
|
||||
"name": "name",
|
||||
"type": 9
|
||||
},
|
||||
{
|
||||
"id": "4:241621230513128588",
|
||||
"name": "carbsRatio",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"id": "5:4678123663117222609",
|
||||
"name": "portionSize",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"id": "6:780211923138281722",
|
||||
"name": "carbsPerPortion",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"id": "7:763575433624979013",
|
||||
"name": "delayedBolusDuration",
|
||||
"type": 6
|
||||
},
|
||||
{
|
||||
"id": "8:1225271130099322691",
|
||||
"name": "delayedBolusPercentage",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"id": "9:8593446427752839266",
|
||||
"name": "notes",
|
||||
"type": 9
|
||||
},
|
||||
{
|
||||
"id": "10:4370359747396560337",
|
||||
"name": "portionId",
|
||||
"type": 11,
|
||||
"flags": 520,
|
||||
"indexId": "29:5110151182694376118",
|
||||
"relationTarget": "Meal"
|
||||
}
|
||||
],
|
||||
"lastEntityId": "17:5041265995704044399",
|
||||
"lastIndexId": "28:4563029809754152081",
|
||||
"relations": []
|
||||
},
|
||||
{
|
||||
"id": "19:6950311793136068892",
|
||||
"lastPropertyId": "5:6495065881132428893",
|
||||
"name": "Ingredient",
|
||||
"flags": 2,
|
||||
"properties": [
|
||||
{
|
||||
"id": "1:7766569281758551418",
|
||||
"name": "id",
|
||||
"type": 6,
|
||||
"flags": 1
|
||||
},
|
||||
{
|
||||
"id": "2:3830559702655088692",
|
||||
"name": "deleted",
|
||||
"type": 1
|
||||
},
|
||||
{
|
||||
"id": "3:602057803225843875",
|
||||
"name": "amount",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"id": "4:26686399245586953",
|
||||
"name": "recipeId",
|
||||
"type": 11,
|
||||
"flags": 520,
|
||||
"indexId": "30:5492781242713788590",
|
||||
"relationTarget": "Recipe"
|
||||
},
|
||||
{
|
||||
"id": "5:6495065881132428893",
|
||||
"name": "ingredientId",
|
||||
"type": 11,
|
||||
"flags": 520,
|
||||
"indexId": "31:3277019237664417023",
|
||||
"relationTarget": "Meal"
|
||||
}
|
||||
],
|
||||
"relations": []
|
||||
}
|
||||
],
|
||||
"lastEntityId": "19:6950311793136068892",
|
||||
"lastIndexId": "31:3277019237664417023",
|
||||
"lastRelationId": "0:0",
|
||||
"lastSequenceId": "0:0",
|
||||
"modelVersion": 5,
|
||||
@ -975,7 +1084,8 @@
|
||||
7638848982383620744,
|
||||
3282706593658092097,
|
||||
596980591281311896,
|
||||
3633551763915044903
|
||||
3633551763915044903,
|
||||
2215708755581938580
|
||||
],
|
||||
"retiredRelationUids": [],
|
||||
"version": 1
|
||||
|
@ -15,6 +15,7 @@ import 'models/basal_profile.dart';
|
||||
import 'models/bolus.dart';
|
||||
import 'models/bolus_profile.dart';
|
||||
import 'models/glucose_target.dart';
|
||||
import 'models/ingredient.dart';
|
||||
import 'models/log_bolus.dart';
|
||||
import 'models/log_entry.dart';
|
||||
import 'models/log_event.dart';
|
||||
@ -24,6 +25,7 @@ import 'models/meal.dart';
|
||||
import 'models/meal_category.dart';
|
||||
import 'models/meal_portion_type.dart';
|
||||
import 'models/meal_source.dart';
|
||||
import 'models/recipe.dart';
|
||||
import 'models/settings.dart';
|
||||
|
||||
export 'package:objectbox/objectbox.dart'; // so that callers only have to import this file
|
||||
@ -359,7 +361,7 @@ final _entities = <ModelEntity>[
|
||||
ModelEntity(
|
||||
id: const IdUid(9, 411177866700467286),
|
||||
name: 'LogMeal',
|
||||
lastPropertyId: const IdUid(17, 7341439841011629937),
|
||||
lastPropertyId: const IdUid(19, 8965198821438347033),
|
||||
flags: 2,
|
||||
properties: <ModelProperty>[
|
||||
ModelProperty(
|
||||
@ -382,11 +384,6 @@ final _entities = <ModelEntity>[
|
||||
name: 'portionSize',
|
||||
type: 8,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(5, 2215708755581938580),
|
||||
name: 'carbsPerPortion',
|
||||
type: 8,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(6, 8074052538574863399),
|
||||
name: 'bolus',
|
||||
@ -450,6 +447,16 @@ final _entities = <ModelEntity>[
|
||||
id: const IdUid(17, 7341439841011629937),
|
||||
name: 'deleted',
|
||||
type: 1,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(18, 7405129785654054238),
|
||||
name: 'amount',
|
||||
type: 8,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(19, 8965198821438347033),
|
||||
name: 'totalCarbs',
|
||||
type: 8,
|
||||
flags: 0)
|
||||
],
|
||||
relations: <ModelRelation>[],
|
||||
@ -919,6 +926,105 @@ final _entities = <ModelEntity>[
|
||||
flags: 0)
|
||||
],
|
||||
relations: <ModelRelation>[],
|
||||
backlinks: <ModelBacklink>[]),
|
||||
ModelEntity(
|
||||
id: const IdUid(18, 6497942314956341514),
|
||||
name: 'Recipe',
|
||||
lastPropertyId: const IdUid(10, 4370359747396560337),
|
||||
flags: 2,
|
||||
properties: <ModelProperty>[
|
||||
ModelProperty(
|
||||
id: const IdUid(1, 6426741154282018946),
|
||||
name: 'id',
|
||||
type: 6,
|
||||
flags: 1),
|
||||
ModelProperty(
|
||||
id: const IdUid(2, 1167304402395485629),
|
||||
name: 'deleted',
|
||||
type: 1,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(3, 1244733840071626966),
|
||||
name: 'name',
|
||||
type: 9,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(4, 241621230513128588),
|
||||
name: 'carbsRatio',
|
||||
type: 8,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(5, 4678123663117222609),
|
||||
name: 'portionSize',
|
||||
type: 8,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(6, 780211923138281722),
|
||||
name: 'carbsPerPortion',
|
||||
type: 8,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(7, 763575433624979013),
|
||||
name: 'delayedBolusDuration',
|
||||
type: 6,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(8, 1225271130099322691),
|
||||
name: 'delayedBolusPercentage',
|
||||
type: 8,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(9, 8593446427752839266),
|
||||
name: 'notes',
|
||||
type: 9,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(10, 4370359747396560337),
|
||||
name: 'portionId',
|
||||
type: 11,
|
||||
flags: 520,
|
||||
indexId: const IdUid(29, 5110151182694376118),
|
||||
relationTarget: 'Meal')
|
||||
],
|
||||
relations: <ModelRelation>[],
|
||||
backlinks: <ModelBacklink>[]),
|
||||
ModelEntity(
|
||||
id: const IdUid(19, 6950311793136068892),
|
||||
name: 'Ingredient',
|
||||
lastPropertyId: const IdUid(5, 6495065881132428893),
|
||||
flags: 2,
|
||||
properties: <ModelProperty>[
|
||||
ModelProperty(
|
||||
id: const IdUid(1, 7766569281758551418),
|
||||
name: 'id',
|
||||
type: 6,
|
||||
flags: 1),
|
||||
ModelProperty(
|
||||
id: const IdUid(2, 3830559702655088692),
|
||||
name: 'deleted',
|
||||
type: 1,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(3, 602057803225843875),
|
||||
name: 'amount',
|
||||
type: 8,
|
||||
flags: 0),
|
||||
ModelProperty(
|
||||
id: const IdUid(4, 26686399245586953),
|
||||
name: 'recipeId',
|
||||
type: 11,
|
||||
flags: 520,
|
||||
indexId: const IdUid(30, 5492781242713788590),
|
||||
relationTarget: 'Recipe'),
|
||||
ModelProperty(
|
||||
id: const IdUid(5, 6495065881132428893),
|
||||
name: 'ingredientId',
|
||||
type: 11,
|
||||
flags: 520,
|
||||
indexId: const IdUid(31, 3277019237664417023),
|
||||
relationTarget: 'Meal')
|
||||
],
|
||||
relations: <ModelRelation>[],
|
||||
backlinks: <ModelBacklink>[])
|
||||
];
|
||||
|
||||
@ -942,8 +1048,8 @@ Future<Store> openStore(
|
||||
ModelDefinition getObjectBoxModel() {
|
||||
final model = ModelInfo(
|
||||
entities: _entities,
|
||||
lastEntityId: const IdUid(17, 5041265995704044399),
|
||||
lastIndexId: const IdUid(28, 4563029809754152081),
|
||||
lastEntityId: const IdUid(19, 6950311793136068892),
|
||||
lastIndexId: const IdUid(31, 3277019237664417023),
|
||||
lastRelationId: const IdUid(0, 0),
|
||||
lastSequenceId: const IdUid(0, 0),
|
||||
retiredEntityUids: const [3095978685310268382],
|
||||
@ -973,7 +1079,8 @@ ModelDefinition getObjectBoxModel() {
|
||||
7638848982383620744,
|
||||
3282706593658092097,
|
||||
596980591281311896,
|
||||
3633551763915044903
|
||||
3633551763915044903,
|
||||
2215708755581938580
|
||||
],
|
||||
retiredRelationUids: const [],
|
||||
modelVersion: 5,
|
||||
@ -1311,12 +1418,11 @@ ModelDefinition getObjectBoxModel() {
|
||||
final valueOffset = fbb.writeString(object.value);
|
||||
final notesOffset =
|
||||
object.notes == null ? null : fbb.writeString(object.notes!);
|
||||
fbb.startTable(18);
|
||||
fbb.startTable(20);
|
||||
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.addFloat64(5, object.bolus);
|
||||
fbb.addOffset(8, notesOffset);
|
||||
fbb.addInt64(9, object.logEntry.targetId);
|
||||
@ -1327,6 +1433,8 @@ ModelDefinition getObjectBoxModel() {
|
||||
fbb.addInt64(14, object.portionSizeAccuracy.targetId);
|
||||
fbb.addInt64(15, object.carbsRatioAccuracy.targetId);
|
||||
fbb.addBool(16, object.deleted);
|
||||
fbb.addFloat64(17, object.amount);
|
||||
fbb.addFloat64(18, object.totalCarbs);
|
||||
fbb.finish(fbb.endTable());
|
||||
return object.id;
|
||||
},
|
||||
@ -1340,12 +1448,14 @@ ModelDefinition getObjectBoxModel() {
|
||||
.vTableGet(buffer, rootOffset, 36, false),
|
||||
value:
|
||||
const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''),
|
||||
amount:
|
||||
const fb.Float64Reader().vTableGet(buffer, rootOffset, 38, 0),
|
||||
carbsRatio: const fb.Float64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 8),
|
||||
portionSize: const fb.Float64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 10),
|
||||
carbsPerPortion: const fb.Float64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 12),
|
||||
totalCarbs: const fb.Float64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 40),
|
||||
notes: const fb.StringReader()
|
||||
.vTableGetNullable(buffer, rootOffset, 20))
|
||||
..bolus = const fb.Float64Reader()
|
||||
@ -1799,6 +1909,96 @@ ModelDefinition getObjectBoxModel() {
|
||||
const fb.Int64Reader().vTableGet(buffer, rootOffset, 16, 0));
|
||||
|
||||
return object;
|
||||
}),
|
||||
Recipe: EntityDefinition<Recipe>(
|
||||
model: _entities[16],
|
||||
toOneRelations: (Recipe object) => [object.portion],
|
||||
toManyRelations: (Recipe object) => {},
|
||||
getId: (Recipe object) => object.id,
|
||||
setId: (Recipe object, int id) {
|
||||
object.id = id;
|
||||
},
|
||||
objectToFB: (Recipe object, fb.Builder fbb) {
|
||||
final nameOffset = fbb.writeString(object.name);
|
||||
final notesOffset =
|
||||
object.notes == null ? null : fbb.writeString(object.notes!);
|
||||
fbb.startTable(11);
|
||||
fbb.addInt64(0, object.id);
|
||||
fbb.addBool(1, object.deleted);
|
||||
fbb.addOffset(2, nameOffset);
|
||||
fbb.addFloat64(3, object.carbsRatio);
|
||||
fbb.addFloat64(4, object.portionSize);
|
||||
fbb.addFloat64(5, object.carbsPerPortion);
|
||||
fbb.addInt64(6, object.delayedBolusDuration);
|
||||
fbb.addFloat64(7, object.delayedBolusPercentage);
|
||||
fbb.addOffset(8, notesOffset);
|
||||
fbb.addInt64(9, object.portion.targetId);
|
||||
fbb.finish(fbb.endTable());
|
||||
return object.id;
|
||||
},
|
||||
objectFromFB: (Store store, ByteData fbData) {
|
||||
final buffer = fb.BufferContext(fbData);
|
||||
final rootOffset = buffer.derefObject(0);
|
||||
|
||||
final object = Recipe(
|
||||
id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0),
|
||||
deleted:
|
||||
const fb.BoolReader().vTableGet(buffer, rootOffset, 6, false),
|
||||
name:
|
||||
const fb.StringReader().vTableGet(buffer, rootOffset, 8, ''),
|
||||
carbsRatio: const fb.Float64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 10),
|
||||
portionSize: const fb.Float64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 12),
|
||||
carbsPerPortion: const fb.Float64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 14),
|
||||
delayedBolusDuration: const fb.Int64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 16),
|
||||
delayedBolusPercentage: const fb.Float64Reader()
|
||||
.vTableGetNullable(buffer, rootOffset, 18),
|
||||
notes: const fb.StringReader()
|
||||
.vTableGetNullable(buffer, rootOffset, 20));
|
||||
object.portion.targetId =
|
||||
const fb.Int64Reader().vTableGet(buffer, rootOffset, 22, 0);
|
||||
object.portion.attach(store);
|
||||
return object;
|
||||
}),
|
||||
Ingredient: EntityDefinition<Ingredient>(
|
||||
model: _entities[17],
|
||||
toOneRelations: (Ingredient object) =>
|
||||
[object.recipe, object.ingredient],
|
||||
toManyRelations: (Ingredient object) => {},
|
||||
getId: (Ingredient object) => object.id,
|
||||
setId: (Ingredient object, int id) {
|
||||
object.id = id;
|
||||
},
|
||||
objectToFB: (Ingredient object, fb.Builder fbb) {
|
||||
fbb.startTable(6);
|
||||
fbb.addInt64(0, object.id);
|
||||
fbb.addBool(1, object.deleted);
|
||||
fbb.addFloat64(2, object.amount);
|
||||
fbb.addInt64(3, object.recipe.targetId);
|
||||
fbb.addInt64(4, object.ingredient.targetId);
|
||||
fbb.finish(fbb.endTable());
|
||||
return object.id;
|
||||
},
|
||||
objectFromFB: (Store store, ByteData fbData) {
|
||||
final buffer = fb.BufferContext(fbData);
|
||||
final rootOffset = buffer.derefObject(0);
|
||||
|
||||
final object = Ingredient(
|
||||
id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0),
|
||||
deleted:
|
||||
const fb.BoolReader().vTableGet(buffer, rootOffset, 6, false),
|
||||
amount:
|
||||
const fb.Float64Reader().vTableGet(buffer, rootOffset, 8, 0));
|
||||
object.recipe.targetId =
|
||||
const fb.Int64Reader().vTableGet(buffer, rootOffset, 10, 0);
|
||||
object.recipe.attach(store);
|
||||
object.ingredient.targetId =
|
||||
const fb.Int64Reader().vTableGet(buffer, rootOffset, 12, 0);
|
||||
object.ingredient.attach(store);
|
||||
return object;
|
||||
})
|
||||
};
|
||||
|
||||
@ -2035,47 +2235,51 @@ class LogMeal_ {
|
||||
static final portionSize =
|
||||
QueryDoubleProperty<LogMeal>(_entities[7].properties[3]);
|
||||
|
||||
/// see [LogMeal.carbsPerPortion]
|
||||
static final carbsPerPortion =
|
||||
QueryDoubleProperty<LogMeal>(_entities[7].properties[4]);
|
||||
|
||||
/// see [LogMeal.bolus]
|
||||
static final bolus = QueryDoubleProperty<LogMeal>(_entities[7].properties[5]);
|
||||
static final bolus = QueryDoubleProperty<LogMeal>(_entities[7].properties[4]);
|
||||
|
||||
/// see [LogMeal.notes]
|
||||
static final notes = QueryStringProperty<LogMeal>(_entities[7].properties[6]);
|
||||
static final notes = QueryStringProperty<LogMeal>(_entities[7].properties[5]);
|
||||
|
||||
/// see [LogMeal.logEntry]
|
||||
static final logEntry =
|
||||
QueryRelationToOne<LogMeal, LogEntry>(_entities[7].properties[7]);
|
||||
QueryRelationToOne<LogMeal, LogEntry>(_entities[7].properties[6]);
|
||||
|
||||
/// see [LogMeal.meal]
|
||||
static final meal =
|
||||
QueryRelationToOne<LogMeal, Meal>(_entities[7].properties[8]);
|
||||
QueryRelationToOne<LogMeal, Meal>(_entities[7].properties[7]);
|
||||
|
||||
/// see [LogMeal.mealSource]
|
||||
static final mealSource =
|
||||
QueryRelationToOne<LogMeal, MealSource>(_entities[7].properties[9]);
|
||||
QueryRelationToOne<LogMeal, MealSource>(_entities[7].properties[8]);
|
||||
|
||||
/// see [LogMeal.mealCategory]
|
||||
static final mealCategory =
|
||||
QueryRelationToOne<LogMeal, MealCategory>(_entities[7].properties[10]);
|
||||
QueryRelationToOne<LogMeal, MealCategory>(_entities[7].properties[9]);
|
||||
|
||||
/// see [LogMeal.mealPortionType]
|
||||
static final mealPortionType =
|
||||
QueryRelationToOne<LogMeal, MealPortionType>(_entities[7].properties[11]);
|
||||
QueryRelationToOne<LogMeal, MealPortionType>(_entities[7].properties[10]);
|
||||
|
||||
/// see [LogMeal.portionSizeAccuracy]
|
||||
static final portionSizeAccuracy =
|
||||
QueryRelationToOne<LogMeal, Accuracy>(_entities[7].properties[12]);
|
||||
QueryRelationToOne<LogMeal, Accuracy>(_entities[7].properties[11]);
|
||||
|
||||
/// see [LogMeal.carbsRatioAccuracy]
|
||||
static final carbsRatioAccuracy =
|
||||
QueryRelationToOne<LogMeal, Accuracy>(_entities[7].properties[13]);
|
||||
QueryRelationToOne<LogMeal, Accuracy>(_entities[7].properties[12]);
|
||||
|
||||
/// see [LogMeal.deleted]
|
||||
static final deleted =
|
||||
QueryBooleanProperty<LogMeal>(_entities[7].properties[14]);
|
||||
QueryBooleanProperty<LogMeal>(_entities[7].properties[13]);
|
||||
|
||||
/// see [LogMeal.amount]
|
||||
static final amount =
|
||||
QueryDoubleProperty<LogMeal>(_entities[7].properties[14]);
|
||||
|
||||
/// see [LogMeal.totalCarbs]
|
||||
static final totalCarbs =
|
||||
QueryDoubleProperty<LogMeal>(_entities[7].properties[15]);
|
||||
}
|
||||
|
||||
/// [Meal] entity fields to define ObjectBox queries.
|
||||
@ -2392,3 +2596,66 @@ class GlucoseTarget_ {
|
||||
static final color =
|
||||
QueryIntegerProperty<GlucoseTarget>(_entities[15].properties[6]);
|
||||
}
|
||||
|
||||
/// [Recipe] entity fields to define ObjectBox queries.
|
||||
class Recipe_ {
|
||||
/// see [Recipe.id]
|
||||
static final id = QueryIntegerProperty<Recipe>(_entities[16].properties[0]);
|
||||
|
||||
/// see [Recipe.deleted]
|
||||
static final deleted =
|
||||
QueryBooleanProperty<Recipe>(_entities[16].properties[1]);
|
||||
|
||||
/// see [Recipe.name]
|
||||
static final name = QueryStringProperty<Recipe>(_entities[16].properties[2]);
|
||||
|
||||
/// see [Recipe.carbsRatio]
|
||||
static final carbsRatio =
|
||||
QueryDoubleProperty<Recipe>(_entities[16].properties[3]);
|
||||
|
||||
/// see [Recipe.portionSize]
|
||||
static final portionSize =
|
||||
QueryDoubleProperty<Recipe>(_entities[16].properties[4]);
|
||||
|
||||
/// see [Recipe.carbsPerPortion]
|
||||
static final carbsPerPortion =
|
||||
QueryDoubleProperty<Recipe>(_entities[16].properties[5]);
|
||||
|
||||
/// see [Recipe.delayedBolusDuration]
|
||||
static final delayedBolusDuration =
|
||||
QueryIntegerProperty<Recipe>(_entities[16].properties[6]);
|
||||
|
||||
/// see [Recipe.delayedBolusPercentage]
|
||||
static final delayedBolusPercentage =
|
||||
QueryDoubleProperty<Recipe>(_entities[16].properties[7]);
|
||||
|
||||
/// see [Recipe.notes]
|
||||
static final notes = QueryStringProperty<Recipe>(_entities[16].properties[8]);
|
||||
|
||||
/// see [Recipe.portion]
|
||||
static final portion =
|
||||
QueryRelationToOne<Recipe, Meal>(_entities[16].properties[9]);
|
||||
}
|
||||
|
||||
/// [Ingredient] entity fields to define ObjectBox queries.
|
||||
class Ingredient_ {
|
||||
/// see [Ingredient.id]
|
||||
static final id =
|
||||
QueryIntegerProperty<Ingredient>(_entities[17].properties[0]);
|
||||
|
||||
/// see [Ingredient.deleted]
|
||||
static final deleted =
|
||||
QueryBooleanProperty<Ingredient>(_entities[17].properties[1]);
|
||||
|
||||
/// see [Ingredient.amount]
|
||||
static final amount =
|
||||
QueryDoubleProperty<Ingredient>(_entities[17].properties[2]);
|
||||
|
||||
/// see [Ingredient.recipe]
|
||||
static final recipe =
|
||||
QueryRelationToOne<Ingredient, Recipe>(_entities[17].properties[3]);
|
||||
|
||||
/// see [Ingredient.ingredient]
|
||||
static final ingredient =
|
||||
QueryRelationToOne<Ingredient, Meal>(_entities[17].properties[4]);
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
|
||||
reload();
|
||||
|
||||
_logEntry = LogEntry.get(widget.logEntryId);
|
||||
_logMeals = LogMeal.getAllForEntry(widget.logEntryId);
|
||||
_logMeals = LogMeal.getRecentWithoutBolus(widget.logEntryId);
|
||||
|
||||
if (widget.id != 0) {
|
||||
_carbsController.text = (_logBolus!.carbs ?? '').toString();
|
||||
@ -163,8 +163,8 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
|
||||
_mealController.text = (_meal ?? '').toString();
|
||||
});
|
||||
if (_meal != null) {
|
||||
if (_meal!.carbsPerPortion != null) {
|
||||
_carbsController.text = (_meal!.carbsPerPortion).toString();
|
||||
if (_meal!.totalCarbs != null) {
|
||||
_carbsController.text = (_meal!.totalCarbs).toString();
|
||||
}
|
||||
if (_meal!.meal.hasValue) {
|
||||
if (_meal!.meal.target!.delayedBolusDuration != null) {
|
||||
@ -198,9 +198,9 @@ class _LogBolusDetailScreenState extends State<LogBolusDetailScreen> {
|
||||
|
||||
void onSelectMeal(LogMeal? meal) {
|
||||
updateLogMeal(meal);
|
||||
if (meal != null && meal.carbsPerPortion != null) {
|
||||
if (meal != null && meal.totalCarbs != null) {
|
||||
setState(() {
|
||||
_carbsController.text = meal.carbsPerPortion.toString();
|
||||
_carbsController.text = meal.totalCarbs.toString();
|
||||
calculateBolus();
|
||||
});
|
||||
}
|
||||
|
@ -214,8 +214,7 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
onDiscard: (context) => Navigator.pushReplacementNamed(context, '/log'),
|
||||
);
|
||||
} else {
|
||||
Navigator.pushReplacementNamed(context, '/log',
|
||||
arguments: '${_isNew ? 'New' : ''} Log Entry Saved');
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,13 +37,16 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
bool _isSaving = false;
|
||||
bool _isExpanded = false;
|
||||
|
||||
double _amount = 1;
|
||||
|
||||
final GlobalKey<FormState> _logMealForm = GlobalKey<FormState>();
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
final _valueController = TextEditingController(text: '');
|
||||
final _amountController = TextEditingController(text: '');
|
||||
final _carbsRatioController = TextEditingController(text: '');
|
||||
final _portionSizeController = TextEditingController(text: '');
|
||||
final _carbsPerPortionController = TextEditingController(text: '');
|
||||
final _totalCarbsController = TextEditingController(text: '');
|
||||
final _notesController = TextEditingController(text: '');
|
||||
|
||||
Meal? _meal;
|
||||
@ -81,10 +84,10 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
|
||||
if (widget.id != 0) {
|
||||
_valueController.text = _logMeal!.value;
|
||||
_amountController.text = _logMeal!.amount.toString();
|
||||
_carbsRatioController.text = (_logMeal!.carbsRatio ?? '').toString();
|
||||
_portionSizeController.text = (_logMeal!.portionSize ?? '').toString();
|
||||
_carbsPerPortionController.text =
|
||||
(_logMeal!.carbsPerPortion ?? '').toString();
|
||||
_totalCarbsController.text = (_logMeal!.totalCarbs ?? '').toString();
|
||||
_notesController.text = _logMeal!.notes ?? '';
|
||||
|
||||
_meal = _logMeal!.meal.target;
|
||||
@ -102,6 +105,10 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
_carbsRatioAccuracyController.text =
|
||||
(_carbsRatioAccuracy ?? '').toString();
|
||||
}
|
||||
|
||||
if (_amountController.text == '') {
|
||||
_amountController.text = '1';
|
||||
}
|
||||
}
|
||||
|
||||
void reload({String? message}) {
|
||||
@ -165,35 +172,18 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
Future<void> onSelectMeal(Meal? meal) async {
|
||||
setState(() {
|
||||
_meal = meal;
|
||||
_valueController.text = _mealController.text = (_meal ?? '').toString();
|
||||
_mealController.text = (_meal ?? '').toString();
|
||||
_valueController.text = _mealController.text;
|
||||
_carbsRatioController.text = (meal?.carbsRatio ?? '').toString();
|
||||
_amountController.text = '1';
|
||||
_portionSizeController.text = (meal?.portionSize ?? '').toString();
|
||||
_totalCarbsController.text = (meal?.carbsPerPortion ?? '').toString();
|
||||
});
|
||||
|
||||
if (meal != null) {
|
||||
if (meal.carbsRatio != null) {
|
||||
_carbsRatioController.text = meal.carbsRatio.toString();
|
||||
}
|
||||
if (meal.portionSize != null) {
|
||||
_portionSizeController.text = meal.portionSize.toString();
|
||||
}
|
||||
if (meal.carbsPerPortion != null) {
|
||||
_carbsPerPortionController.text = meal.carbsPerPortion.toString();
|
||||
}
|
||||
if (meal.mealSource.hasValue) {
|
||||
updateMealSource(meal.mealSource.target);
|
||||
}
|
||||
if (meal.mealCategory.hasValue) {
|
||||
updateMealCategory(meal.mealCategory.target);
|
||||
}
|
||||
if (meal.mealPortionType.hasValue) {
|
||||
updateMealPortionType(meal.mealPortionType.target);
|
||||
}
|
||||
if (meal.portionSizeAccuracy.hasValue) {
|
||||
updatePortionSizeAccuracy(meal.portionSizeAccuracy.target);
|
||||
}
|
||||
if (meal.carbsRatioAccuracy.hasValue) {
|
||||
updateCarbsRatioAccuracy(meal.carbsRatioAccuracy.target);
|
||||
}
|
||||
}
|
||||
updateMealSource(meal?.mealSource.target);
|
||||
updateMealCategory(meal?.mealCategory.target);
|
||||
updateMealPortionType(meal?.mealPortionType.target);
|
||||
updatePortionSizeAccuracy(meal?.portionSizeAccuracy.target);
|
||||
updateCarbsRatioAccuracy(meal?.carbsRatioAccuracy.target);
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
@ -206,7 +196,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
value: _valueController.text,
|
||||
carbsRatio: double.tryParse(_carbsRatioController.text),
|
||||
portionSize: double.tryParse(_portionSizeController.text),
|
||||
carbsPerPortion: double.tryParse(_carbsPerPortionController.text),
|
||||
totalCarbs: double.tryParse(_totalCarbsController.text),
|
||||
);
|
||||
logMeal.logEntry.targetId = widget.logEntryId;
|
||||
logMeal.meal.target = _meal;
|
||||
@ -234,7 +224,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
_mealPortionType != null ||
|
||||
double.tryParse(_carbsRatioController.text) != null ||
|
||||
double.tryParse(_portionSizeController.text) != null ||
|
||||
double.tryParse(_carbsPerPortionController.text) != null ||
|
||||
double.tryParse(_totalCarbsController.text) != null ||
|
||||
_carbsRatioAccuracy != null ||
|
||||
_portionSizeAccuracy != null ||
|
||||
_notesController.text != '')) ||
|
||||
@ -248,8 +238,8 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
_logMeal!.carbsRatio ||
|
||||
double.tryParse(_portionSizeController.text) !=
|
||||
_logMeal!.portionSize ||
|
||||
double.tryParse(_carbsPerPortionController.text) !=
|
||||
_logMeal!.carbsPerPortion ||
|
||||
double.tryParse(_totalCarbsController.text) !=
|
||||
_logMeal!.totalCarbs ||
|
||||
_carbsRatioAccuracy !=
|
||||
_logMeal!.carbsRatioAccuracy.target ||
|
||||
_portionSizeAccuracy !=
|
||||
@ -265,36 +255,69 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void calculateThirdMeasurementOfPortionCarbsRelation(
|
||||
{PortionCarbsParameter? parameterToBeCalculated}) {
|
||||
void updateAmount(double? amount) {
|
||||
double? previousAmount;
|
||||
double? portionSize;
|
||||
double? carbsRatio;
|
||||
|
||||
previousAmount = _amount;
|
||||
|
||||
setState(() {
|
||||
_amountController.text = (amount ?? '').toString();
|
||||
_amount = amount ?? 1;
|
||||
});
|
||||
|
||||
if (_carbsRatioController.text != '') {
|
||||
carbsRatio = double.tryParse(_carbsRatioController.text);
|
||||
}
|
||||
if (_portionSizeController.text != '') {
|
||||
portionSize = double.tryParse(_portionSizeController.text);
|
||||
}
|
||||
|
||||
if (amount != null && portionSize != null) {
|
||||
setState(() {
|
||||
portionSize = portionSize! / (previousAmount ?? 1) * amount;
|
||||
_portionSizeController.text = portionSize.toString();
|
||||
});
|
||||
if (carbsRatio != null) {
|
||||
setState(() {
|
||||
_totalCarbsController.text =
|
||||
Utils.calculateCarbs(carbsRatio!, portionSize!).toString();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void calculateThirdMeasurementOfPortionCarbsRelation() {
|
||||
int? amount;
|
||||
double? carbsRatio;
|
||||
double? portionSize;
|
||||
double? carbsPerPortion;
|
||||
|
||||
if (parameterToBeCalculated != PortionCarbsParameter.carbsRatio &&
|
||||
_carbsRatioController.text != '') {
|
||||
if (_amountController.text != '') {
|
||||
amount = int.tryParse(_amountController.text);
|
||||
}
|
||||
if (_carbsRatioController.text != '') {
|
||||
carbsRatio = double.tryParse(_carbsRatioController.text);
|
||||
}
|
||||
if (parameterToBeCalculated != PortionCarbsParameter.portionSize &&
|
||||
_portionSizeController.text != '') {
|
||||
if (_portionSizeController.text != '') {
|
||||
portionSize = double.tryParse(_portionSizeController.text);
|
||||
}
|
||||
if (parameterToBeCalculated != PortionCarbsParameter.carbsPerPortion &&
|
||||
_carbsRatioController.text != '') {
|
||||
carbsPerPortion = double.tryParse(_carbsPerPortionController.text);
|
||||
if (_totalCarbsController.text != '') {
|
||||
carbsPerPortion = double.tryParse(_totalCarbsController.text);
|
||||
}
|
||||
|
||||
if (carbsRatio != null && portionSize != null && carbsPerPortion == null) {
|
||||
setState(() {
|
||||
_carbsPerPortionController.text =
|
||||
Utils.calculateCarbsPerPortion(carbsRatio!, portionSize!)
|
||||
_totalCarbsController.text =
|
||||
Utils.calculateCarbs(carbsRatio!, portionSize! * (amount ?? 1))
|
||||
.toString();
|
||||
});
|
||||
}
|
||||
if (carbsRatio == null && portionSize != null && carbsPerPortion != null) {
|
||||
setState(() {
|
||||
_carbsRatioController.text =
|
||||
Utils.calculateCarbsRatio(carbsPerPortion!, portionSize!)
|
||||
_carbsRatioController.text = Utils.calculateCarbsRatio(
|
||||
carbsPerPortion!, portionSize! * (amount ?? 1))
|
||||
.toString();
|
||||
});
|
||||
}
|
||||
@ -311,7 +334,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_isNew ? 'New Meal' : _logMeal!.value),
|
||||
title: Text(_isNew ? 'New Meal for Log Entry' : _logMeal!.value),
|
||||
),
|
||||
drawer: const Navigation(currentLocation: LogMealDetailScreen.routeName),
|
||||
body: Scrollbar(
|
||||
@ -344,11 +367,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
selectedItem: _meal,
|
||||
label: 'Meal',
|
||||
items: _meals,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
onSelectMeal(value);
|
||||
}
|
||||
},
|
||||
onChanged: onSelectMeal,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
@ -369,34 +388,14 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Carbs ratio',
|
||||
suffixText: '%',
|
||||
),
|
||||
controller: _carbsRatioController,
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true),
|
||||
onChanged: (_) async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
calculateThirdMeasurementOfPortionCarbsRelation();
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () =>
|
||||
calculateThirdMeasurementOfPortionCarbsRelation(
|
||||
parameterToBeCalculated:
|
||||
PortionCarbsParameter.carbsRatio),
|
||||
icon: const Icon(Icons.calculate),
|
||||
),
|
||||
],
|
||||
NumberFormField(
|
||||
controller: _amountController,
|
||||
label: 'Amount',
|
||||
suffix: _mealPortionType?.value,
|
||||
min: 1,
|
||||
onChanged: updateAmount,
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
@ -413,24 +412,14 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () =>
|
||||
calculateThirdMeasurementOfPortionCarbsRelation(
|
||||
parameterToBeCalculated:
|
||||
PortionCarbsParameter.portionSize),
|
||||
icon: const Icon(Icons.calculate),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Carbs per portion',
|
||||
suffixText: Settings.nutritionMeasurementSuffix,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Carbs ratio',
|
||||
suffixText: '%',
|
||||
),
|
||||
controller: _carbsPerPortionController,
|
||||
controller: _carbsRatioController,
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true),
|
||||
onChanged: (_) async {
|
||||
@ -439,12 +428,21 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () =>
|
||||
calculateThirdMeasurementOfPortionCarbsRelation(
|
||||
parameterToBeCalculated:
|
||||
PortionCarbsParameter.carbsPerPortion),
|
||||
icon: const Icon(Icons.calculate),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Total carbs',
|
||||
suffixText: Settings.nutritionMeasurementSuffix,
|
||||
),
|
||||
controller: _totalCarbsController,
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true),
|
||||
onChanged: (_) async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
calculateThirdMeasurementOfPortionCarbsRelation();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -480,11 +478,13 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
children: _isExpanded
|
||||
? [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: AutoCompleteDropdownButton<MealSource>(
|
||||
child:
|
||||
AutoCompleteDropdownButton<MealSource>(
|
||||
controller: _mealSourceController,
|
||||
selectedItem: _mealSource,
|
||||
label: 'Meal Source',
|
||||
@ -497,8 +497,8 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
_mealSource == null
|
||||
builder: (context) => _mealSource ==
|
||||
null
|
||||
? const MealSourceDetailScreen()
|
||||
: MealSourceDetailScreen(
|
||||
id: _mealSource!.id),
|
||||
@ -516,12 +516,13 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child:
|
||||
AutoCompleteDropdownButton<MealCategory>(
|
||||
child: AutoCompleteDropdownButton<
|
||||
MealCategory>(
|
||||
controller: _mealCategoryController,
|
||||
selectedItem: _mealCategory,
|
||||
label: 'Meal Category',
|
||||
@ -553,7 +554,8 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@ -590,12 +592,14 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: AutoCompleteDropdownButton<Accuracy>(
|
||||
controller: _portionSizeAccuracyController,
|
||||
controller:
|
||||
_portionSizeAccuracyController,
|
||||
selectedItem: _portionSizeAccuracy,
|
||||
label: 'Portion Size Accuracy',
|
||||
items: _portionSizeAccuracies,
|
||||
@ -607,10 +611,12 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => _portionSizeAccuracy == null
|
||||
builder: (context) =>
|
||||
_portionSizeAccuracy == null
|
||||
? const AccuracyDetailScreen()
|
||||
: AccuracyDetailScreen(
|
||||
id: _portionSizeAccuracy!.id),
|
||||
id: _portionSizeAccuracy!
|
||||
.id),
|
||||
),
|
||||
).then((result) {
|
||||
updatePortionSizeAccuracy(result?[1]);
|
||||
@ -625,7 +631,8 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@ -642,10 +649,12 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => _carbsRatioAccuracy == null
|
||||
builder: (context) =>
|
||||
_carbsRatioAccuracy == null
|
||||
? const AccuracyDetailScreen()
|
||||
: AccuracyDetailScreen(
|
||||
id: _carbsRatioAccuracy!.id),
|
||||
id: _carbsRatioAccuracy!
|
||||
.id),
|
||||
),
|
||||
).then((result) {
|
||||
updateCarbsRatioAccuracy(result?[1]);
|
||||
|
@ -89,9 +89,9 @@ class _LogMealListScreenState extends State<LogMealListScreen> {
|
||||
)),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: ((meal.carbsPerPortion ?? 0) > 0)
|
||||
children: ((meal.totalCarbs ?? 0) > 0)
|
||||
? [
|
||||
Text(meal.carbsPerPortion!.toStringAsPrecision(3)),
|
||||
Text(meal.totalCarbs!.toStringAsPrecision(3)),
|
||||
Text(
|
||||
'${Settings.nutritionMeasurementSuffix} carbs',
|
||||
textScaleFactor: 0.75),
|
||||
|
@ -246,8 +246,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void calculateThirdMeasurementOfPortionCarbsRelation(
|
||||
{PortionCarbsParameter? changedParameter}) {
|
||||
void calculateThirdMeasurementOfPortionCarbsRelation() {
|
||||
double? carbsRatio;
|
||||
double? portionSize;
|
||||
double? carbsPerPortion;
|
||||
@ -265,7 +264,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
if (carbsRatio != null && portionSize != null && carbsPerPortion == null) {
|
||||
setState(() {
|
||||
_carbsPerPortionController.text =
|
||||
Utils.calculateCarbsPerPortion(carbsRatio!, portionSize!)
|
||||
Utils.calculateCarbs(carbsRatio!, portionSize!)
|
||||
.toString();
|
||||
});
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class Utils {
|
||||
return (mmolPerL * 18.018).round();
|
||||
}
|
||||
|
||||
static double calculateCarbsPerPortion(
|
||||
static double calculateCarbs(
|
||||
double carbsRatio, double portionSize) {
|
||||
return Utils.roundToDecimalPlaces(carbsRatio * portionSize / 100, 2);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user