From f7d727e070d3940ade93e1dea4273c4e4e2844c0 Mon Sep 17 00:00:00 2001 From: spinel Date: Sun, 7 Nov 2021 21:13:28 +0100 Subject: [PATCH] switch from back4app to local store using objectbox --- README.md | 6 +- TODO | 3 +- android/app/build.gradle | 1 + android/build.gradle | 1 + lib/components/progress_indicator.dart | 6 +- lib/main.dart | 15 +- lib/models/accuracy.dart | 157 +- lib/models/basal.dart | 142 +- lib/models/basal_profile.dart | 124 +- lib/models/bolus.dart | 231 +-- lib/models/bolus_profile.dart | 124 +- lib/models/log_entry.dart | 216 +-- lib/models/log_event.dart | 207 +- lib/models/log_event_type.dart | 100 +- lib/models/log_meal.dart | 262 +-- lib/models/meal.dart | 220 +-- lib/models/meal_category.dart | 78 +- lib/models/meal_portion_type.dart | 79 +- lib/models/meal_source.dart | 173 +- lib/object_box.dart | 14 + lib/objectbox-model.json | 648 +++++++ lib/objectbox.g.dart | 1694 +++++++++++++++++ lib/screens/accuracy_detail.dart | 93 +- lib/screens/accuracy_list.dart | 183 +- lib/screens/basal/basal_detail.dart | 88 +- lib/screens/basal/basal_list.dart | 132 +- lib/screens/basal/basal_profile_detail.dart | 122 +- lib/screens/basal/basal_profiles_list.dart | 111 +- lib/screens/bolus/bolus_detail.dart | 113 +- lib/screens/bolus/bolus_list.dart | 131 +- lib/screens/bolus/bolus_profile_detail.dart | 132 +- lib/screens/bolus/bolus_profile_list.dart | 120 +- lib/screens/log/active_log_event_list.dart | 172 +- lib/screens/log/log.dart | 163 +- lib/screens/log/log_entry.dart | 278 +-- lib/screens/log/log_entry_form.dart | 2 +- lib/screens/log/log_event_detail.dart | 63 +- lib/screens/log/log_event_list.dart | 190 +- lib/screens/log/log_event_type_detail.dart | 40 +- lib/screens/log/log_event_type_list.dart | 95 +- lib/screens/log/log_meal_detail.dart | 322 ++-- lib/screens/log/log_meal_list.dart | 109 +- lib/screens/meal/meal_category_detail.dart | 12 +- lib/screens/meal/meal_category_list.dart | 96 +- lib/screens/meal/meal_detail.dart | 248 ++- lib/screens/meal/meal_list.dart | 85 +- .../meal/meal_portion_type_detail.dart | 25 +- lib/screens/meal/meal_portion_type_list.dart | 100 +- lib/screens/meal/meal_source_detail.dart | 136 +- lib/screens/meal/meal_source_list.dart | 120 +- logs/parse-server.err.2021-10-31 | 0 logs/parse-server.info.2021-10-31 | 0 pubspec.lock | 278 ++- pubspec.yaml | 44 +- 54 files changed, 4751 insertions(+), 3553 deletions(-) create mode 100644 lib/object_box.dart create mode 100644 lib/objectbox-model.json create mode 100644 lib/objectbox.g.dart create mode 100644 logs/parse-server.err.2021-10-31 create mode 100644 logs/parse-server.info.2021-10-31 diff --git a/README.md b/README.md index f7b02b6..78045d0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# tide +# Diameter A new Flutter project. @@ -8,8 +8,8 @@ This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: -- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) For help getting started with Flutter, view our [online documentation](https://flutter.dev/docs), which offers tutorials, diff --git a/TODO b/TODO index 144b8d0..a522ce5 100644 --- a/TODO +++ b/TODO @@ -3,4 +3,5 @@ Todo: ☐ add active/deleted flag to all data models ☐ account for deleted/disabled elements in dropdowns ☐ place dropdown items right below their input - ☐ use local database instead of back4app \ No newline at end of file + ✔ use local database instead of back4app @done(21-11-07 18:53) + \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 03f030d..e8ef626 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -65,4 +65,5 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "com.github.parse-community.Parse-SDK-Android:parse:2.0.3" } diff --git a/android/build.gradle b/android/build.gradle index ed45c65..44bf4e1 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -15,6 +15,7 @@ allprojects { repositories { google() mavenCentral() + maven { url "https://jitpack.io" } } } diff --git a/lib/components/progress_indicator.dart b/lib/components/progress_indicator.dart index 1e52b69..f9a69e9 100644 --- a/lib/components/progress_indicator.dart +++ b/lib/components/progress_indicator.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; +// import 'package:flutter/widgets.dart'; class ViewWithProgressIndicator extends StatefulWidget { final AsyncSnapshot snapshot; @@ -28,10 +28,6 @@ class _ViewWithProgressIndicatorState extends State { switch (widget.snapshot.connectionState) { case ConnectionState.none: case ConnectionState.waiting: - Widget progressIndicator = Container(); - // Future.delayed(const Duration(milliseconds: 100)).then((_) => { - // progressIndicator = const CircularProgressIndicator() - // }); return Container( alignment: Alignment.center, padding: widget.padding, diff --git a/lib/main.dart b/lib/main.dart index 6a024a0..b1b4763 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:diameter/components/app_theme.dart'; +import 'package:diameter/object_box.dart'; import 'package:diameter/screens/accuracy_detail.dart'; import 'package:diameter/screens/basal/basal_profile_detail.dart'; import 'package:diameter/screens/bolus/bolus_profile_detail.dart'; @@ -24,14 +25,22 @@ import 'package:diameter/screens/basal/basal_profiles_list.dart'; import 'package:diameter/screens/bolus/bolus_profile_list.dart'; import 'package:diameter/navigation.dart'; -void main() async { +late ObjectBox objectBox; +Future main() async { WidgetsFlutterBinding.ensureInitialized(); - await Parse().initialize(keyApplicationId, keyParseServerUrl, - clientKey: keyClientKey, debug: true); + await Parse().initialize( + keyApplicationId, + keyParseServerUrl, + clientKey: keyClientKey, + debug: true, + coreStore: await CoreStoreSharedPrefsImp.getInstance(), + ); Settings.loadSettingsIntoConfig(); + objectBox = await ObjectBox.create(); + runApp( MaterialApp( theme: AppTheme.makeTheme(AppTheme.lightTheme), diff --git a/lib/models/accuracy.dart b/lib/models/accuracy.dart index b01a896..5391c84 100644 --- a/lib/models/accuracy.dart +++ b/lib/models/accuracy.dart @@ -1,126 +1,45 @@ -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/main.dart'; +import 'package:diameter/objectbox.g.dart'; +@Entity() class Accuracy { - late String? objectId; - late String value; - late bool forCarbsRatio = false; - late bool forPortionSize = false; - late int? confidenceRating; - late String? notes; + static final Box box = objectBox.store.box(); - Accuracy(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - value = object.get('value')!; - forCarbsRatio = object.get('forCarbsRatio')!; - forPortionSize = object.get('forPortionSize')!; - confidenceRating = object.get('confidenceRating') != null - ? object.get('confidenceRating')!.toInt() - : null; - notes = object.get('notes'); - } + int id; + String value; + bool forCarbsRatio; + bool forPortionSize; + int? confidenceRating; + String? notes; + + Accuracy({ + this.id = 0, + this.value = '', + this.forCarbsRatio = false, + this.forPortionSize = false, + this.confidenceRating, + this.notes, + }); + + static Accuracy? get(int id) => box.get(id); + static List getAll() { + QueryBuilder all = box.query()..order(Accuracy_.confidenceRating); + return all.build().find(); + } + static void put(Accuracy accuracy) => box.put(accuracy); + static void remove(int id) => box.remove(id); + + static List getAllForPortionSize() { + QueryBuilder allForPortionSize = box + .query(Accuracy_.forPortionSize.equals(true)) + ..order(Accuracy_.confidenceRating); + return allForPortionSize.build().find(); } - static Future> fetchAll() async { - QueryBuilder query = - QueryBuilder(ParseObject('Accuracy')); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => Accuracy(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future> fetchAllForCarbsRatio() async { - QueryBuilder query = - QueryBuilder(ParseObject('Accuracy')) - ..whereEqualTo('forCarbsRatio', true); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => Accuracy(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future> fetchAllForPortionSize() async { - QueryBuilder query = - QueryBuilder(ParseObject('Accuracy')) - ..whereEqualTo('forPortionSize', true); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => Accuracy(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('Accuracy')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return Accuracy(apiResponse.result.first); - } - } - - static Future save({ - required String value, - bool forCarbsRatio = false, - bool forPortionSize = false, - int? confidenceRating, - String? notes, - }) async { - final accuracy = ParseObject('Accuracy') - ..set('value', value) - ..set('forCarbsRatio', forCarbsRatio) - ..set('forPortionSize', forPortionSize) - ..set('confidenceRating', confidenceRating) - ..set('notes', notes); - await accuracy.save(); - } - - static Future update( - String objectId, { - String? value, - bool? forCarbsRatio, - bool? forPortionSize, - int? confidenceRating, - String? notes, - }) async { - var accuracy = ParseObject('Accuracy')..objectId = objectId; - if (value != null) { - accuracy.set('value', value); - } - if (forCarbsRatio != null) { - accuracy.set('forCarbsRatio', forCarbsRatio); - } - if (forPortionSize != null) { - accuracy.set('forPortionSize', forPortionSize); - } - if (confidenceRating != null) { - accuracy.set('confidenceRating', confidenceRating); - } - if (notes != null) { - accuracy.set('notes', notes); - } - await accuracy.save(); - } - - Future delete() async { - var accuracy = ParseObject('Accuracy')..objectId = objectId; - await accuracy.delete(); + static List getAllForCarbsRatio() { + QueryBuilder allForCarbsRatio = box + .query(Accuracy_.forCarbsRatio.equals(true)) + ..order(Accuracy_.confidenceRating); + return allForCarbsRatio.build().find(); } } diff --git a/lib/models/basal.dart b/lib/models/basal.dart index 85f3525..cb547be 100644 --- a/lib/models/basal.dart +++ b/lib/models/basal.dart @@ -1,115 +1,37 @@ -// import 'package:diameter/utils/date_time_utils.dart'; -// import 'package:flutter/material.dart'; -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/main.dart'; import 'package:diameter/models/basal_profile.dart'; -import 'package:diameter/components/data_table.dart'; +import 'package:diameter/objectbox.g.dart'; -class Basal extends DataTableContent { - late String? objectId; - late DateTime startTime; - late DateTime endTime; - late double units; - late String basalProfile; +@Entity() +class Basal { + static final Box box = objectBox.store.box(); + + int id; - Basal(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - startTime = object.get('startTime')!.toLocal(); - endTime = object.get('endTime')!.toLocal(); - units = object.get('units')! / 100; - basalProfile = - object.get('basalProfile')!.get('objectId')!; - } + @Property(type: PropertyType.date) + DateTime startTime; + + @Property(type: PropertyType.date) + DateTime endTime; + + double units; + + final basalProfile = ToOne(); + + Basal({ + this.id = 0, + required this.startTime, + required this.endTime, + this.units = 0, + }); + + static Basal? get(int id) => box.get(id); + static void put(Basal basal) => box.put(basal); + static void remove(int id) => box.remove(id); + + static List getAllForProfile(int id) { + QueryBuilder builder = box.query()..order(Basal_.startTime); + builder.link(Basal_.basalProfile, BasalProfile_.id.equals(id)); + return builder.build().find(); } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('Basal')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return Basal(apiResponse.result.first); - } - } - - static Future> fetchAllForBasalProfile( - BasalProfile basalProfile) async { - QueryBuilder query = - QueryBuilder(ParseObject('Basal')) - ..whereEqualTo( - 'basalProfile', - (ParseObject('BasalProfile')..objectId = basalProfile.objectId!) - .toPointer()) - ..orderByAscending('startTime'); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results!.map((e) => Basal(e as ParseObject)).toList(); - } else { - return []; - } - } - - static Future save({ - required DateTime startTime, - required DateTime endTime, - required double units, - required String basalProfile, - }) async { - final basal = ParseObject('Basal') - ..set('startTime', startTime.toUtc()) - ..set('endTime', endTime.toUtc()) - ..set('units', units * 100) - ..set('basalProfile', - (ParseObject('BasalProfile')..objectId = basalProfile).toPointer()); - await basal.save(); - } - - static Future update( - String objectId, { - DateTime? startTime, - DateTime? endTime, - double? units, - }) async { - var basal = ParseObject('Basal')..objectId = objectId; - if (startTime != null) { - basal.set('startTime', startTime.toUtc()); - } - if (endTime != null) { - basal.set('endTime', endTime.toUtc()); - } - if (units != null) { - basal.set('units', units * 100); - } - await basal.save(); - } - - Future delete() async { - var basal = ParseObject('Basal')..objectId = objectId; - await basal.delete(); - } - // - // @override - // List asDataTableCells(List? actions) { - // return [ - // DataCell(Text(DateTimeUtils.displayTime(startTime))), - // DataCell(Text(DateTimeUtils.displayTime(endTime))), - // DataCell(Text('${units.toString()} U')), - // DataCell( - // Row( - // children: actions ?? [], - // ), - // ), - // ]; - // } - // - // static List asDataTableColumns() { - // return [ - // const DataColumn(label: Expanded(child: Text('Start Time'))), - // const DataColumn(label: Expanded(child: Text('End Time'))), - // const DataColumn(label: Expanded(child: Text('Units'))), - // const DataColumn(label: Expanded(child: Text('Actions'))), - // ]; - // } } diff --git a/lib/models/basal_profile.dart b/lib/models/basal_profile.dart index ce051cf..ceb9bff 100644 --- a/lib/models/basal_profile.dart +++ b/lib/models/basal_profile.dart @@ -1,101 +1,37 @@ -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; -import 'package:diameter/models/basal.dart'; +import 'package:diameter/main.dart'; +import 'package:diameter/objectbox.g.dart'; +@Entity() class BasalProfile { - late String? objectId; - late String name; - late bool active = false; - late Future> basalRates; - late String? notes; + static final Box box = objectBox.store.box(); - BasalProfile(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - name = object.get('name')!; - active = object.get('active')!; - basalRates = Basal.fetchAllForBasalProfile(this); - notes = object.get('notes'); - } + int id; + String name; + bool active; + String? notes; + + BasalProfile({ + this.id = 0, + this.name = '', + this.active = false, + this.notes, + }); + + static BasalProfile? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(BasalProfile basalProfile) => box.put(basalProfile); + static void remove(int id) => box.remove(id); + + static int activeCount() { + Query query = + box.query(BasalProfile_.active.equals(true)).build(); + return query.find().length; } - static Future> fetchAll() async { - QueryBuilder query = - QueryBuilder(ParseObject('BasalProfile')); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => BasalProfile(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('BasalProfile')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return BasalProfile(apiResponse.result.first); - } - } - - static Future getActiveCount() async { - QueryBuilder query = - QueryBuilder(ParseObject('BasalProfile')) - ..whereEqualTo('active', true); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results!.length; - } else { - return 0; - } - } - - static Future setAllInactive({String? exception}) async { - QueryBuilder query = - QueryBuilder(ParseObject('BasalProfile')); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - for (var basalProfile in apiResponse.results as List) { - basalProfile.set( - 'active', basalProfile.objectId == exception ? true : false); - await basalProfile.save(); - } - } - } - - static Future save( - {required String name, bool active = false, String? notes}) async { - final basalProfile = ParseObject('BasalProfile') - ..set('name', name) - ..set('active', active) - ..set('notes', notes); - await basalProfile.save(); - } - - static Future update(String objectId, - {String? name, bool? active, String? notes}) async { - var basalProfile = ParseObject('BasalProfile')..objectId = objectId; - if (name != null) { - basalProfile.set('name', name); - } - if (active != null) { - basalProfile.set('active', active); - } - if (notes != null) { - basalProfile.set('notes', notes); - } - await basalProfile.save(); - } - - Future delete() async { - var basalProfile = ParseObject('BasalProfile')..objectId = objectId; - await basalProfile.delete(); + static void setAllInactive() { + box.putMany(box.getAll().map((element) { + element.active = false; + return element; + }).toList()); } } diff --git a/lib/models/bolus.dart b/lib/models/bolus.dart index 0e4d92a..975f461 100644 --- a/lib/models/bolus.dart +++ b/lib/models/bolus.dart @@ -1,201 +1,40 @@ -// import 'package:diameter/config.dart'; -// import 'package:diameter/settings.dart'; -// import 'package:diameter/utils/date_time_utils.dart'; -import 'package:diameter/utils/utils.dart'; -// import 'package:flutter/material.dart'; -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; -import 'package:diameter/components/data_table.dart'; +import 'package:diameter/main.dart'; import 'package:diameter/models/bolus_profile.dart'; +import 'package:diameter/objectbox.g.dart'; -class Bolus extends DataTableContent { - late String? objectId; - late DateTime startTime; - late DateTime endTime; - late double units; - late double carbs; - late int? mgPerDl; - late double? mmolPerL; - late String bolusProfile; +@Entity() +class Bolus { + static final Box box = objectBox.store.box(); - Bolus(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - startTime = object.get('startTime')!.toLocal(); - endTime = object.get('endTime')!.toLocal(); - units = object.get('units')! / 100; - carbs = object.get('carbs')!.toDouble(); - mgPerDl = object.get('mgPerDl') != null - ? object.get('mgPerDl')!.toInt() - : null; - mmolPerL = object.get('mmolPerL') != null - ? object.get('mmolPerL')! / 100 - : null; - bolusProfile = - object.get('bolusProfile')!.get('objectId')!; - } + int id; + @Property(type: PropertyType.date) + DateTime startTime; + @Property(type: PropertyType.date) + DateTime endTime; + double units; + double carbs; + int? mgPerDl; + double? mmolPerL; + + final bolusProfile = ToOne(); + + Bolus({ + this.id = 0, + required this.startTime, + required this.endTime, + this.units = 0, + this.carbs = 0, + this.mgPerDl, + this.mmolPerL, + }); + + static Bolus? get(int id) => box.get(id); + static void put(Bolus bolus) => box.put(bolus); + static void remove(int id) => box.remove(id); + + static List getAllForProfile(int id) { + QueryBuilder builder = box.query()..order(Bolus_.startTime); + builder.link(Bolus_.bolusProfile, BolusProfile_.id.equals(id)); + return builder.build().find(); } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('Bolus')) - ..whereEqualTo('objectId', objectId); - - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return Bolus(apiResponse.result.first); - } - } - - static Future> fetchAllForBolusProfile( - BolusProfile bolusProfile) async { - QueryBuilder query = - QueryBuilder(ParseObject('Bolus')) - ..whereEqualTo( - 'bolusProfile', - (ParseObject('BolusProfile')..objectId = bolusProfile.objectId!) - .toPointer()) - ..orderByAscending('startTime'); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results!.map((e) => Bolus(e as ParseObject)).toList(); - } else { - return []; - } - } - - static Future save({ - required DateTime startTime, - required DateTime endTime, - required double units, - required double carbs, - int? mgPerDl, - double? mmolPerL, - required String bolusProfile, - }) async { - final bolus = ParseObject('Bolus') - ..set('startTime', startTime.toUtc()) - ..set('endTime', endTime.toUtc()) - ..set('units', units * 100) - ..set('carbs', carbs.round()) - ..set('bolusProfile', - (ParseObject('BolusProfile')..objectId = bolusProfile).toPointer()); - - bolus.set( - 'mgPerDl', - mgPerDl != null - ? mgPerDl.round() - : Utils.convertMmolPerLToMgPerDl(mmolPerL ?? 0)); - bolus.set( - 'mmolPerL', - mmolPerL != null - ? mmolPerL * 100 - : Utils.convertMgPerDlToMmolPerL(mgPerDl ?? 0) * 100); - - await bolus.save(); - } - - static Future update( - String objectId, { - DateTime? startTime, - DateTime? endTime, - double? units, - double? carbs, - int? mgPerDl, - double? mmolPerL, - }) async { - var bolus = ParseObject('Bolus')..objectId = objectId; - if (startTime != null) { - bolus.set('startTime', startTime.toUtc()); - } - if (endTime != null) { - bolus.set('endTime', endTime.toUtc()); - } - if (units != null) { - bolus.set('units', units * 100); - } - if (carbs != null) { - bolus.set('carbs', carbs); - } - - if (mgPerDl != null || mmolPerL != null) { - bolus.set( - 'mgPerDl', - mgPerDl != null - ? mgPerDl.round() - : Utils.convertMmolPerLToMgPerDl(mmolPerL ?? 0)); - bolus.set( - 'mmolPerL', - mmolPerL != null - ? mmolPerL * 100 - : Utils.convertMgPerDlToMmolPerL(mgPerDl ?? 0) * 100); - } - - await bolus.save(); - } - - Future delete() async { - var bolus = ParseObject('Bolus')..objectId = objectId; - await bolus.delete(); - } - // - // @override - // List asDataTableCells(List? actions) { - // var cols = [ - // DataCell(Text(DateTimeUtils.displayTime(startTime))), - // DataCell(Text(DateTimeUtils.displayTime(endTime))), - // DataCell(Text('${units.toString()} U')), - // DataCell(Text('${carbs.toString()} g')), - // ]; - // - // if (glucoseMeasurement == GlucoseMeasurement.mgPerDl || - // glucoseDisplayMode == GlucoseDisplayMode.both || - // glucoseDisplayMode == GlucoseDisplayMode.bothForList) { - // cols.add(DataCell(Text('${mgPerDl.toString()} mg/dl'))); - // } - // - // if (glucoseMeasurement == GlucoseMeasurement.mmolPerL || - // glucoseDisplayMode == GlucoseDisplayMode.both || - // glucoseDisplayMode == GlucoseDisplayMode.bothForList) { - // cols.add(DataCell(Text('${mmolPerL.toString()} mmol/l'))); - // } - // - // cols.add( - // DataCell( - // Row( - // children: actions ?? [], - // ), - // ), - // ); - // - // return cols; - // } - // - // static List asDataTableColumns() { - // var cols = [ - // const DataColumn(label: Expanded(child: Text('Start Time'))), - // const DataColumn(label: Expanded(child: Text('End Time'))), - // const DataColumn(label: Expanded(child: Text('Units'))), - // const DataColumn(label: Expanded(child: Text('per Carbs'))), - // ]; - // - // if (glucoseMeasurement == GlucoseMeasurement.mgPerDl || - // glucoseDisplayMode == GlucoseDisplayMode.both || - // glucoseDisplayMode == GlucoseDisplayMode.bothForList) { - // cols.add(const DataColumn(label: Expanded(child: Text('per mg/dl')))); - // } - // - // if (glucoseMeasurement == GlucoseMeasurement.mmolPerL || - // glucoseDisplayMode == GlucoseDisplayMode.both || - // glucoseDisplayMode == GlucoseDisplayMode.bothForList) { - // cols.add(const DataColumn(label: Expanded(child: Text('per mmol/l')))); - // } - // - // cols.add( - // const DataColumn(label: Expanded(child: Text('Actions'))), - // ); - // - // return cols; - // } } diff --git a/lib/models/bolus_profile.dart b/lib/models/bolus_profile.dart index dcee764..36966b5 100644 --- a/lib/models/bolus_profile.dart +++ b/lib/models/bolus_profile.dart @@ -1,101 +1,37 @@ -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; -import 'package:diameter/models/bolus.dart'; +import 'package:diameter/main.dart'; +import 'package:diameter/objectbox.g.dart'; +@Entity() class BolusProfile { - late String? objectId; - late String name; - late bool active = false; - late Future> bolusRates; - late String? notes; + static final Box box = objectBox.store.box(); - BolusProfile(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - name = object.get('name')!; - active = object.get('active')!; - bolusRates = Bolus.fetchAllForBolusProfile(this); - notes = object.get('notes'); - } + int id; + String name; + bool active; + String? notes; + + BolusProfile({ + this.id = 0, + this.name = '', + this.active = false, + this.notes, + }); + + static BolusProfile? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(BolusProfile bolusProfile) => box.put(bolusProfile); + static void remove(int id) => box.remove(id); + + static int activeCount() { + Query query = + box.query(BolusProfile_.active.equals(true)).build(); + return query.find().length; } - static Future> fetchAll() async { - QueryBuilder query = - QueryBuilder(ParseObject('BolusProfile')); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => BolusProfile(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('BolusProfile')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return BolusProfile(apiResponse.result.first); - } - } - - static Future getActiveCount() async { - QueryBuilder query = - QueryBuilder(ParseObject('BolusProfile')) - ..whereEqualTo('active', true); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results!.length; - } else { - return 0; - } - } - - static Future setAllInactive({String? exception}) async { - QueryBuilder query = - QueryBuilder(ParseObject('BolusProfile')); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - for (var bolusProfile in apiResponse.results as List) { - bolusProfile.set( - 'active', bolusProfile.objectId == exception ? true : false); - await bolusProfile.save(); - } - } - } - - static Future save( - {required String name, bool active = false, String? notes}) async { - final bolusProfile = ParseObject('BolusProfile') - ..set('name', name) - ..set('active', active) - ..set('notes', notes); - await bolusProfile.save(); - } - - static Future update(String objectId, - {String? name, bool? active, String? notes}) async { - var bolusProfile = ParseObject('BolusProfile')..objectId = objectId; - if (name != null) { - bolusProfile.set('name', name); - } - if (active != null) { - bolusProfile.set('active', active); - } - if (notes != null) { - bolusProfile.set('notes', notes); - } - await bolusProfile.save(); - } - - Future delete() async { - var bolusProfile = ParseObject('BolusProfile')..objectId = objectId; - await bolusProfile.delete(); + static void setAllInactive() { + box.putMany(box.getAll().map((element) { + element.active = false; + return element; + }).toList()); } } diff --git a/lib/models/log_entry.dart b/lib/models/log_entry.dart index 99d22c1..eaf4ac2 100644 --- a/lib/models/log_entry.dart +++ b/lib/models/log_entry.dart @@ -1,50 +1,55 @@ -import 'package:diameter/models/log_meal.dart'; -import 'package:diameter/utils/utils.dart'; -import 'package:flutter/material.dart'; -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/main.dart'; import 'package:diameter/models/log_event.dart'; +import 'package:diameter/models/log_meal.dart'; +import 'package:diameter/objectbox.g.dart'; +import 'package:objectbox/objectbox.dart'; +@Entity() class LogEntry { - late String? objectId; - late DateTime time; - late int? mgPerDl; - late double? mmolPerL; - late double? bolusGlucose; - late int? delayedBolusDuration; - // TODO: either rename this or all other fields using delayedBolusRate - late double? delayedBolusRatio; - late String? notes; - late Future> events; - late Future> endedEvents; - late Future> meals; + static final Box box = objectBox.store.box(); - LogEntry(ParseObject object) { - objectId = object.get('objectId'); - time = object.get('time')!.toLocal(); - mgPerDl = object.get('mgPerDl') != null - ? object.get('mgPerDl')!.toInt() - : null; - mmolPerL = object.get('mmolPerL') != null - ? object.get('mmolPerL')!.toDouble() - : null; - bolusGlucose = object.get('bolusGlucose') != null - ? object.get('bolusGlucose')!.toDouble() - : null; - delayedBolusDuration = object.get('delayedBolusDuration') != null - ? object.get('delayedBolusDuration')!.toInt() - : null; - delayedBolusRatio = object.get('delayedBolusRatio') != null - ? object.get('delayedBolusRatio')!.toDouble() - : null; - events = LogEvent.fetchAllForLogEntry(this); - endedEvents = LogEvent.fetchAllEndedByEntry(this); - meals = LogMeal.fetchAllForLogEntry(this); - notes = object.get('notes'); - } + int id; - static Future>> createDailyEntryMap() async { + @Property(type: PropertyType.date) + DateTime time; + + int? mgPerDl; + double? mmolPerL; + double? bolusGlucose; + int? delayedBolusDuration; + double? delayedBolusRate; + String? notes; + + @Backlink('logEntry') + final events = ToMany(); + + @Backlink('endLogEntry') + final endedEvents = ToMany(); + + @Backlink('logEntry') + final meals = ToMany(); + + LogEntry({ + this.id = 0, + required this.time, + this.mgPerDl, + this.mmolPerL, + this.bolusGlucose, + this.delayedBolusDuration, + this.delayedBolusRate, + this.notes, + }); + + static LogEntry? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(LogEntry logEntry) => box.put(logEntry); + static void remove(int id) => box.remove(id); + + static Map> getDailyEntryMap() { Map> dateMap = >{}; - List entries = await fetchAll(); + + QueryBuilder allByDate = box.query()..order(LogEntry_.time, flags: Order.descending); + List entries = allByDate.build().find(); DateTime? date; for (LogEntry entry in entries) { @@ -54,133 +59,4 @@ class LogEntry { return dateMap; } - - static Future> fetchAllForRange(DateTimeRange range) async { - QueryBuilder query = - QueryBuilder(ParseObject('LogEntry')) - ..whereGreaterThanOrEqualsTo('time', range.start.toUtc()) - ..whereLessThanOrEqualTo('time', range.end.toUtc()) - ..orderByAscending('time'); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => LogEntry(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future> fetchAll() async { - // TODO: consider adding pagination/lazy loading here - QueryBuilder query = - QueryBuilder(ParseObject('LogEntry')) - ..orderByAscending('time'); - ; - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => LogEntry(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('LogEntry')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return LogEntry(apiResponse.result.first); - } - } - - static Future save({ - required DateTime time, - int? mgPerDl, - double? mmolPerL, - double? bolusGlucose, - int? delayedBolusDuration, - double? delayedBolusRatio, - String? notes, - }) async { - final logEntry = ParseObject('LogEntry') - ..set('time', time.toUtc()) - ..set('bolusGlucose', bolusGlucose) - ..set('delayedBolusDuration', delayedBolusDuration) - ..set('delayedBolusRatio', delayedBolusRatio) - ..set('notes', notes); - - if (!(mgPerDl == null && mmolPerL == null)) { - logEntry.set( - 'mgPerDl', - mgPerDl != null - ? mgPerDl.round() - : Utils.convertMmolPerLToMgPerDl(mmolPerL ?? 0)); - logEntry.set( - 'mmolPerL', - mmolPerL != null - ? mmolPerL * 100 - : Utils.convertMgPerDlToMmolPerL(mgPerDl ?? 0) * 100); - } - - await logEntry.save(); - } - - static Future update( - String objectId, { - DateTime? time, - int? mgPerDl, - double? mmolPerL, - double? bolusGlucose, - int? delayedBolusDuration, - double? delayedBolusRatio, - String? notes, - }) async { - final logEntry = ParseObject('LogEntry'); - - if (time != null) { - logEntry.set('time', time.toUtc()); - } - - if (bolusGlucose != null) { - logEntry.set('bolusGlucose', bolusGlucose); - } - - if (delayedBolusDuration != null) { - logEntry.set('delayedBolusDuration', delayedBolusDuration); - } - - if (delayedBolusRatio != null) { - logEntry.set('delayedBolusRatio', delayedBolusRatio); - } - - if (notes != null) { - logEntry.set('notes', notes); - } - - if (!(mgPerDl == null && mmolPerL == null)) { - logEntry.set( - 'mgPerDl', - mgPerDl != null - ? mgPerDl.round() - : Utils.convertMmolPerLToMgPerDl(mmolPerL ?? 0)); - logEntry.set( - 'mmolPerL', - mmolPerL != null - ? mmolPerL * 100 - : Utils.convertMgPerDlToMmolPerL(mgPerDl ?? 0) * 100); - } - await logEntry.save(); - } - - Future delete() async { - var logEntry = ParseObject('LogEntry')..objectId = objectId; - await logEntry.delete(); - } } diff --git a/lib/models/log_event.dart b/lib/models/log_event.dart index b035d1e..4db1bec 100644 --- a/lib/models/log_event.dart +++ b/lib/models/log_event.dart @@ -1,176 +1,43 @@ -import 'package:diameter/components/data_table.dart'; +import 'package:diameter/main.dart'; import 'package:diameter/models/log_entry.dart'; import 'package:diameter/models/log_event_type.dart'; -import 'package:diameter/utils/date_time_utils.dart'; -import 'package:flutter/material.dart'; -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/objectbox.g.dart'; -class LogEvent extends DataTableContent { - late String? objectId; - late String logEntry; - late String? endLogEntry; - late String eventType; - late DateTime time; - late DateTime? endTime; - late bool hasEndTime; - late String? notes; +@Entity() +class LogEvent { + static final Box box = objectBox.store.box(); - LogEvent(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - logEntry = object.get('logEntry')!.get('objectId')!; - endLogEntry = - object.get('endLogEntry')?.get('objectId'); - eventType = - object.get('eventType')!.get('objectId')!; - time = object.get('time')!.toLocal(); - endTime = object.get('endTime')?.toLocal(); - hasEndTime = object.get('hasEndTime')!; - notes = object.get('notes'); - } + int id; + + @Property(type: PropertyType.date) + DateTime time; + + @Property(type: PropertyType.date) + DateTime? endTime; + + bool hasEndTime; + String? notes; + + final logEntry = ToOne(); + final endLogEntry = ToOne(); + final eventType = ToOne(); + + LogEvent({ + this.id = 0, + required this.time, + this.endTime, + this.hasEndTime = false, + this.notes, + }); + + static LogEvent? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(LogEvent logEvent) => box.put(logEvent); + static void remove(int id) => box.remove(id); + + static List getAllOngoing() { + QueryBuilder query = + box.query(LogEvent_.hasEndTime.equals(true) & LogEvent_.endTime.isNull())..order(LogEvent_.time); + return query.build().find(); } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('LogEvent')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return LogEvent(apiResponse.result.first); - } - } - - static Future> fetchAllActive() async { - QueryBuilder query = - QueryBuilder(ParseObject('LogEvent')) - ..whereEqualTo('hasEndTime', true) - ..whereEqualTo('endTime', null); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => LogEvent(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future> fetchAllForLogEntry(LogEntry logEntry) async { - QueryBuilder query = QueryBuilder( - ParseObject('LogEvent')) - ..whereEqualTo('logEntry', - (ParseObject('LogEntry')..objectId = logEntry.objectId!).toPointer()); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => LogEvent(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future> fetchAllEndedByEntry(LogEntry logEntry) async { - QueryBuilder query = QueryBuilder( - ParseObject('LogEvent')) - ..whereEqualTo('endLogEntry', - (ParseObject('LogEntry')..objectId = logEntry.objectId!).toPointer()); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => LogEvent(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future save({ - required String logEntry, - required String eventType, - required DateTime time, - required bool hasEndTime, - String? notes, - }) async { - final logEvent = ParseObject('LogEvent') - ..set('logEntry', - (ParseObject('LogEntry')..objectId = logEntry).toPointer()) - ..set('eventType', - (ParseObject('LogEventType')..objectId = eventType).toPointer()) - ..set('time', time.toUtc()) - ..set('hasEndTime', hasEndTime) - ..set('notes', notes); - await logEvent.save(); - } - - static Future update( - String objectId, { - String? eventType, - String? endLogEntry, - DateTime? time, - DateTime? endTime, - bool? hasEndTime, - String? notes, - }) async { - var logEvent = ParseObject('LogEvent')..objectId = objectId; - if (eventType != null) { - logEvent.set('eventType', - (ParseObject('LogEventType')..objectId = eventType).toPointer()); - } - if (endLogEntry != null) { - logEvent.set('endLogEntry', - (ParseObject('LogEntry')..objectId = endLogEntry).toPointer()); - } - if (time != null) { - logEvent.set('time', time.toUtc()); - } - if (endTime != null) { - logEvent.set('endTime', endTime.toUtc()); - } - if (hasEndTime != null) { - logEvent.set('hasEndTime', hasEndTime); - } - if (notes != null) { - logEvent.set('notes', notes); - } - await logEvent.save(); - } - - Future delete() async { - var logEvent = ParseObject('LogEvent')..objectId = objectId; - await logEvent.delete(); - } - // - // @override - // List asDataTableCells(List actions, - // {List? types}) { - // return [ - // DataCell(Text( - // types?.firstWhere((element) => element.objectId == eventType).value ?? - // types?.length.toString() ?? - // '')), - // DataCell(Text(DateTimeUtils.displayDateTime(time))), - // DataCell(Text(hasEndTime - // ? DateTimeUtils.displayDateTime(endTime, fallback: 'ongoing') - // : '-')), - // DataCell( - // Row( - // children: actions, - // ), - // ), - // ]; - // } - // - // static List asDataTableColumns() { - // return [ - // const DataColumn(label: Expanded(child: Text('Event Type'))), - // const DataColumn(label: Expanded(child: Text('Start Time'))), - // const DataColumn(label: Expanded(child: Text('End Time'))), - // const DataColumn(label: Expanded(child: Text('Actions'))), - // ]; - // } } diff --git a/lib/models/log_event_type.dart b/lib/models/log_event_type.dart index afa95dc..857813d 100644 --- a/lib/models/log_event_type.dart +++ b/lib/models/log_event_type.dart @@ -1,86 +1,26 @@ -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/main.dart'; +import 'package:objectbox/objectbox.dart'; +@Entity() class LogEventType { - late String? objectId; - late String value; - late bool hasEndTime; - late int? defaultReminderDuration; - late String? notes; + static final Box box = objectBox.store.box(); - LogEventType(ParseObject object) { - objectId = object.get('objectId'); - value = object.get('value')!; - hasEndTime = object.get('hasEndTime')!; - defaultReminderDuration = object.get('defaultReminderDuration') != null - ? object.get('defaultReminderDuration')!.toInt() - : null; - notes = object.get('notes'); - } + int id; + String value; + bool hasEndTime; + int? defaultReminderDuration; + String? notes; - static Future> fetchAll() async { - QueryBuilder query = - QueryBuilder(ParseObject('LogEventType')); - final ParseResponse apiResponse = await query.query(); + LogEventType({ + this.id = 0, + this.value = '', + this.hasEndTime = false, + this.defaultReminderDuration, + this.notes, + }); - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => LogEventType(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('LogEventType')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return LogEventType(apiResponse.result.first); - } - } - - static Future save({ - required String value, - required bool hasEndTime, - int? defaultReminderDuration, - String? notes, - }) async { - final logEventType = ParseObject('LogEventType') - ..set('value', value) - ..set('hasEndTime', hasEndTime) - ..set('defaultReminderDuration', defaultReminderDuration) - ..set('notes', notes); - await logEventType.save(); - } - - static Future update( - String objectId, { - String? value, - bool? hasEndTime, - int? defaultReminderDuration, - String? notes, - }) async { - var logEventType = ParseObject('LogEventType')..objectId = objectId; - if (value != null) { - logEventType.set('value', value); - } - if (hasEndTime != null) { - logEventType.set('hasEndTime', hasEndTime); - } - if (defaultReminderDuration != null) { - logEventType.set('defaultReminderDuration', defaultReminderDuration); - } - if (notes != null) { - logEventType.set('notes', notes); - } - await logEventType.save(); - } - - Future delete() async { - var logEventType = ParseObject('LogEventType')..objectId = objectId; - await logEventType.delete(); - } + static LogEventType? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(LogEventType logEventType) => box.put(logEventType); + static void remove(int id) => box.remove(id); } diff --git a/lib/models/log_meal.dart b/lib/models/log_meal.dart index 99b40c9..e1fea66 100644 --- a/lib/models/log_meal.dart +++ b/lib/models/log_meal.dart @@ -1,228 +1,48 @@ -import 'package:diameter/components/data_table.dart'; +import 'package:diameter/main.dart'; import 'package:diameter/models/log_entry.dart'; -import 'package:flutter/material.dart'; -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/models/meal.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/models/accuracy.dart'; +import 'package:objectbox/objectbox.dart'; -class LogMeal extends DataTableContent { - late String? objectId; - late String logEntry; - late String? meal; - late String value; - late String? source; - late String? category; - late String? portionType; - late double? carbsRatio; - late double? portionSize; - late double? carbsPerPortion; - late String? portionSizeAccuracy; - late String? carbsRatioAccuracy; - late double? bolus; - late int? delayedBolusDuration; - late double? delayedBolusRate; - late String? notes; +@Entity() +class LogMeal { + static final Box box = objectBox.store.box(); - LogMeal(ParseObject object) { - objectId = object.get('objectId'); - logEntry = object.get('logEntry')!.get('objectId')!; - meal = object.get('meal')?.get('objectId'); - value = object.get('value')!; - source = object.get('source')?.get('objectId'); - category = object.get('category')?.get('objectId'); - portionType = object.get('portionType')?.get('objectId'); - carbsRatio = object.get('carbsRatio')?.toDouble(); - portionSize = object.get('portionSize')?.toDouble(); - carbsPerPortion = object.get('carbsPerPortion')?.toDouble(); - portionSizeAccuracy = object.get('portionSizeAccuracy')?.get('objectId'); - carbsRatioAccuracy = object.get('carbsRatioAccuracy')?.get('objectId'); - bolus = object.get('bolus')?.toDouble(); - delayedBolusDuration = object.get('delayedBolusDuration')?.toInt(); - delayedBolusRate = object.get('delayedBolusRate')?.toDouble(); - notes = object.get('notes'); - } + int id; + String value; + double? carbsRatio; + double? portionSize; + double? carbsPerPortion; + double? bolus; + int? delayedBolusDuration; + double? delayedBolusRate; + String? notes; - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('LogMeal')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); + final logEntry = ToOne(); + final meal = ToOne(); + final mealSource = ToOne(); + final mealCategory = ToOne(); + final mealPortionType = ToOne(); + final portionSizeAccuracy = ToOne(); + final carbsRatioAccuracy = ToOne(); - if (apiResponse.success && apiResponse.results != null) { - return LogMeal(apiResponse.result.first); - } - } + LogMeal({ + this.id = 0, + this.value = '', + this.carbsRatio, + this.portionSize, + this.carbsPerPortion, + this.bolus, + this.delayedBolusDuration, + this.delayedBolusRate, + this.notes, + }); - static Future> fetchAllForLogEntry(LogEntry logEntry) async { - QueryBuilder query = QueryBuilder( - ParseObject('LogMeal')) - ..whereEqualTo('logEntry', - (ParseObject('LogEntry')..objectId = logEntry.objectId!).toPointer()); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => LogMeal(e as ParseObject)) - .toList(); - } else { - return []; - } - } - - static Future save({ - required String value, - required String logEntry, - String? meal, - String? source, - String? category, - String? portionType, - double? carbsRatio, - double? portionSize, - double? carbsPerPortion, - String? portionSizeAccuracy, - String? carbsRatioAccuracy, - double? bolus, - int? delayedBolusDuration, - double? delayedBolusRate, - String? notes, - }) async { - final logMeal = ParseObject('LogMeal') - ..set('value', value) - ..set('logEntry', - (ParseObject('LogEntry')..objectId = logEntry).toPointer()) - ..set('carbsRatio', carbsRatio) - ..set('portionSize', portionSize) - ..set('carbsPerPortion', carbsPerPortion) - ..set('bolus', bolus) - ..set('delayedBolusDuration', delayedBolusDuration) - ..set('delayedBolusRate', delayedBolusRate) - ..set('notes', notes); - - if (meal != null) { - logMeal.set('meal', (ParseObject('Meal')..objectId = meal).toPointer()); - } - if (source != null) { - logMeal.set( - 'source', (ParseObject('MealSource')..objectId = source).toPointer()); - } - if (category != null) { - logMeal.set('category', - (ParseObject('MealCategory')..objectId = category).toPointer()); - } - if (portionType != null) { - logMeal.set('portionType', - (ParseObject('MealPortionType')..objectId = portionType).toPointer()); - } - if (portionSizeAccuracy != null) { - logMeal.set( - 'portionSizeAccuracy', - (ParseObject('Accuracy')..objectId = portionSizeAccuracy) - .toPointer()); - } - if (carbsRatioAccuracy != null) { - logMeal.set('carbsRatioAccuracy', - (ParseObject('Accuracy')..objectId = carbsRatioAccuracy).toPointer()); - } - await logMeal.save(); - } - - static Future update( - String objectId, { - String? value, - String? meal, - String? source, - String? category, - String? portionType, - double? carbsRatio, - double? portionSize, - double? carbsPerPortion, - String? portionSizeAccuracy, - String? carbsRatioAccuracy, - double? bolus, - int? delayedBolusDuration, - double? delayedBolusRate, - String? notes, - }) async { - var logMeal = ParseObject('LogMeal')..objectId = objectId; - if (value != null) { - logMeal.set('value', value); - } - if (meal != null) { - logMeal.set('meal', (ParseObject('Meal')..objectId = meal).toPointer()); - } - if (source != null) { - logMeal.set( - 'source', (ParseObject('MealSource')..objectId = source).toPointer()); - } - if (category != null) { - logMeal.set('category', - (ParseObject('MealCategory')..objectId = category).toPointer()); - } - if (portionType != null) { - logMeal.set('portionType', - (ParseObject('MealPortionType')..objectId = portionType).toPointer()); - } - if (carbsRatio != null) { - logMeal.set('carbsRatio', carbsRatio); - } - if (portionSize != null) { - logMeal.set('portionSize', portionSize); - } - if (carbsPerPortion != null) { - logMeal.set('carbsPerPortion', carbsPerPortion); - } - if (portionSizeAccuracy != null) { - logMeal.set( - 'portionSizeAccuracy', - (ParseObject('Accuracy')..objectId = portionSizeAccuracy) - .toPointer()); - } - if (carbsRatioAccuracy != null) { - logMeal.set('carbsRatioAccuracy', - (ParseObject('Accuracy')..objectId = carbsRatioAccuracy).toPointer()); - } - if (bolus != null) { - logMeal.set('bolus', bolus); - } - if (delayedBolusDuration != null) { - logMeal.set('delayedBolusDuration', delayedBolusDuration); - } - if (delayedBolusRate != null) { - logMeal.set('delayedBolusRate', delayedBolusRate); - } - if (notes != null) { - logMeal.set('notes', notes); - } - await logMeal.save(); - } - - Future delete() async { - var logMeal = ParseObject('LogMeal')..objectId = objectId; - await logMeal.delete(); - } - - @override - List asDataTableCells(List? actions) { - return [ - DataCell(Text(value)), - DataCell(Text('${(carbsPerPortion ?? '').toString()} g')), - DataCell(Text('${(bolus ?? '').toString()} U')), - DataCell(Text(delayedBolusRate != null - ? '${delayedBolusRate.toString()} U/${(delayedBolusDuration ?? '').toString()} min' - : '')), - DataCell( - Row( - children: actions ?? [], - ), - ), - ]; - } - - static List asDataTableColumns() { - return [ - const DataColumn(label: Expanded(child: Text('Meal'))), - const DataColumn(label: Expanded(child: Text('Carbs'))), - const DataColumn(label: Expanded(child: Text('Bolus'))), - const DataColumn(label: Expanded(child: Text('Delayed Bolus'))), - const DataColumn(label: Expanded(child: Text('Actions'))), - ]; - } + static LogMeal? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(LogMeal logMeal) => box.put(logMeal); + static void remove(int id) => box.remove(id); } diff --git a/lib/models/meal.dart b/lib/models/meal.dart index 90feb1e..eb763e2 100644 --- a/lib/models/meal.dart +++ b/lib/models/meal.dart @@ -1,195 +1,45 @@ -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/main.dart'; +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:objectbox/objectbox.dart'; enum PortionCarbsParameter { carbsRatio, portionSize, carbsPerPortion } +@Entity() class Meal { - late String? objectId; - late String value; - late String? source; - late String? category; - late String? portionType; - late double? carbsRatio; - late double? portionSize; - late double? carbsPerPortion; - late String? portionSizeAccuracy; - late String? carbsRatioAccuracy; - late int? delayedBolusDuration; - late double? delayedBolusRate; - late String? notes; + static final Box box = objectBox.store.box(); - Meal(ParseObject object) { - objectId = object.get('objectId'); - value = object.get('value')!; - source = object.get('source') != null - ? object.get('source')!.get('objectId') - : null; - category = object.get('category') != null - ? object.get('category')!.get('objectId') - : null; - portionType = object.get('portionType') != null - ? object.get('portionType')!.get('objectId') - : null; - carbsRatio = object.get('carbsRatio') != null - ? object.get('carbsRatio')!.toDouble() - : null; - portionSize = object.get('portionSize') != null - ? object.get('portionSize')!.toDouble() - : null; - carbsPerPortion = object.get('carbsPerPortion') != null - ? object.get('carbsPerPortion')!.toDouble() - : null; - portionSizeAccuracy = object.get('portionSizeAccuracy') != null - ? object - .get('portionSizeAccuracy')! - .get('objectId') - : null; - carbsRatioAccuracy = object.get('carbsRatioAccuracy') != null - ? object.get('carbsRatioAccuracy')!.get('objectId') - : null; - delayedBolusDuration = object.get('delayedBolusDuration') != null - ? object.get('delayedBolusDuration')!.toInt() - : null; - delayedBolusRate = object.get('delayedBolusRate') != null - ? object.get('delayedBolusRate')!.toDouble() - : null; - notes = object.get('notes'); - } + int id; + String value; + double? carbsRatio; + double? portionSize; + double? carbsPerPortion; + int? delayedBolusDuration; + double? delayedBolusRate; + String? notes; - static Future> fetchAll() async { - QueryBuilder query = - QueryBuilder(ParseObject('Meal')); - final ParseResponse apiResponse = await query.query(); - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results!.map((e) => Meal(e as ParseObject)).toList(); - } else { - return []; - } - } + final mealSource = ToOne(); + final mealCategory = ToOne(); + final mealPortionType = ToOne(); + final portionSizeAccuracy = ToOne(); + final carbsRatioAccuracy = ToOne(); - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('Meal')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); + Meal({ + this.id = 0, + this.value = '', + this.carbsRatio, + this.portionSize, + this.carbsPerPortion, + this.delayedBolusDuration, + this.delayedBolusRate, + this.notes, + }); - if (apiResponse.success && apiResponse.results != null) { - return Meal(apiResponse.result.first); - } - } - - static Future save({ - required String value, - String? source, - String? category, - String? portionType, - double? carbsRatio, - double? portionSize, - double? carbsPerPortion, - String? portionSizeAccuracy, - String? carbsRatioAccuracy, - int? delayedBolusDuration, - double? delayedBolusRate, - String? notes, - }) async { - final meal = ParseObject('Meal') - ..set('value', value) - ..set('carbsRatio', carbsRatio) - ..set('portionSize', portionSize) - ..set('carbsPerPortion', carbsPerPortion) - ..set('delayedBolusDuration', delayedBolusDuration) - ..set('delayedBolusRate', delayedBolusRate) - ..set('notes', notes); - - if (source != null) { - meal.set( - 'source', (ParseObject('MealSource')..objectId = source).toPointer()); - } - if (category != null) { - meal.set('category', - (ParseObject('MealCategory')..objectId = category).toPointer()); - } - if (portionType != null) { - meal.set('portionType', - (ParseObject('MealPortionType')..objectId = portionType).toPointer()); - } - if (portionSizeAccuracy != null) { - meal.set( - 'portionSizeAccuracy', - (ParseObject('Accuracy')..objectId = portionSizeAccuracy) - .toPointer()); - } - if (carbsRatioAccuracy != null) { - meal.set('carbsRatioAccuracy', - (ParseObject('Accuracy')..objectId = carbsRatioAccuracy).toPointer()); - } - await meal.save(); - } - - static Future update( - String objectId, { - String? value, - String? source, - String? category, - String? portionType, - double? carbsRatio, - double? portionSize, - double? carbsPerPortion, - String? portionSizeAccuracy, - String? carbsRatioAccuracy, - int? delayedBolusDuration, - double? delayedBolusRate, - String? notes, - }) async { - var meal = ParseObject('Meal')..objectId = objectId; - if (value != null) { - meal.set('value', value); - } - if (source != null) { - meal.set( - 'source', (ParseObject('MealSource')..objectId = source).toPointer()); - } - if (category != null) { - meal.set('category', - (ParseObject('MealCategory')..objectId = category).toPointer()); - } - if (portionType != null) { - meal.set('portionType', - (ParseObject('MealPortionType')..objectId = portionType).toPointer()); - } - if (carbsRatio != null) { - meal.set('carbsRatio', carbsRatio); - } - if (portionSize != null) { - meal.set('portionSize', portionSize); - } - if (carbsPerPortion != null) { - meal.set('carbsPerPortion', carbsPerPortion); - } - if (portionSizeAccuracy != null) { - meal.set( - 'portionSizeAccuracy', - (ParseObject('Accuracy')..objectId = portionSizeAccuracy) - .toPointer()); - } - if (carbsRatioAccuracy != null) { - meal.set('carbsRatioAccuracy', - (ParseObject('Accuracy')..objectId = carbsRatioAccuracy).toPointer()); - } - if (delayedBolusDuration != null) { - meal.set('delayedBolusDuration', delayedBolusDuration); - } - if (delayedBolusRate != null) { - meal.set('delayedBolusRate', delayedBolusRate); - } - if (notes != null) { - meal.set('notes', notes); - } - await meal.save(); - } - - Future delete() async { - var meal = ParseObject('Meal')..objectId = objectId; - await meal.delete(); - } + static Meal? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(Meal meal) => box.put(meal); + static void remove(int id) => box.remove(id); } diff --git a/lib/models/meal_category.dart b/lib/models/meal_category.dart index 318f706..298dac0 100644 --- a/lib/models/meal_category.dart +++ b/lib/models/meal_category.dart @@ -1,68 +1,22 @@ -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/main.dart'; +import 'package:objectbox/objectbox.dart'; +@Entity() class MealCategory { - late String? objectId; - late String value; - late String? notes; + static final Box box = objectBox.store.box(); - MealCategory(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - value = object.get('value')!; - notes = object.get('notes'); - } - } + int id; + String value; + String? notes; - static Future> fetchAll() async { - QueryBuilder query = - QueryBuilder(ParseObject('MealCategory')); - final ParseResponse apiResponse = await query.query(); + MealCategory({ + this.id = 0, + this.value = '', + this.notes, + }); - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results!.map((e) => MealCategory(e as ParseObject)).toList(); - } else { - return []; - } - } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('MealCategory')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return MealCategory(apiResponse.result.first); - } - } - - static Future save({ - required String value, - String? notes, - }) async { - final mealCategory = ParseObject('MealCategory') - ..set('value', value) - ..set('notes', notes); - await mealCategory.save(); - } - - static Future update( - String objectId, { - String? value, - String? notes, - }) async { - var mealCategory = ParseObject('MealCategory')..objectId = objectId; - if (value != null) { - mealCategory.set('value', value); - } - if (notes != null) { - mealCategory.set('notes', notes); - } - await mealCategory.save(); - } - - Future delete() async { - var mealCategory = ParseObject('MealCategory')..objectId = objectId; - await mealCategory.delete(); - } + static MealCategory? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(MealCategory mealCategory) => box.put(mealCategory); + static void remove(int id) => box.remove(id); } diff --git a/lib/models/meal_portion_type.dart b/lib/models/meal_portion_type.dart index 650cab6..43d8734 100644 --- a/lib/models/meal_portion_type.dart +++ b/lib/models/meal_portion_type.dart @@ -1,69 +1,22 @@ -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/main.dart'; +import 'package:objectbox/objectbox.dart'; +@Entity() class MealPortionType { - late String? objectId; - late String value; - late String? notes; + static final Box box = objectBox.store.box(); - MealPortionType(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - value = object.get('value')!; - notes = object.get('notes'); - } - } + int id; + String value; + String? notes; - static Future> fetchAll() async { - QueryBuilder query = - QueryBuilder(ParseObject('MealPortionType')); - final ParseResponse apiResponse = await query.query(); + MealPortionType({ + this.id = 0, + this.value = '', + this.notes, + }); - if (apiResponse.success && apiResponse.results != null) { - // return apiResponse.results as List; - return apiResponse.results!.map((e) => MealPortionType(e as ParseObject)).toList(); - } else { - return []; - } - } - - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('MealPortionType')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return MealPortionType(apiResponse.result.first); - } - } - - static Future save({ - required String value, - String? notes, - }) async { - final mealPortionType = ParseObject('MealPortionType') - ..set('value', value) - ..set('notes', notes); - await mealPortionType.save(); - } - - static Future update( - String objectId, { - String? value, - String? notes, - }) async { - var mealPortionType = ParseObject('MealPortionType')..objectId = objectId; - if (value != null) { - mealPortionType.set('value', value); - } - if (notes != null) { - mealPortionType.set('notes', notes); - } - await mealPortionType.save(); - } - - Future delete() async { - var mealPortionType = ParseObject('MealPortionType')..objectId = objectId; - await mealPortionType.delete(); - } + static MealPortionType? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(MealPortionType mealPortionType) => box.put(mealPortionType); + static void remove(int id) => box.remove(id); } diff --git a/lib/models/meal_source.dart b/lib/models/meal_source.dart index 1a91042..03c1801 100644 --- a/lib/models/meal_source.dart +++ b/lib/models/meal_source.dart @@ -1,157 +1,30 @@ -// import 'package:diameter/models/accuracy.dart'; -// import 'package:diameter/models/meal_category.dart'; -// import 'package:diameter/models/meal_portion_type.dart'; -import 'package:parse_server_sdk_flutter/parse_server_sdk.dart'; +import 'package:diameter/main.dart'; +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'; +@Entity() class MealSource { - late String? objectId; - late String value; - late String? defaultCarbsRatioAccuracy; - late String? defaultPortionSizeAccuracy; - late String? defaultMealCategory; - late String? defaultMealPortionType; - late String? notes; + static final Box box = objectBox.store.box(); - MealSource(ParseObject? object) { - if (object != null) { - objectId = object.get('objectId'); - value = object.get('value')!; - defaultCarbsRatioAccuracy = - object.get('defaultCarbsRatioAccuracy') != null - ? object - .get('defaultCarbsRatioAccuracy')! - .get('objectId') - : null; - defaultPortionSizeAccuracy = - object.get('defaultPortionSizeAccuracy') != null - ? object - .get('defaultPortionSizeAccuracy')! - .get('objectId') - : null; - defaultMealCategory = - object.get('defaultMealCategory') != null - ? object - .get('defaultMealCategory')! - .get('objectId') - : null; - defaultMealPortionType = - object.get('defaultMealPortionType') != null - ? object - .get('defaultMealPortionType')! - .get('objectId') - : null; - notes = object.get('notes'); - } - } + int id; + String value; + String? notes; - static Future> fetchAll() async { - QueryBuilder query = - QueryBuilder(ParseObject('MealSource')); - final ParseResponse apiResponse = await query.query(); + final defaultMealCategory = ToOne(); + final defaultMealPortionType = ToOne(); + final defaultCarbsRatioAccuracy = ToOne(); + final defaultPortionSizeAccuracy = ToOne(); - if (apiResponse.success && apiResponse.results != null) { - return apiResponse.results! - .map((e) => MealSource(e as ParseObject)) - .toList(); - } else { - return []; - } - } + MealSource({ + this.id = 0, + this.value = '', + this.notes, + }); - static Future get(String objectId) async { - QueryBuilder query = - QueryBuilder(ParseObject('MealSource')) - ..whereEqualTo('objectId', objectId); - final ParseResponse apiResponse = await query.query(); - - if (apiResponse.success && apiResponse.results != null) { - return MealSource(apiResponse.result.first); - } - } - - static Future save({ - required String value, - String? defaultCarbsRatioAccuracy, - String? defaultPortionSizeAccuracy, - String? defaultMealCategory, - String? defaultMealPortionType, - String? notes, - }) async { - final mealSource = ParseObject('MealSource') - ..set('value', value) - ..set('notes', notes); - if (defaultCarbsRatioAccuracy != null) { - mealSource.set( - 'defaultCarbsRatioAccuracy', - (ParseObject('Accuracy')..objectId = defaultCarbsRatioAccuracy) - .toPointer()); - } - if (defaultPortionSizeAccuracy != null) { - mealSource.set( - 'defaultCarbsRatioAccuracy', - (ParseObject('Accuracy')..objectId = defaultPortionSizeAccuracy) - .toPointer()); - } - if (defaultMealCategory != null) { - mealSource.set( - 'defaultMealCategory', - (ParseObject('MealCategory')..objectId = defaultMealCategory) - .toPointer()); - } - if (defaultMealPortionType != null) { - mealSource.set( - 'defaultMealPortionType', - (ParseObject('MealPortionType')..objectId = defaultMealPortionType) - .toPointer()); - } - await mealSource.save(); - } - - static Future update( - String objectId, { - String? value, - String? defaultCarbsRatioAccuracy, - String? defaultPortionSizeAccuracy, - String? defaultMealCategory, - String? defaultMealPortionType, - String? notes, - }) async { - final mealSource = ParseObject('MealSource')..objectId = objectId; - if (value != null) { - mealSource.set('value', value); - } - if (defaultCarbsRatioAccuracy != null) { - mealSource.set( - 'defaultCarbsRatioAccuracy', - (ParseObject('Accuracy')..objectId = defaultCarbsRatioAccuracy) - .toPointer()); - } - if (defaultPortionSizeAccuracy != null) { - mealSource.set( - 'defaultCarbsRatioAccuracy', - (ParseObject('Accuracy')..objectId = defaultPortionSizeAccuracy) - .toPointer()); - } - if (defaultMealCategory != null) { - mealSource.set( - 'defaultMealCategory', - (ParseObject('MealCategory')..objectId = defaultMealCategory) - .toPointer()); - } - if (defaultMealPortionType != null) { - mealSource.set( - 'defaultMealPortionType', - (ParseObject('MealPortionType')..objectId = defaultMealPortionType) - .toPointer()); - } - if (notes != null) { - mealSource.set('notes', notes); - } - await mealSource.save(); - } - - Future delete() async { - var mealSource = ParseObject('MealSource')..objectId = objectId; - await mealSource.delete(); - } + static MealSource? get(int id) => box.get(id); + static List getAll() => box.getAll(); + static void put(MealSource mealSource) => box.put(mealSource); + static void remove(int id) => box.remove(id); } diff --git a/lib/object_box.dart b/lib/object_box.dart new file mode 100644 index 0000000..cbd2473 --- /dev/null +++ b/lib/object_box.dart @@ -0,0 +1,14 @@ +import 'package:diameter/objectbox.g.dart'; + +class ObjectBox { + late final Store store; + + ObjectBox._create(this.store) { + // additiona setup logic + } + + static Future create() async { + final store = await openStore(); + return ObjectBox._create(store); + } +} diff --git a/lib/objectbox-model.json b/lib/objectbox-model.json new file mode 100644 index 0000000..65b048e --- /dev/null +++ b/lib/objectbox-model.json @@ -0,0 +1,648 @@ +{ + "_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.", + "_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.", + "_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.", + "entities": [ + { + "id": "1:3095978685310268382", + "lastPropertyId": "6:5471636804765937328", + "name": "Accuracy", + "properties": [ + { + "id": "1:3455702077061719523", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:1048198814030724077", + "name": "value", + "type": 9 + }, + { + "id": "3:9003780003858349085", + "name": "forCarbsRatio", + "type": 1 + }, + { + "id": "4:5421422436108145565", + "name": "forPortionSize", + "type": 1 + }, + { + "id": "5:7741631874181070179", + "name": "confidenceRating", + "type": 6 + }, + { + "id": "6:5471636804765937328", + "name": "notes", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "2:1467758525778521891", + "lastPropertyId": "5:3908367275335317130", + "name": "Basal", + "properties": [ + { + "id": "1:4281816825522738642", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:4009055523978371979", + "name": "startTime", + "type": 10 + }, + { + "id": "3:4023788962759622162", + "name": "endTime", + "type": 10 + }, + { + "id": "4:7477362011547874977", + "name": "units", + "type": 8 + }, + { + "id": "5:3908367275335317130", + "name": "basalProfileId", + "type": 11, + "flags": 520, + "indexId": "1:8279975749291974737", + "relationTarget": "BasalProfile" + } + ], + "relations": [] + }, + { + "id": "3:3613736032926903785", + "lastPropertyId": "4:6719547342639071472", + "name": "BasalProfile", + "properties": [ + { + "id": "1:353771983641472117", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:3551375678911240048", + "name": "name", + "type": 9 + }, + { + "id": "3:8867907906620144161", + "name": "active", + "type": 1 + }, + { + "id": "4:6719547342639071472", + "name": "notes", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "4:3417770529060202389", + "lastPropertyId": "8:7679622918986671917", + "name": "Bolus", + "properties": [ + { + "id": "1:8141647919190345775", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:5125398907947855021", + "name": "startTime", + "type": 10 + }, + { + "id": "3:4407971823097024949", + "name": "endTime", + "type": 10 + }, + { + "id": "4:2189083553538343203", + "name": "units", + "type": 8 + }, + { + "id": "5:1743412468359480761", + "name": "carbs", + "type": 8 + }, + { + "id": "6:6172996718025500229", + "name": "mgPerDl", + "type": 6 + }, + { + "id": "7:5407916209359443797", + "name": "mmolPerL", + "type": 8 + }, + { + "id": "8:7679622918986671917", + "name": "bolusProfileId", + "type": 11, + "flags": 520, + "indexId": "2:1936045997906240691", + "relationTarget": "BolusProfile" + } + ], + "relations": [] + }, + { + "id": "5:8812452529027052317", + "lastPropertyId": "4:3030493484602726372", + "name": "BolusProfile", + "properties": [ + { + "id": "1:4233863196673391978", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:1213341428301430611", + "name": "name", + "type": 9 + }, + { + "id": "3:8255411532896152868", + "name": "active", + "type": 1 + }, + { + "id": "4:3030493484602726372", + "name": "notes", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "6:752131069307970560", + "lastPropertyId": "8:6492273995038150006", + "name": "LogEntry", + "properties": [ + { + "id": "1:5528657304180237933", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:2227745196606148370", + "name": "time", + "type": 10 + }, + { + "id": "3:6679353626542225935", + "name": "mgPerDl", + "type": 6 + }, + { + "id": "4:7624273251826662730", + "name": "mmolPerL", + "type": 8 + }, + { + "id": "5:3678829169126156351", + "name": "bolusGlucose", + "type": 8 + }, + { + "id": "6:1568597071506264632", + "name": "delayedBolusDuration", + "type": 6 + }, + { + "id": "7:8795268969829293398", + "name": "delayedBolusRate", + "type": 8 + }, + { + "id": "8:6492273995038150006", + "name": "notes", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "7:4303325892753185970", + "lastPropertyId": "8:2514297323717317184", + "name": "LogEvent", + "properties": [ + { + "id": "1:6648501734758557663", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:4564145770032506132", + "name": "time", + "type": 10 + }, + { + "id": "3:1956029073259700909", + "name": "endTime", + "type": 10 + }, + { + "id": "4:289190785515853098", + "name": "hasEndTime", + "type": 1 + }, + { + "id": "5:3285255817130847007", + "name": "notes", + "type": 9 + }, + { + "id": "6:7838546213550447420", + "name": "logEntryId", + "type": 11, + "flags": 520, + "indexId": "3:3670661188280692002", + "relationTarget": "LogEntry" + }, + { + "id": "7:8031421171668506924", + "name": "endLogEntryId", + "type": 11, + "flags": 520, + "indexId": "4:7379712902406481832", + "relationTarget": "LogEntry" + }, + { + "id": "8:2514297323717317184", + "name": "eventTypeId", + "type": 11, + "flags": 520, + "indexId": "5:1417691902662024007", + "relationTarget": "LogEventType" + } + ], + "relations": [] + }, + { + "id": "8:8362795406595606110", + "lastPropertyId": "5:7361377572496986196", + "name": "LogEventType", + "properties": [ + { + "id": "1:1430413826199774000", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:2680646402943052466", + "name": "value", + "type": 9 + }, + { + "id": "3:8730441532702098240", + "name": "hasEndTime", + "type": 1 + }, + { + "id": "4:236107426012682102", + "name": "defaultReminderDuration", + "type": 6 + }, + { + "id": "5:7361377572496986196", + "name": "notes", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "9:411177866700467286", + "lastPropertyId": "16:7121997990741934484", + "name": "LogMeal", + "properties": [ + { + "id": "1:962999525294133158", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:4212591835755306346", + "name": "value", + "type": 9 + }, + { + "id": "3:2349971916492396452", + "name": "carbsRatio", + "type": 8 + }, + { + "id": "4:6619360836320223700", + "name": "portionSize", + "type": 8 + }, + { + "id": "5:2215708755581938580", + "name": "carbsPerPortion", + "type": 8 + }, + { + "id": "6:8074052538574863399", + "name": "bolus", + "type": 8 + }, + { + "id": "7:3247926313599127440", + "name": "delayedBolusDuration", + "type": 6 + }, + { + "id": "8:8789440370359282572", + "name": "delayedBolusRate", + "type": 8 + }, + { + "id": "9:1920579694098037947", + "name": "notes", + "type": 9 + }, + { + "id": "10:1795064951424581062", + "name": "logEntryId", + "type": 11, + "flags": 520, + "indexId": "6:2834631406671335954", + "relationTarget": "LogEntry" + }, + { + "id": "11:1891119831250929825", + "name": "mealId", + "type": 11, + "flags": 520, + "indexId": "7:7173877404300881319", + "relationTarget": "Meal" + }, + { + "id": "12:4842743668630588125", + "name": "mealSourceId", + "type": 11, + "flags": 520, + "indexId": "8:7798251372140622457", + "relationTarget": "MealSource" + }, + { + "id": "13:2354087448211548018", + "name": "mealCategoryId", + "type": 11, + "flags": 520, + "indexId": "9:169838544472067864", + "relationTarget": "MealCategory" + }, + { + "id": "14:6539714286499574550", + "name": "mealPortionTypeId", + "type": 11, + "flags": 520, + "indexId": "10:5017472742879643357", + "relationTarget": "MealPortionType" + }, + { + "id": "15:6038336651358102122", + "name": "portionSizeAccuracyId", + "type": 11, + "flags": 520, + "indexId": "11:7222637893025102905", + "relationTarget": "Accuracy" + }, + { + "id": "16:7121997990741934484", + "name": "carbsRatioAccuracyId", + "type": 11, + "flags": 520, + "indexId": "12:35287836658362611", + "relationTarget": "Accuracy" + } + ], + "relations": [] + }, + { + "id": "10:382130101578692012", + "lastPropertyId": "13:4890778480468380841", + "name": "Meal", + "properties": [ + { + "id": "1:612386612600420389", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:681065067668661250", + "name": "value", + "type": 9 + }, + { + "id": "3:2286464176896471045", + "name": "carbsRatio", + "type": 8 + }, + { + "id": "4:416562598768357192", + "name": "portionSize", + "type": 8 + }, + { + "id": "5:1888298906034647156", + "name": "carbsPerPortion", + "type": 8 + }, + { + "id": "6:3569732290918220814", + "name": "delayedBolusDuration", + "type": 6 + }, + { + "id": "7:2172890064639236018", + "name": "delayedBolusRate", + "type": 8 + }, + { + "id": "8:6111684052388229887", + "name": "notes", + "type": 9 + }, + { + "id": "9:5739692923906084863", + "name": "mealSourceId", + "type": 11, + "flags": 520, + "indexId": "13:5996617393160420536", + "relationTarget": "MealSource" + }, + { + "id": "10:8193290820580187413", + "name": "mealCategoryId", + "type": 11, + "flags": 520, + "indexId": "14:2128681772675444526", + "relationTarget": "MealCategory" + }, + { + "id": "11:3434302594951612479", + "name": "mealPortionTypeId", + "type": 11, + "flags": 520, + "indexId": "15:6211229960970898621", + "relationTarget": "MealPortionType" + }, + { + "id": "12:7588894964037003621", + "name": "portionSizeAccuracyId", + "type": 11, + "flags": 520, + "indexId": "16:7050212577048329568", + "relationTarget": "Accuracy" + }, + { + "id": "13:4890778480468380841", + "name": "carbsRatioAccuracyId", + "type": 11, + "flags": 520, + "indexId": "17:9108886538013386415", + "relationTarget": "Accuracy" + } + ], + "relations": [] + }, + { + "id": "11:3158200688796904913", + "lastPropertyId": "3:3543757971350345683", + "name": "MealCategory", + "properties": [ + { + "id": "1:3678943122076184840", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:1327341169479604917", + "name": "value", + "type": 9 + }, + { + "id": "3:3543757971350345683", + "name": "notes", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "12:2111511899235985637", + "lastPropertyId": "3:1950852666001613408", + "name": "MealPortionType", + "properties": [ + { + "id": "1:65428405312238271", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:5681230398840506311", + "name": "value", + "type": 9 + }, + { + "id": "3:1950852666001613408", + "name": "notes", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "13:1283034494527412242", + "lastPropertyId": "7:5852853174931678667", + "name": "MealSource", + "properties": [ + { + "id": "1:7205380295259922130", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:5768595544243621991", + "name": "value", + "type": 9 + }, + { + "id": "3:458760914712162612", + "name": "notes", + "type": 9 + }, + { + "id": "4:2034134758700899120", + "name": "defaultMealCategoryId", + "type": 11, + "flags": 520, + "indexId": "18:3223820950176501928", + "relationTarget": "MealCategory" + }, + { + "id": "5:8956771998294100216", + "name": "defaultMealPortionTypeId", + "type": 11, + "flags": 520, + "indexId": "19:2932086504877178672", + "relationTarget": "MealPortionType" + }, + { + "id": "6:7521960537811004317", + "name": "defaultCarbsRatioAccuracyId", + "type": 11, + "flags": 520, + "indexId": "20:2257356658656760706", + "relationTarget": "Accuracy" + }, + { + "id": "7:5852853174931678667", + "name": "defaultPortionSizeAccuracyId", + "type": 11, + "flags": 520, + "indexId": "21:1931330716440762729", + "relationTarget": "Accuracy" + } + ], + "relations": [] + } + ], + "lastEntityId": "13:1283034494527412242", + "lastIndexId": "21:1931330716440762729", + "lastRelationId": "0:0", + "lastSequenceId": "0:0", + "modelVersion": 5, + "modelVersionParserMinimum": 5, + "retiredEntityUids": [], + "retiredIndexUids": [], + "retiredPropertyUids": [], + "retiredRelationUids": [], + "version": 1 +} \ No newline at end of file diff --git a/lib/objectbox.g.dart b/lib/objectbox.g.dart new file mode 100644 index 0000000..4517098 --- /dev/null +++ b/lib/objectbox.g.dart @@ -0,0 +1,1694 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: camel_case_types + +import 'dart:typed_data'; + +import 'package:objectbox/flatbuffers/flat_buffers.dart' as fb; +import 'package:objectbox/internal.dart'; // generated code can access "internal" functionality +import 'package:objectbox/objectbox.dart'; +import 'package:objectbox_flutter_libs/objectbox_flutter_libs.dart'; + +import 'models/accuracy.dart'; +import 'models/basal.dart'; +import 'models/basal_profile.dart'; +import 'models/bolus.dart'; +import 'models/bolus_profile.dart'; +import 'models/log_entry.dart'; +import 'models/log_event.dart'; +import 'models/log_event_type.dart'; +import 'models/log_meal.dart'; +import 'models/meal.dart'; +import 'models/meal_category.dart'; +import 'models/meal_portion_type.dart'; +import 'models/meal_source.dart'; + +export 'package:objectbox/objectbox.dart'; // so that callers only have to import this file + +final _entities = [ + ModelEntity( + id: const IdUid(1, 3095978685310268382), + name: 'Accuracy', + lastPropertyId: const IdUid(6, 5471636804765937328), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 3455702077061719523), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 1048198814030724077), + name: 'value', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 9003780003858349085), + name: 'forCarbsRatio', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(4, 5421422436108145565), + name: 'forPortionSize', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(5, 7741631874181070179), + name: 'confidenceRating', + type: 6, + flags: 0), + ModelProperty( + id: const IdUid(6, 5471636804765937328), + name: 'notes', + type: 9, + flags: 0) + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(2, 1467758525778521891), + name: 'Basal', + lastPropertyId: const IdUid(5, 3908367275335317130), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 4281816825522738642), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 4009055523978371979), + name: 'startTime', + type: 10, + flags: 0), + ModelProperty( + id: const IdUid(3, 4023788962759622162), + name: 'endTime', + type: 10, + flags: 0), + ModelProperty( + id: const IdUid(4, 7477362011547874977), + name: 'units', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(5, 3908367275335317130), + name: 'basalProfileId', + type: 11, + flags: 520, + indexId: const IdUid(1, 8279975749291974737), + relationTarget: 'BasalProfile') + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(3, 3613736032926903785), + name: 'BasalProfile', + lastPropertyId: const IdUid(4, 6719547342639071472), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 353771983641472117), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 3551375678911240048), + name: 'name', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 8867907906620144161), + name: 'active', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(4, 6719547342639071472), + name: 'notes', + type: 9, + flags: 0) + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(4, 3417770529060202389), + name: 'Bolus', + lastPropertyId: const IdUid(8, 7679622918986671917), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 8141647919190345775), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 5125398907947855021), + name: 'startTime', + type: 10, + flags: 0), + ModelProperty( + id: const IdUid(3, 4407971823097024949), + name: 'endTime', + type: 10, + flags: 0), + ModelProperty( + id: const IdUid(4, 2189083553538343203), + name: 'units', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(5, 1743412468359480761), + name: 'carbs', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(6, 6172996718025500229), + name: 'mgPerDl', + type: 6, + flags: 0), + ModelProperty( + id: const IdUid(7, 5407916209359443797), + name: 'mmolPerL', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(8, 7679622918986671917), + name: 'bolusProfileId', + type: 11, + flags: 520, + indexId: const IdUid(2, 1936045997906240691), + relationTarget: 'BolusProfile') + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(5, 8812452529027052317), + name: 'BolusProfile', + lastPropertyId: const IdUid(4, 3030493484602726372), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 4233863196673391978), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 1213341428301430611), + name: 'name', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 8255411532896152868), + name: 'active', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(4, 3030493484602726372), + name: 'notes', + type: 9, + flags: 0) + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(6, 752131069307970560), + name: 'LogEntry', + lastPropertyId: const IdUid(8, 6492273995038150006), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 5528657304180237933), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 2227745196606148370), + name: 'time', + type: 10, + flags: 0), + ModelProperty( + id: const IdUid(3, 6679353626542225935), + name: 'mgPerDl', + type: 6, + flags: 0), + ModelProperty( + id: const IdUid(4, 7624273251826662730), + name: 'mmolPerL', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(5, 3678829169126156351), + name: 'bolusGlucose', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(6, 1568597071506264632), + name: 'delayedBolusDuration', + type: 6, + flags: 0), + ModelProperty( + id: const IdUid(7, 8795268969829293398), + name: 'delayedBolusRate', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(8, 6492273995038150006), + name: 'notes', + type: 9, + flags: 0) + ], + relations: [], + backlinks: [ + ModelBacklink( + name: 'events', srcEntity: 'LogEvent', srcField: 'logEntry'), + ModelBacklink( + name: 'endedEvents', + srcEntity: 'LogEvent', + srcField: 'endLogEntry'), + ModelBacklink(name: 'meals', srcEntity: 'LogMeal', srcField: 'logEntry') + ]), + ModelEntity( + id: const IdUid(7, 4303325892753185970), + name: 'LogEvent', + lastPropertyId: const IdUid(8, 2514297323717317184), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 6648501734758557663), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 4564145770032506132), + name: 'time', + type: 10, + flags: 0), + ModelProperty( + id: const IdUid(3, 1956029073259700909), + name: 'endTime', + type: 10, + flags: 0), + ModelProperty( + id: const IdUid(4, 289190785515853098), + name: 'hasEndTime', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(5, 3285255817130847007), + name: 'notes', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(6, 7838546213550447420), + name: 'logEntryId', + type: 11, + flags: 520, + indexId: const IdUid(3, 3670661188280692002), + relationTarget: 'LogEntry'), + ModelProperty( + id: const IdUid(7, 8031421171668506924), + name: 'endLogEntryId', + type: 11, + flags: 520, + indexId: const IdUid(4, 7379712902406481832), + relationTarget: 'LogEntry'), + ModelProperty( + id: const IdUid(8, 2514297323717317184), + name: 'eventTypeId', + type: 11, + flags: 520, + indexId: const IdUid(5, 1417691902662024007), + relationTarget: 'LogEventType') + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(8, 8362795406595606110), + name: 'LogEventType', + lastPropertyId: const IdUid(5, 7361377572496986196), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 1430413826199774000), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 2680646402943052466), + name: 'value', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 8730441532702098240), + name: 'hasEndTime', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(4, 236107426012682102), + name: 'defaultReminderDuration', + type: 6, + flags: 0), + ModelProperty( + id: const IdUid(5, 7361377572496986196), + name: 'notes', + type: 9, + flags: 0) + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(9, 411177866700467286), + name: 'LogMeal', + lastPropertyId: const IdUid(16, 7121997990741934484), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 962999525294133158), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 4212591835755306346), + name: 'value', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 2349971916492396452), + name: 'carbsRatio', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(4, 6619360836320223700), + 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', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(7, 3247926313599127440), + name: 'delayedBolusDuration', + type: 6, + flags: 0), + ModelProperty( + id: const IdUid(8, 8789440370359282572), + name: 'delayedBolusRate', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(9, 1920579694098037947), + name: 'notes', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(10, 1795064951424581062), + name: 'logEntryId', + type: 11, + flags: 520, + indexId: const IdUid(6, 2834631406671335954), + relationTarget: 'LogEntry'), + ModelProperty( + id: const IdUid(11, 1891119831250929825), + name: 'mealId', + type: 11, + flags: 520, + indexId: const IdUid(7, 7173877404300881319), + relationTarget: 'Meal'), + ModelProperty( + id: const IdUid(12, 4842743668630588125), + name: 'mealSourceId', + type: 11, + flags: 520, + indexId: const IdUid(8, 7798251372140622457), + relationTarget: 'MealSource'), + ModelProperty( + id: const IdUid(13, 2354087448211548018), + name: 'mealCategoryId', + type: 11, + flags: 520, + indexId: const IdUid(9, 169838544472067864), + relationTarget: 'MealCategory'), + ModelProperty( + id: const IdUid(14, 6539714286499574550), + name: 'mealPortionTypeId', + type: 11, + flags: 520, + indexId: const IdUid(10, 5017472742879643357), + relationTarget: 'MealPortionType'), + ModelProperty( + id: const IdUid(15, 6038336651358102122), + name: 'portionSizeAccuracyId', + type: 11, + flags: 520, + indexId: const IdUid(11, 7222637893025102905), + relationTarget: 'Accuracy'), + ModelProperty( + id: const IdUid(16, 7121997990741934484), + name: 'carbsRatioAccuracyId', + type: 11, + flags: 520, + indexId: const IdUid(12, 35287836658362611), + relationTarget: 'Accuracy') + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(10, 382130101578692012), + name: 'Meal', + lastPropertyId: const IdUid(13, 4890778480468380841), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 612386612600420389), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 681065067668661250), + name: 'value', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 2286464176896471045), + name: 'carbsRatio', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(4, 416562598768357192), + name: 'portionSize', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(5, 1888298906034647156), + name: 'carbsPerPortion', + type: 8, + flags: 0), + ModelProperty( + id: const IdUid(6, 3569732290918220814), + 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', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(9, 5739692923906084863), + name: 'mealSourceId', + type: 11, + flags: 520, + indexId: const IdUid(13, 5996617393160420536), + relationTarget: 'MealSource'), + ModelProperty( + id: const IdUid(10, 8193290820580187413), + name: 'mealCategoryId', + type: 11, + flags: 520, + indexId: const IdUid(14, 2128681772675444526), + relationTarget: 'MealCategory'), + ModelProperty( + id: const IdUid(11, 3434302594951612479), + name: 'mealPortionTypeId', + type: 11, + flags: 520, + indexId: const IdUid(15, 6211229960970898621), + relationTarget: 'MealPortionType'), + ModelProperty( + id: const IdUid(12, 7588894964037003621), + name: 'portionSizeAccuracyId', + type: 11, + flags: 520, + indexId: const IdUid(16, 7050212577048329568), + relationTarget: 'Accuracy'), + ModelProperty( + id: const IdUid(13, 4890778480468380841), + name: 'carbsRatioAccuracyId', + type: 11, + flags: 520, + indexId: const IdUid(17, 9108886538013386415), + relationTarget: 'Accuracy') + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(11, 3158200688796904913), + name: 'MealCategory', + lastPropertyId: const IdUid(3, 3543757971350345683), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 3678943122076184840), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 1327341169479604917), + name: 'value', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 3543757971350345683), + name: 'notes', + type: 9, + flags: 0) + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(12, 2111511899235985637), + name: 'MealPortionType', + lastPropertyId: const IdUid(3, 1950852666001613408), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 65428405312238271), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 5681230398840506311), + name: 'value', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 1950852666001613408), + name: 'notes', + type: 9, + flags: 0) + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(13, 1283034494527412242), + name: 'MealSource', + lastPropertyId: const IdUid(7, 5852853174931678667), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 7205380295259922130), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 5768595544243621991), + name: 'value', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 458760914712162612), + name: 'notes', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(4, 2034134758700899120), + name: 'defaultMealCategoryId', + type: 11, + flags: 520, + indexId: const IdUid(18, 3223820950176501928), + relationTarget: 'MealCategory'), + ModelProperty( + id: const IdUid(5, 8956771998294100216), + name: 'defaultMealPortionTypeId', + type: 11, + flags: 520, + indexId: const IdUid(19, 2932086504877178672), + relationTarget: 'MealPortionType'), + ModelProperty( + id: const IdUid(6, 7521960537811004317), + name: 'defaultCarbsRatioAccuracyId', + type: 11, + flags: 520, + indexId: const IdUid(20, 2257356658656760706), + relationTarget: 'Accuracy'), + ModelProperty( + id: const IdUid(7, 5852853174931678667), + name: 'defaultPortionSizeAccuracyId', + type: 11, + flags: 520, + indexId: const IdUid(21, 1931330716440762729), + relationTarget: 'Accuracy') + ], + relations: [], + backlinks: []) +]; + +/// Open an ObjectBox store with the model declared in this file. +Future openStore( + {String? directory, + int? maxDBSizeInKB, + int? fileMode, + int? maxReaders, + bool queriesCaseSensitiveDefault = true, + String? macosApplicationGroup}) async => + Store(getObjectBoxModel(), + directory: directory ?? (await defaultStoreDirectory()).path, + maxDBSizeInKB: maxDBSizeInKB, + fileMode: fileMode, + maxReaders: maxReaders, + queriesCaseSensitiveDefault: queriesCaseSensitiveDefault, + macosApplicationGroup: macosApplicationGroup); + +/// ObjectBox model definition, pass it to [Store] - Store(getObjectBoxModel()) +ModelDefinition getObjectBoxModel() { + final model = ModelInfo( + entities: _entities, + lastEntityId: const IdUid(18, 1283034494527412242), + lastIndexId: const IdUid(25, 1931330716440762729), + lastRelationId: const IdUid(0, 0), + lastSequenceId: const IdUid(0, 0), + retiredEntityUids: const [], + retiredIndexUids: const [], + retiredPropertyUids: const [], + retiredRelationUids: const [], + modelVersion: 5, + modelVersionParserMinimum: 5, + version: 1); + + final bindings = { + Accuracy: EntityDefinition( + model: _entities[0], + toOneRelations: (Accuracy object) => [], + toManyRelations: (Accuracy object) => {}, + getId: (Accuracy object) => object.id, + setId: (Accuracy object, int id) { + object.id = id; + }, + objectToFB: (Accuracy object, fb.Builder fbb) { + final valueOffset = fbb.writeString(object.value); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(7); + fbb.addInt64(0, object.id); + fbb.addOffset(1, valueOffset); + fbb.addBool(2, object.forCarbsRatio); + fbb.addBool(3, object.forPortionSize); + fbb.addInt64(4, object.confidenceRating); + fbb.addOffset(5, notesOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = Accuracy( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + value: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + forCarbsRatio: + const fb.BoolReader().vTableGet(buffer, rootOffset, 8, false), + forPortionSize: const fb.BoolReader() + .vTableGet(buffer, rootOffset, 10, false), + confidenceRating: const fb.Int64Reader() + .vTableGetNullable(buffer, rootOffset, 12), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 14)); + + return object; + }), + Basal: EntityDefinition( + model: _entities[1], + toOneRelations: (Basal object) => [object.basalProfile], + toManyRelations: (Basal object) => {}, + getId: (Basal object) => object.id, + setId: (Basal object, int id) { + object.id = id; + }, + objectToFB: (Basal object, fb.Builder fbb) { + fbb.startTable(6); + fbb.addInt64(0, object.id); + fbb.addInt64(1, object.startTime.millisecondsSinceEpoch); + fbb.addInt64(2, object.endTime.millisecondsSinceEpoch); + fbb.addFloat64(3, object.units); + fbb.addInt64(4, object.basalProfile.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 = Basal( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + startTime: DateTime.fromMillisecondsSinceEpoch( + const fb.Int64Reader().vTableGet(buffer, rootOffset, 6, 0)), + endTime: DateTime.fromMillisecondsSinceEpoch( + const fb.Int64Reader().vTableGet(buffer, rootOffset, 8, 0)), + units: const fb.Float64Reader() + .vTableGet(buffer, rootOffset, 10, 0)); + object.basalProfile.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 12, 0); + object.basalProfile.attach(store); + return object; + }), + BasalProfile: EntityDefinition( + model: _entities[2], + toOneRelations: (BasalProfile object) => [], + toManyRelations: (BasalProfile object) => {}, + getId: (BasalProfile object) => object.id, + setId: (BasalProfile object, int id) { + object.id = id; + }, + objectToFB: (BasalProfile object, fb.Builder fbb) { + final nameOffset = fbb.writeString(object.name); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(5); + fbb.addInt64(0, object.id); + fbb.addOffset(1, nameOffset); + fbb.addBool(2, object.active); + fbb.addOffset(3, notesOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = BasalProfile( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + name: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + active: + const fb.BoolReader().vTableGet(buffer, rootOffset, 8, false), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 10)); + + return object; + }), + Bolus: EntityDefinition( + model: _entities[3], + toOneRelations: (Bolus object) => [object.bolusProfile], + toManyRelations: (Bolus object) => {}, + getId: (Bolus object) => object.id, + setId: (Bolus object, int id) { + object.id = id; + }, + objectToFB: (Bolus object, fb.Builder fbb) { + fbb.startTable(9); + fbb.addInt64(0, object.id); + fbb.addInt64(1, object.startTime.millisecondsSinceEpoch); + fbb.addInt64(2, object.endTime.millisecondsSinceEpoch); + fbb.addFloat64(3, object.units); + fbb.addFloat64(4, object.carbs); + fbb.addInt64(5, object.mgPerDl); + fbb.addFloat64(6, object.mmolPerL); + fbb.addInt64(7, object.bolusProfile.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 = Bolus( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + startTime: DateTime.fromMillisecondsSinceEpoch( + const fb.Int64Reader().vTableGet(buffer, rootOffset, 6, 0)), + endTime: DateTime.fromMillisecondsSinceEpoch( + const fb.Int64Reader().vTableGet(buffer, rootOffset, 8, 0)), + units: + const fb.Float64Reader().vTableGet(buffer, rootOffset, 10, 0), + carbs: + const fb.Float64Reader().vTableGet(buffer, rootOffset, 12, 0), + mgPerDl: const fb.Int64Reader() + .vTableGetNullable(buffer, rootOffset, 14), + mmolPerL: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 16)); + object.bolusProfile.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 18, 0); + object.bolusProfile.attach(store); + return object; + }), + BolusProfile: EntityDefinition( + model: _entities[4], + toOneRelations: (BolusProfile object) => [], + toManyRelations: (BolusProfile object) => {}, + getId: (BolusProfile object) => object.id, + setId: (BolusProfile object, int id) { + object.id = id; + }, + objectToFB: (BolusProfile object, fb.Builder fbb) { + final nameOffset = fbb.writeString(object.name); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(5); + fbb.addInt64(0, object.id); + fbb.addOffset(1, nameOffset); + fbb.addBool(2, object.active); + fbb.addOffset(3, notesOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = BolusProfile( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + name: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + active: + const fb.BoolReader().vTableGet(buffer, rootOffset, 8, false), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 10)); + + return object; + }), + LogEntry: EntityDefinition( + model: _entities[5], + toOneRelations: (LogEntry object) => [], + toManyRelations: (LogEntry object) => { + RelInfo.toOneBacklink( + 6, object.id, (LogEvent srcObject) => srcObject.logEntry): + object.events, + RelInfo.toOneBacklink(7, object.id, + (LogEvent srcObject) => srcObject.endLogEntry): + object.endedEvents, + RelInfo.toOneBacklink( + 10, object.id, (LogMeal srcObject) => srcObject.logEntry): + object.meals + }, + getId: (LogEntry object) => object.id, + setId: (LogEntry object, int id) { + object.id = id; + }, + objectToFB: (LogEntry object, fb.Builder fbb) { + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(9); + fbb.addInt64(0, object.id); + fbb.addInt64(1, object.time.millisecondsSinceEpoch); + fbb.addInt64(2, object.mgPerDl); + fbb.addFloat64(3, object.mmolPerL); + fbb.addFloat64(4, object.bolusGlucose); + fbb.addInt64(5, object.delayedBolusDuration); + fbb.addFloat64(6, object.delayedBolusRate); + fbb.addOffset(7, notesOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = LogEntry( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + time: DateTime.fromMillisecondsSinceEpoch( + const fb.Int64Reader().vTableGet(buffer, rootOffset, 6, 0)), + mgPerDl: const fb.Int64Reader() + .vTableGetNullable(buffer, rootOffset, 8), + mmolPerL: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 10), + bolusGlucose: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 12), + delayedBolusDuration: const fb.Int64Reader() + .vTableGetNullable(buffer, rootOffset, 14), + delayedBolusRate: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 16), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 18)); + InternalToManyAccess.setRelInfo( + object.events, + store, + RelInfo.toOneBacklink( + 6, object.id, (LogEvent srcObject) => srcObject.logEntry), + store.box()); + InternalToManyAccess.setRelInfo( + object.endedEvents, + store, + RelInfo.toOneBacklink( + 7, object.id, (LogEvent srcObject) => srcObject.endLogEntry), + store.box()); + InternalToManyAccess.setRelInfo( + object.meals, + store, + RelInfo.toOneBacklink( + 10, object.id, (LogMeal srcObject) => srcObject.logEntry), + store.box()); + return object; + }), + LogEvent: EntityDefinition( + model: _entities[6], + toOneRelations: (LogEvent object) => + [object.logEntry, object.endLogEntry, object.eventType], + toManyRelations: (LogEvent object) => {}, + getId: (LogEvent object) => object.id, + setId: (LogEvent object, int id) { + object.id = id; + }, + objectToFB: (LogEvent object, fb.Builder fbb) { + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(9); + fbb.addInt64(0, object.id); + fbb.addInt64(1, object.time.millisecondsSinceEpoch); + fbb.addInt64(2, object.endTime?.millisecondsSinceEpoch); + fbb.addBool(3, object.hasEndTime); + fbb.addOffset(4, notesOffset); + fbb.addInt64(5, object.logEntry.targetId); + fbb.addInt64(6, object.endLogEntry.targetId); + fbb.addInt64(7, object.eventType.targetId); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + final endTimeValue = + const fb.Int64Reader().vTableGetNullable(buffer, rootOffset, 8); + final object = LogEvent( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + time: DateTime.fromMillisecondsSinceEpoch( + const fb.Int64Reader().vTableGet(buffer, rootOffset, 6, 0)), + endTime: endTimeValue == null + ? null + : DateTime.fromMillisecondsSinceEpoch(endTimeValue), + hasEndTime: const fb.BoolReader() + .vTableGet(buffer, rootOffset, 10, false), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 12)); + object.logEntry.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 14, 0); + object.logEntry.attach(store); + object.endLogEntry.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 16, 0); + object.endLogEntry.attach(store); + object.eventType.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 18, 0); + object.eventType.attach(store); + return object; + }), + LogEventType: EntityDefinition( + model: _entities[7], + toOneRelations: (LogEventType object) => [], + toManyRelations: (LogEventType object) => {}, + getId: (LogEventType object) => object.id, + setId: (LogEventType object, int id) { + object.id = id; + }, + objectToFB: (LogEventType object, fb.Builder fbb) { + final valueOffset = fbb.writeString(object.value); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(6); + fbb.addInt64(0, object.id); + fbb.addOffset(1, valueOffset); + fbb.addBool(2, object.hasEndTime); + fbb.addInt64(3, object.defaultReminderDuration); + fbb.addOffset(4, notesOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = LogEventType( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + value: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + hasEndTime: + const fb.BoolReader().vTableGet(buffer, rootOffset, 8, false), + defaultReminderDuration: const fb.Int64Reader() + .vTableGetNullable(buffer, rootOffset, 10), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 12)); + + return object; + }), + LogMeal: EntityDefinition( + model: _entities[8], + toOneRelations: (LogMeal object) => [ + object.logEntry, + object.meal, + object.mealSource, + object.mealCategory, + object.mealPortionType, + object.portionSizeAccuracy, + object.carbsRatioAccuracy + ], + toManyRelations: (LogMeal object) => {}, + getId: (LogMeal object) => object.id, + setId: (LogMeal object, int id) { + object.id = id; + }, + objectToFB: (LogMeal object, fb.Builder fbb) { + final valueOffset = fbb.writeString(object.value); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(17); + 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.addInt64(6, object.delayedBolusDuration); + fbb.addFloat64(7, object.delayedBolusRate); + fbb.addOffset(8, notesOffset); + fbb.addInt64(9, object.logEntry.targetId); + fbb.addInt64(10, object.meal.targetId); + fbb.addInt64(11, object.mealSource.targetId); + fbb.addInt64(12, object.mealCategory.targetId); + fbb.addInt64(13, object.mealPortionType.targetId); + fbb.addInt64(14, object.portionSizeAccuracy.targetId); + fbb.addInt64(15, object.carbsRatioAccuracy.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 = LogMeal( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + value: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + carbsRatio: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 8), + portionSize: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 10), + carbsPerPortion: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 12), + bolus: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 14), + delayedBolusDuration: const fb.Int64Reader() + .vTableGetNullable(buffer, rootOffset, 16), + delayedBolusRate: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 18), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 20)); + object.logEntry.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 22, 0); + object.logEntry.attach(store); + object.meal.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 24, 0); + object.meal.attach(store); + object.mealSource.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 26, 0); + object.mealSource.attach(store); + object.mealCategory.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 28, 0); + object.mealCategory.attach(store); + object.mealPortionType.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 30, 0); + object.mealPortionType.attach(store); + object.portionSizeAccuracy.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 32, 0); + object.portionSizeAccuracy.attach(store); + object.carbsRatioAccuracy.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 34, 0); + object.carbsRatioAccuracy.attach(store); + return object; + }), + Meal: EntityDefinition( + model: _entities[9], + toOneRelations: (Meal object) => [ + object.mealSource, + object.mealCategory, + object.mealPortionType, + object.portionSizeAccuracy, + object.carbsRatioAccuracy + ], + toManyRelations: (Meal object) => {}, + getId: (Meal object) => object.id, + setId: (Meal object, int id) { + object.id = id; + }, + objectToFB: (Meal object, fb.Builder fbb) { + final valueOffset = fbb.writeString(object.value); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(14); + 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); + fbb.addInt64(10, object.mealPortionType.targetId); + fbb.addInt64(11, object.portionSizeAccuracy.targetId); + fbb.addInt64(12, object.carbsRatioAccuracy.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 = Meal( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + value: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + carbsRatio: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 8), + portionSize: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 10), + carbsPerPortion: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 12), + delayedBolusDuration: const fb.Int64Reader() + .vTableGetNullable(buffer, rootOffset, 14), + delayedBolusRate: const fb.Float64Reader() + .vTableGetNullable(buffer, rootOffset, 16), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 18)); + object.mealSource.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 20, 0); + object.mealSource.attach(store); + object.mealCategory.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 22, 0); + object.mealCategory.attach(store); + object.mealPortionType.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 24, 0); + object.mealPortionType.attach(store); + object.portionSizeAccuracy.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 26, 0); + object.portionSizeAccuracy.attach(store); + object.carbsRatioAccuracy.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 28, 0); + object.carbsRatioAccuracy.attach(store); + return object; + }), + MealCategory: EntityDefinition( + model: _entities[10], + toOneRelations: (MealCategory object) => [], + toManyRelations: (MealCategory object) => {}, + getId: (MealCategory object) => object.id, + setId: (MealCategory object, int id) { + object.id = id; + }, + objectToFB: (MealCategory object, fb.Builder fbb) { + final valueOffset = fbb.writeString(object.value); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(4); + fbb.addInt64(0, object.id); + fbb.addOffset(1, valueOffset); + fbb.addOffset(2, notesOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = MealCategory( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + value: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 8)); + + return object; + }), + MealPortionType: EntityDefinition( + model: _entities[11], + toOneRelations: (MealPortionType object) => [], + toManyRelations: (MealPortionType object) => {}, + getId: (MealPortionType object) => object.id, + setId: (MealPortionType object, int id) { + object.id = id; + }, + objectToFB: (MealPortionType object, fb.Builder fbb) { + final valueOffset = fbb.writeString(object.value); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(4); + fbb.addInt64(0, object.id); + fbb.addOffset(1, valueOffset); + fbb.addOffset(2, notesOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = MealPortionType( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + value: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 8)); + + return object; + }), + MealSource: EntityDefinition( + model: _entities[12], + toOneRelations: (MealSource object) => [ + object.defaultMealCategory, + object.defaultMealPortionType, + object.defaultCarbsRatioAccuracy, + object.defaultPortionSizeAccuracy + ], + toManyRelations: (MealSource object) => {}, + getId: (MealSource object) => object.id, + setId: (MealSource object, int id) { + object.id = id; + }, + objectToFB: (MealSource object, fb.Builder fbb) { + final valueOffset = fbb.writeString(object.value); + final notesOffset = + object.notes == null ? null : fbb.writeString(object.notes!); + fbb.startTable(8); + fbb.addInt64(0, object.id); + fbb.addOffset(1, valueOffset); + fbb.addOffset(2, notesOffset); + fbb.addInt64(3, object.defaultMealCategory.targetId); + fbb.addInt64(4, object.defaultMealPortionType.targetId); + fbb.addInt64(5, object.defaultCarbsRatioAccuracy.targetId); + fbb.addInt64(6, object.defaultPortionSizeAccuracy.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 = MealSource( + id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0), + value: + const fb.StringReader().vTableGet(buffer, rootOffset, 6, ''), + notes: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 8)); + object.defaultMealCategory.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 10, 0); + object.defaultMealCategory.attach(store); + object.defaultMealPortionType.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 12, 0); + object.defaultMealPortionType.attach(store); + object.defaultCarbsRatioAccuracy.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 14, 0); + object.defaultCarbsRatioAccuracy.attach(store); + object.defaultPortionSizeAccuracy.targetId = + const fb.Int64Reader().vTableGet(buffer, rootOffset, 16, 0); + object.defaultPortionSizeAccuracy.attach(store); + return object; + }) + }; + + return ModelDefinition(model, bindings); +} + +/// [Accuracy] entity fields to define ObjectBox queries. +class Accuracy_ { + /// see [Accuracy.id] + static final id = QueryIntegerProperty(_entities[0].properties[0]); + + /// see [Accuracy.value] + static final value = + QueryStringProperty(_entities[0].properties[1]); + + /// see [Accuracy.forCarbsRatio] + static final forCarbsRatio = + QueryBooleanProperty(_entities[0].properties[2]); + + /// see [Accuracy.forPortionSize] + static final forPortionSize = + QueryBooleanProperty(_entities[0].properties[3]); + + /// see [Accuracy.confidenceRating] + static final confidenceRating = + QueryIntegerProperty(_entities[0].properties[4]); + + /// see [Accuracy.notes] + static final notes = + QueryStringProperty(_entities[0].properties[5]); +} + +/// [Basal] entity fields to define ObjectBox queries. +class Basal_ { + /// see [Basal.id] + static final id = QueryIntegerProperty(_entities[1].properties[0]); + + /// see [Basal.startTime] + static final startTime = + QueryIntegerProperty(_entities[1].properties[1]); + + /// see [Basal.endTime] + static final endTime = + QueryIntegerProperty(_entities[1].properties[2]); + + /// see [Basal.units] + static final units = QueryDoubleProperty(_entities[1].properties[3]); + + /// see [Basal.basalProfile] + static final basalProfile = + QueryRelationToOne(_entities[1].properties[4]); +} + +/// [BasalProfile] entity fields to define ObjectBox queries. +class BasalProfile_ { + /// see [BasalProfile.id] + static final id = + QueryIntegerProperty(_entities[2].properties[0]); + + /// see [BasalProfile.name] + static final name = + QueryStringProperty(_entities[2].properties[1]); + + /// see [BasalProfile.active] + static final active = + QueryBooleanProperty(_entities[2].properties[2]); + + /// see [BasalProfile.notes] + static final notes = + QueryStringProperty(_entities[2].properties[3]); +} + +/// [Bolus] entity fields to define ObjectBox queries. +class Bolus_ { + /// see [Bolus.id] + static final id = QueryIntegerProperty(_entities[3].properties[0]); + + /// see [Bolus.startTime] + static final startTime = + QueryIntegerProperty(_entities[3].properties[1]); + + /// see [Bolus.endTime] + static final endTime = + QueryIntegerProperty(_entities[3].properties[2]); + + /// see [Bolus.units] + static final units = QueryDoubleProperty(_entities[3].properties[3]); + + /// see [Bolus.carbs] + static final carbs = QueryDoubleProperty(_entities[3].properties[4]); + + /// see [Bolus.mgPerDl] + static final mgPerDl = + QueryIntegerProperty(_entities[3].properties[5]); + + /// see [Bolus.mmolPerL] + static final mmolPerL = + QueryDoubleProperty(_entities[3].properties[6]); + + /// see [Bolus.bolusProfile] + static final bolusProfile = + QueryRelationToOne(_entities[3].properties[7]); +} + +/// [BolusProfile] entity fields to define ObjectBox queries. +class BolusProfile_ { + /// see [BolusProfile.id] + static final id = + QueryIntegerProperty(_entities[4].properties[0]); + + /// see [BolusProfile.name] + static final name = + QueryStringProperty(_entities[4].properties[1]); + + /// see [BolusProfile.active] + static final active = + QueryBooleanProperty(_entities[4].properties[2]); + + /// see [BolusProfile.notes] + static final notes = + QueryStringProperty(_entities[4].properties[3]); +} + +/// [LogEntry] entity fields to define ObjectBox queries. +class LogEntry_ { + /// see [LogEntry.id] + static final id = QueryIntegerProperty(_entities[5].properties[0]); + + /// see [LogEntry.time] + static final time = + QueryIntegerProperty(_entities[5].properties[1]); + + /// see [LogEntry.mgPerDl] + static final mgPerDl = + QueryIntegerProperty(_entities[5].properties[2]); + + /// see [LogEntry.mmolPerL] + static final mmolPerL = + QueryDoubleProperty(_entities[5].properties[3]); + + /// see [LogEntry.bolusGlucose] + static final bolusGlucose = + QueryDoubleProperty(_entities[5].properties[4]); + + /// see [LogEntry.delayedBolusDuration] + static final delayedBolusDuration = + QueryIntegerProperty(_entities[5].properties[5]); + + /// see [LogEntry.delayedBolusRate] + static final delayedBolusRate = + QueryDoubleProperty(_entities[5].properties[6]); + + /// see [LogEntry.notes] + static final notes = + QueryStringProperty(_entities[5].properties[7]); +} + +/// [LogEvent] entity fields to define ObjectBox queries. +class LogEvent_ { + /// see [LogEvent.id] + static final id = QueryIntegerProperty(_entities[6].properties[0]); + + /// see [LogEvent.time] + static final time = + QueryIntegerProperty(_entities[6].properties[1]); + + /// see [LogEvent.endTime] + static final endTime = + QueryIntegerProperty(_entities[6].properties[2]); + + /// see [LogEvent.hasEndTime] + static final hasEndTime = + QueryBooleanProperty(_entities[6].properties[3]); + + /// see [LogEvent.notes] + static final notes = + QueryStringProperty(_entities[6].properties[4]); + + /// see [LogEvent.logEntry] + static final logEntry = + QueryRelationToOne(_entities[6].properties[5]); + + /// see [LogEvent.endLogEntry] + static final endLogEntry = + QueryRelationToOne(_entities[6].properties[6]); + + /// see [LogEvent.eventType] + static final eventType = + QueryRelationToOne(_entities[6].properties[7]); +} + +/// [LogEventType] entity fields to define ObjectBox queries. +class LogEventType_ { + /// see [LogEventType.id] + static final id = + QueryIntegerProperty(_entities[7].properties[0]); + + /// see [LogEventType.value] + static final value = + QueryStringProperty(_entities[7].properties[1]); + + /// see [LogEventType.hasEndTime] + static final hasEndTime = + QueryBooleanProperty(_entities[7].properties[2]); + + /// see [LogEventType.defaultReminderDuration] + static final defaultReminderDuration = + QueryIntegerProperty(_entities[7].properties[3]); + + /// see [LogEventType.notes] + static final notes = + QueryStringProperty(_entities[7].properties[4]); +} + +/// [LogMeal] entity fields to define ObjectBox queries. +class LogMeal_ { + /// see [LogMeal.id] + static final id = QueryIntegerProperty(_entities[8].properties[0]); + + /// see [LogMeal.value] + static final value = QueryStringProperty(_entities[8].properties[1]); + + /// see [LogMeal.carbsRatio] + static final carbsRatio = + QueryDoubleProperty(_entities[8].properties[2]); + + /// see [LogMeal.portionSize] + static final portionSize = + QueryDoubleProperty(_entities[8].properties[3]); + + /// see [LogMeal.carbsPerPortion] + static final carbsPerPortion = + QueryDoubleProperty(_entities[8].properties[4]); + + /// see [LogMeal.bolus] + static final bolus = QueryDoubleProperty(_entities[8].properties[5]); + + /// see [LogMeal.delayedBolusDuration] + static final delayedBolusDuration = + QueryIntegerProperty(_entities[8].properties[6]); + + /// see [LogMeal.delayedBolusRate] + static final delayedBolusRate = + QueryDoubleProperty(_entities[8].properties[7]); + + /// see [LogMeal.notes] + static final notes = QueryStringProperty(_entities[8].properties[8]); + + /// see [LogMeal.logEntry] + static final logEntry = + QueryRelationToOne(_entities[8].properties[9]); + + /// see [LogMeal.meal] + static final meal = + QueryRelationToOne(_entities[8].properties[10]); + + /// see [LogMeal.mealSource] + static final mealSource = + QueryRelationToOne(_entities[8].properties[11]); + + /// see [LogMeal.mealCategory] + static final mealCategory = + QueryRelationToOne(_entities[8].properties[12]); + + /// see [LogMeal.mealPortionType] + static final mealPortionType = + QueryRelationToOne(_entities[8].properties[13]); + + /// see [LogMeal.portionSizeAccuracy] + static final portionSizeAccuracy = + QueryRelationToOne(_entities[8].properties[14]); + + /// see [LogMeal.carbsRatioAccuracy] + static final carbsRatioAccuracy = + QueryRelationToOne(_entities[8].properties[15]); +} + +/// [Meal] entity fields to define ObjectBox queries. +class Meal_ { + /// see [Meal.id] + static final id = QueryIntegerProperty(_entities[9].properties[0]); + + /// see [Meal.value] + static final value = QueryStringProperty(_entities[9].properties[1]); + + /// see [Meal.carbsRatio] + static final carbsRatio = + QueryDoubleProperty(_entities[9].properties[2]); + + /// see [Meal.portionSize] + static final portionSize = + QueryDoubleProperty(_entities[9].properties[3]); + + /// see [Meal.carbsPerPortion] + static final carbsPerPortion = + QueryDoubleProperty(_entities[9].properties[4]); + + /// see [Meal.delayedBolusDuration] + static final delayedBolusDuration = + QueryIntegerProperty(_entities[9].properties[5]); + + /// see [Meal.delayedBolusRate] + static final delayedBolusRate = + QueryDoubleProperty(_entities[9].properties[6]); + + /// see [Meal.notes] + static final notes = QueryStringProperty(_entities[9].properties[7]); + + /// see [Meal.mealSource] + static final mealSource = + QueryRelationToOne(_entities[9].properties[8]); + + /// see [Meal.mealCategory] + static final mealCategory = + QueryRelationToOne(_entities[9].properties[9]); + + /// see [Meal.mealPortionType] + static final mealPortionType = + QueryRelationToOne(_entities[9].properties[10]); + + /// see [Meal.portionSizeAccuracy] + static final portionSizeAccuracy = + QueryRelationToOne(_entities[9].properties[11]); + + /// see [Meal.carbsRatioAccuracy] + static final carbsRatioAccuracy = + QueryRelationToOne(_entities[9].properties[12]); +} + +/// [MealCategory] entity fields to define ObjectBox queries. +class MealCategory_ { + /// see [MealCategory.id] + static final id = + QueryIntegerProperty(_entities[10].properties[0]); + + /// see [MealCategory.value] + static final value = + QueryStringProperty(_entities[10].properties[1]); + + /// see [MealCategory.notes] + static final notes = + QueryStringProperty(_entities[10].properties[2]); +} + +/// [MealPortionType] entity fields to define ObjectBox queries. +class MealPortionType_ { + /// see [MealPortionType.id] + static final id = + QueryIntegerProperty(_entities[11].properties[0]); + + /// see [MealPortionType.value] + static final value = + QueryStringProperty(_entities[11].properties[1]); + + /// see [MealPortionType.notes] + static final notes = + QueryStringProperty(_entities[11].properties[2]); +} + +/// [MealSource] entity fields to define ObjectBox queries. +class MealSource_ { + /// see [MealSource.id] + static final id = + QueryIntegerProperty(_entities[12].properties[0]); + + /// see [MealSource.value] + static final value = + QueryStringProperty(_entities[12].properties[1]); + + /// see [MealSource.notes] + static final notes = + QueryStringProperty(_entities[12].properties[2]); + + /// see [MealSource.defaultMealCategory] + static final defaultMealCategory = + QueryRelationToOne(_entities[12].properties[3]); + + /// see [MealSource.defaultMealPortionType] + static final defaultMealPortionType = + QueryRelationToOne( + _entities[12].properties[4]); + + /// see [MealSource.defaultCarbsRatioAccuracy] + static final defaultCarbsRatioAccuracy = + QueryRelationToOne(_entities[12].properties[5]); + + /// see [MealSource.defaultPortionSizeAccuracy] + static final defaultPortionSizeAccuracy = + QueryRelationToOne(_entities[12].properties[6]); +} diff --git a/lib/screens/accuracy_detail.dart b/lib/screens/accuracy_detail.dart index ac2bfac..33cdb48 100644 --- a/lib/screens/accuracy_detail.dart +++ b/lib/screens/accuracy_detail.dart @@ -8,60 +8,64 @@ import 'package:diameter/models/accuracy.dart'; class AccuracyDetailScreen extends StatefulWidget { static const String routeName = '/accuracy'; - final Accuracy? accuracy; + final int id; - const AccuracyDetailScreen({Key? key, this.accuracy}) : super(key: key); + const AccuracyDetailScreen({Key? key, this.id = 0}) : super(key: key); @override _AccuracyDetailScreenState createState() => _AccuracyDetailScreenState(); } class _AccuracyDetailScreenState extends State { + Accuracy? _accuracy; + bool _isNew = true; + bool _isSaving = false; + final GlobalKey _accuracyForm = GlobalKey(); + final _valueController = TextEditingController(text: ''); final _confidenceRatingController = TextEditingController(text: ''); final _notesController = TextEditingController(text: ''); bool _forCarbsRatio = false; bool _forPortionSize = false; - bool _isSaving = false; - @override void initState() { super.initState(); - if (widget.accuracy != null) { - _valueController.text = widget.accuracy!.value; - _forCarbsRatio = widget.accuracy!.forCarbsRatio; - _forPortionSize = widget.accuracy!.forPortionSize; + reload(); + if (_accuracy != null) { + _valueController.text = _accuracy!.value; + _forCarbsRatio = _accuracy!.forCarbsRatio; + _forPortionSize = _accuracy!.forPortionSize; _confidenceRatingController.text = - (widget.accuracy!.confidenceRating ?? '').toString(); - _notesController.text = widget.accuracy!.notes ?? ''; + (_accuracy!.confidenceRating ?? '').toString(); + _notesController.text = _accuracy!.notes ?? ''; } } + void reload() { + if (widget.id != 0) { + setState(() { + _accuracy = Accuracy.get(widget.id); + }); + } + _isNew = _accuracy == null; + } + void handleSaveAction() async { setState(() { _isSaving = true; }); if (_accuracyForm.currentState!.validate()) { - bool isNew = widget.accuracy == null; - isNew - ? await Accuracy.save( - value: _valueController.text, - forCarbsRatio: _forCarbsRatio, - forPortionSize: _forPortionSize, - confidenceRating: int.tryParse(_confidenceRatingController.text), - notes: _notesController.text, - ) - : await Accuracy.update( - widget.accuracy!.objectId!, - value: _valueController.text, - forCarbsRatio: _forCarbsRatio, - forPortionSize: _forPortionSize, - confidenceRating: int.tryParse(_confidenceRatingController.text), - notes: _notesController.text, - ); - Navigator.pop(context, '${isNew ? 'New' : ''} Accuracy saved'); + Accuracy.box.put(Accuracy( + id: widget.id, + value: _valueController.text, + forCarbsRatio: _forCarbsRatio, + forPortionSize: _forPortionSize, + confidenceRating: int.tryParse(_confidenceRatingController.text), + notes: _notesController.text, + )); + Navigator.pop(context, '${_isNew ? 'New' : ''} Accuracy saved'); } setState(() { _isSaving = false; @@ -69,25 +73,23 @@ class _AccuracyDetailScreenState extends State { } void handleCancelAction() { - bool isNew = widget.accuracy == null; - if (showConfirmationDialogOnCancel && - (isNew && - (_forCarbsRatio || - _forPortionSize || - _valueController.text != '' || - int.tryParse(_confidenceRatingController.text) != null || - _notesController.text != '')) || - (!isNew && - (_forCarbsRatio != widget.accuracy!.forCarbsRatio || - _forPortionSize != widget.accuracy!.forPortionSize || - widget.accuracy!.value != _valueController.text || - int.tryParse(_confidenceRatingController.text) != - widget.accuracy!.confidenceRating || - (widget.accuracy!.notes ?? '') != _notesController.text))) { + (_isNew && + (_forCarbsRatio || + _forPortionSize || + _valueController.text != '' || + int.tryParse(_confidenceRatingController.text) != null || + _notesController.text != '')) || + (!_isNew && + (_forCarbsRatio != _accuracy!.forCarbsRatio || + _forPortionSize != _accuracy!.forPortionSize || + _accuracy!.value != _valueController.text || + int.tryParse(_confidenceRatingController.text) != + _accuracy!.confidenceRating || + (_accuracy!.notes ?? '') != _notesController.text))) { Dialogs.showCancelConfirmationDialog( context: context, - isNew: isNew, + isNew: _isNew, onSave: handleSaveAction, ); } else { @@ -97,10 +99,9 @@ class _AccuracyDetailScreenState extends State { @override Widget build(BuildContext context) { - bool isNew = widget.accuracy == null; return Scaffold( appBar: AppBar( - title: Text(isNew ? 'New Accuracy' : widget.accuracy!.value), + title: Text(_isNew ? 'New Accuracy' : _accuracy!.value), ), drawer: const Navigation(currentLocation: AccuracyDetailScreen.routeName), body: SingleChildScrollView( diff --git a/lib/screens/accuracy_list.dart b/lib/screens/accuracy_list.dart index b46917e..8e0c4da 100644 --- a/lib/screens/accuracy_list.dart +++ b/lib/screens/accuracy_list.dart @@ -1,5 +1,4 @@ import 'package:diameter/components/dialogs.dart'; -import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/config.dart'; import 'package:diameter/navigation.dart'; import 'package:diameter/screens/accuracy_detail.dart'; @@ -15,11 +14,17 @@ class AccuracyListScreen extends StatefulWidget { } class _AccuracyListScreenState extends State { - late Future?> _accuracies; + List _accuracies = Accuracy.getAll(); + + @override + void initState() { + super.initState(); + refresh(); + } void refresh({String? message}) { setState(() { - _accuracies = Accuracy.fetchAll(); + _accuracies = Accuracy.getAll(); }); setState(() { @@ -36,7 +41,8 @@ class _AccuracyListScreenState extends State { } void onDelete(Accuracy accuracy) { - accuracy.delete().then((_) => refresh(message: 'Accuracy deleted')); + Accuracy.remove(accuracy.id); + refresh(); } void handleDeleteAction(Accuracy accuracy) async { @@ -52,24 +58,14 @@ class _AccuracyListScreenState extends State { } void handleToggleForPortionSizeAction(Accuracy accuracy) async { - await Accuracy.update( - accuracy.objectId!, - forPortionSize: !accuracy.forPortionSize, - ); + accuracy.forPortionSize = !accuracy.forPortionSize; + Accuracy.put(accuracy); refresh(); } void handleToggleForCarbsRatioAction(Accuracy accuracy) async { - await Accuracy.update( - accuracy.objectId!, - forCarbsRatio: !accuracy.forCarbsRatio, - ); - refresh(); - } - - @override - void initState() { - super.initState(); + accuracy.forCarbsRatio = !accuracy.forCarbsRatio; + Accuracy.put(accuracy); refresh(); } @@ -87,96 +83,77 @@ class _AccuracyListScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( - child: FutureBuilder?>( - future: _accuracies, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Accuracies'), - ) - ], - ) - : ListView.builder( - padding: const EdgeInsets.only(top: 10.0), - itemCount: snapshot.data != null - ? snapshot.data!.length - : 0, - itemBuilder: (context, index) { - final accuracy = snapshot.data![index]; - return ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - AccuracyDetailScreen( - accuracy: accuracy), - ), - ).then( - (message) => refresh(message: message)); - }, - title: Text(accuracy.value), - leading: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.reorder), - onPressed: () { - // TODO: implement reordering - }, - ), - ], - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: Icon(Icons.square_foot, - color: accuracy.forPortionSize - ? Colors.blue - : Colors.grey.shade300), - onPressed: () => - handleToggleForPortionSizeAction( - accuracy)), - IconButton( - icon: Icon(Icons.pie_chart, - color: accuracy.forCarbsRatio - ? Colors.blue - : Colors.grey.shade300), - onPressed: () => - handleToggleForCarbsRatioAction( - accuracy), - ), - const SizedBox(width: 24), - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => - handleDeleteAction(accuracy), - ) - ], - ), - ); - })); - }), - ), + child: _accuracies.isNotEmpty ? ListView.builder( + padding: const EdgeInsets.only(top: 10.0), + itemCount: _accuracies.length, + itemBuilder: (context, index) { + final accuracy = _accuracies[index]; + return ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + AccuracyDetailScreen(id: accuracy.id), + ), + ).then((message) => refresh(message: message)); + }, + title: Text(accuracy.value), + leading: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon(Icons.reorder), + onPressed: () { + // TODO: implement reordering + }, + ), + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon( + Icons.square_foot, + color: accuracy.forPortionSize + ? Theme.of(context).toggleableActiveColor + : Theme.of(context).highlightColor, + ), + onPressed: () => handleToggleForPortionSizeAction(accuracy), + ), + IconButton( + icon: Icon( + Icons.pie_chart, + color: accuracy.forCarbsRatio + ? Theme.of(context).toggleableActiveColor + : Theme.of(context).highlightColor, + ), + onPressed: () => handleToggleForCarbsRatioAction(accuracy), + ), + const SizedBox(width: 24), + IconButton( + icon: const Icon(Icons.delete), + onPressed: () => handleDeleteAction(accuracy), + ) + ], + ), + ); + } + ) : const Center( + child: Text('You have not created any Accuracies yet!'), + ), + ), ], ), floatingActionButton: FloatingActionButton( onPressed: () { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const AccuracyDetailScreen(), - )).then((message) => refresh(message: message)); + context, + MaterialPageRoute( + builder: (context) => const AccuracyDetailScreen(), + ), + ).then((message) => refresh(message: message)); }, child: const Icon(Icons.add), ), diff --git a/lib/screens/basal/basal_detail.dart b/lib/screens/basal/basal_detail.dart index be9a931..80f8c9a 100644 --- a/lib/screens/basal/basal_detail.dart +++ b/lib/screens/basal/basal_detail.dart @@ -11,15 +11,15 @@ import 'package:diameter/models/basal_profile.dart'; class BasalDetailScreen extends StatefulWidget { static const String routeName = '/basal'; - final BasalProfile basalProfile; - final Basal? basal; + final int basalProfileId; + final int id; final TimeOfDay? suggestedStartTime; final TimeOfDay? suggestedEndTime; const BasalDetailScreen( {Key? key, - required this.basalProfile, - this.basal, + this.basalProfileId = 0, + this.id = 0, this.suggestedStartTime, this.suggestedEndTime}) : super(key: key); @@ -29,7 +29,12 @@ class BasalDetailScreen extends StatefulWidget { } class _BasalDetailScreenState extends State { + Basal? _basal; + bool _isNew = true; + bool _isSaving = false; + final GlobalKey _basalForm = GlobalKey(); + TimeOfDay _startTime = const TimeOfDay(hour: 0, minute: 0); TimeOfDay _endTime = const TimeOfDay(hour: 0, minute: 0); @@ -37,27 +42,37 @@ class _BasalDetailScreenState extends State { final _endTimeController = TextEditingController(text: ''); final _unitsController = TextEditingController(text: ''); - bool _isSaving = false; - @override void initState() { super.initState(); + reload(); + if (widget.suggestedStartTime != null) { _startTime = widget.suggestedStartTime!; } if (widget.suggestedEndTime != null) { _endTime = widget.suggestedEndTime!; } - if (widget.basal != null) { - _startTime = TimeOfDay.fromDateTime(widget.basal!.startTime); - _endTime = TimeOfDay.fromDateTime(widget.basal!.endTime); - _unitsController.text = widget.basal!.units.toString(); + if (_basal != null) { + _startTime = TimeOfDay.fromDateTime(_basal!.startTime); + _endTime = TimeOfDay.fromDateTime(_basal!.endTime); + _unitsController.text = _basal!.units.toString(); } + updateStartTime(); updateEndTime(); } + void reload() { + if (widget.id != 0) { + setState(() { + _basal = Basal.get(widget.id); + }); + } + _isNew = _basal == null; + } + void updateStartTime() { _startTimeController.text = DateTimeUtils.displayTimeOfDay(_startTime); } @@ -68,14 +83,13 @@ class _BasalDetailScreenState extends State { Future validateTimePeriod() async { String? error; - List basalRates = - await Basal.fetchAllForBasalProfile(widget.basalProfile); + List basalRates = Basal.getAllForProfile(widget.basalProfileId); + // TODO use a query for the following checks instead? // check for duplicates if (basalRates .where((other) => - (widget.basal == null || - widget.basal!.objectId != other.objectId) && + (widget.id != other.id) && _startTime.hour == other.startTime.hour && _startTime.minute == other.startTime.minute) .isNotEmpty) { @@ -84,8 +98,7 @@ class _BasalDetailScreenState extends State { if (basalRates .where((other) => - (widget.basal == null || - widget.basal!.objectId != other.objectId) && + (widget.id != other.id) && DateTimeUtils.convertTimeOfDayToDateTime(_startTime) .isBefore(other.startTime) && DateTimeUtils.convertTimeOfDayToDateTime(_endTime) @@ -122,23 +135,15 @@ class _BasalDetailScreenState extends State { if (_basalForm.currentState!.validate()) { await validateTimePeriod().then((value) async { if (value != 'CANCEL') { - bool isNew = widget.basal == null; - isNew - ? await Basal.save( - startTime: - DateTimeUtils.convertTimeOfDayToDateTime(_startTime), - endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime), - units: double.parse(_unitsController.text), - basalProfile: widget.basalProfile.objectId!, - ) - : await Basal.update( - widget.basal!.objectId!, - startTime: - DateTimeUtils.convertTimeOfDayToDateTime(_startTime), - endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime), - units: double.parse(_unitsController.text), - ); - Navigator.pop(context, '${isNew ? 'New' : ''} Basal Rate saved'); + Basal basal = Basal( + id: widget.id, + startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime), + endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime), + units: double.parse(_unitsController.text), + ); + basal.basalProfile.targetId = widget.basalProfileId; + Basal.put(basal); + Navigator.pop(context, '${_isNew ? 'New' : ''} Basal Rate saved'); } }); } @@ -148,24 +153,23 @@ class _BasalDetailScreenState extends State { } void handleCancelAction() { - bool isNew = widget.basal == null; if (showConfirmationDialogOnCancel && - ((isNew && + ((_isNew && (_startTime.hour != (widget.suggestedStartTime?.hour ?? 0) || _endTime.hour != (widget.suggestedEndTime?.hour ?? 0) || _startTime.minute != (widget.suggestedStartTime?.minute ?? 0) || _endTime.minute != (widget.suggestedEndTime?.minute ?? 0) || double.tryParse(_unitsController.text) != null)) || - (!isNew && - (TimeOfDay.fromDateTime(widget.basal!.startTime) != + (!_isNew && + (TimeOfDay.fromDateTime(_basal!.startTime) != _startTime || - TimeOfDay.fromDateTime(widget.basal!.endTime) != _endTime || + TimeOfDay.fromDateTime(_basal!.endTime) != _endTime || (double.tryParse(_unitsController.text) ?? 0) != - widget.basal!.units)))) { + _basal!.units)))) { Dialogs.showCancelConfirmationDialog( context: context, - isNew: isNew, + isNew: _isNew, onSave: handleSaveAction, ); } else { @@ -175,12 +179,10 @@ class _BasalDetailScreenState extends State { @override Widget build(BuildContext context) { - bool isNew = widget.basal == null; - return Scaffold( appBar: AppBar( title: Text( - '${isNew ? 'New' : 'Edit'} Basal Rate for ${widget.basalProfile.name}'), + '${_isNew ? 'New' : 'Edit'} Basal Rate for ${BasalProfile.get(widget.basalProfileId)?.name}'), ), drawer: const Navigation(currentLocation: BasalDetailScreen.routeName), body: Column( diff --git a/lib/screens/basal/basal_list.dart b/lib/screens/basal/basal_list.dart index 5d9a229..96a3c5c 100644 --- a/lib/screens/basal/basal_list.dart +++ b/lib/screens/basal/basal_list.dart @@ -2,28 +2,30 @@ import 'package:diameter/components/dialogs.dart'; import 'package:diameter/config.dart'; import 'package:diameter/utils/date_time_utils.dart'; import 'package:flutter/material.dart'; -import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/models/basal.dart'; import 'package:diameter/models/basal_profile.dart'; import 'package:diameter/screens/basal/basal_detail.dart'; class BasalListScreen extends StatefulWidget { - final BasalProfile? basalProfile; + final BasalProfile basalProfile; + final List basalRates; + final Function() reload; - const BasalListScreen({Key? key, this.basalProfile}) : super(key: key); + const BasalListScreen( + {Key? key, + required this.basalProfile, + this.basalRates = const [], + required this.reload}) + : super(key: key); @override _BasalListScreenState createState() => _BasalListScreenState(); } class _BasalListScreenState extends State { - void refresh({String? message}) { - setState(() { - if (widget.basalProfile != null) { - widget.basalProfile!.basalRates = - Basal.fetchAllForBasalProfile(widget.basalProfile!); - } - }); + void reload({String? message}) { + widget.reload(); + setState(() { if (message != null) { var snackBar = SnackBar( @@ -42,15 +44,16 @@ class _BasalListScreenState extends State { context, MaterialPageRoute( builder: (context) => BasalDetailScreen( - basalProfile: widget.basalProfile!, - basal: basal, + basalProfileId: widget.basalProfile.id, + id: basal.id, ), ), - ).then((message) => refresh(message: message)); + ).then((message) => reload(message: message)); } void onDelete(Basal basal) { - basal.delete().then((_) => refresh(message: 'Basal Rate deleted')); + Basal.remove(basal.id); + reload(message: 'Basal Rate deleted'); } void handleDeleteAction(Basal basal) async { @@ -65,9 +68,11 @@ class _BasalListScreenState extends State { } } - String? validateTimePeriod(List basalRates, int index) { + String? validateTimePeriod(int index) { + List basalRates = widget.basalRates; Basal basal = basalRates[index]; + // TODO: use queries for all this // check for gaps if (index == 0 && (basal.startTime.hour != 0 || basal.startTime.minute != 0)) { @@ -102,73 +107,52 @@ class _BasalListScreenState extends State { } } - @override - void initState() { - super.initState(); - refresh(); - } - @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column( children: [ - FutureBuilder>( - future: widget.basalProfile!.basalRates, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? const Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Basal Rates for this Profile'), - ) - : ListView.builder( - shrinkWrap: true, - itemCount: - snapshot.data != null ? snapshot.data!.length : 0, - itemBuilder: (context, index) { - final basal = snapshot.data![index]; - final error = - validateTimePeriod(snapshot.data!, index); - return ListTile( - tileColor: - error != null ? Colors.red.shade100 : null, - onTap: () { - handleEditAction(basal); - }, - title: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: Text( - '${DateTimeUtils.displayTime(basal.startTime)} - ${DateTimeUtils.displayTime(basal.endTime)}')), - const Spacer(), - Expanded(child: Text('${basal.units} U')), - ], - ), - subtitle: error != null - ? Text(error, - style: const TextStyle(color: Colors.red)) - : Container(), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => handleDeleteAction(basal), - ), - ], - ), - ); - }, + widget.basalRates.isNotEmpty ? ListView.builder( + shrinkWrap: true, + itemCount: widget.basalRates.length, + itemBuilder: (context, index) { + final basal = widget.basalRates[index]; + final error = validateTimePeriod(index); + return ListTile( + tileColor: error != null ? Colors.red.shade100 : null, + onTap: () { + handleEditAction(basal); + }, + title: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Text( + '${DateTimeUtils.displayTime(basal.startTime)} - ${DateTimeUtils.displayTime(basal.endTime)}')), + const Spacer(), + Expanded(child: Text('${basal.units} U')), + ], + ), + subtitle: error != null + ? Text(error, style: const TextStyle(color: Colors.red)) + : Container(), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, ), + onPressed: () => handleDeleteAction(basal), + ), + ], + ), ); }, - ), + ) : const Center( + child: Text('You have not created any Basal Rates yet!'), + ), ], ), ); diff --git a/lib/screens/basal/basal_profile_detail.dart b/lib/screens/basal/basal_profile_detail.dart index 08872a4..13af0bf 100644 --- a/lib/screens/basal/basal_profile_detail.dart +++ b/lib/screens/basal/basal_profile_detail.dart @@ -12,11 +12,10 @@ import 'package:diameter/screens/basal/basal_list.dart'; class BasalProfileDetailScreen extends StatefulWidget { static const String routeName = '/basal-profile'; - final BasalProfile? basalProfile; + final int id; final bool active; - const BasalProfileDetailScreen( - {Key? key, this.active = false, this.basalProfile}) + const BasalProfileDetailScreen({Key? key, this.active = false, this.id = 0}) : super(key: key); @override @@ -25,6 +24,11 @@ class BasalProfileDetailScreen extends StatefulWidget { } class _BasalProfileDetailScreenState extends State { + BasalProfile? _basalProfile; + List _basalRates = []; + bool _isNew = true; + bool _isSaving = false; + final GlobalKey _basalProfileForm = GlobalKey(); late FloatingActionButton addBasalButton; @@ -40,28 +44,30 @@ class _BasalProfileDetailScreenState extends State { final _notesController = TextEditingController(text: ''); bool _active = false; - bool _isSaving = false; - @override void initState() { super.initState(); - if (widget.basalProfile != null) { - _nameController.text = widget.basalProfile!.name; - _active = widget.basalProfile!.active; - _notesController.text = widget.basalProfile!.notes ?? ''; + + reload(); + + if (_basalProfile != null) { + _nameController.text = _basalProfile!.name; + _active = _basalProfile!.active; + _notesController.text = _basalProfile!.notes ?? ''; } + if (widget.active) { _active = true; } addBasalButton = FloatingActionButton( - onPressed: handleAddNew, + onPressed: handleAddNewBasal, child: const Icon(Icons.add), ); refreshButton = IconButton( icon: const Icon(Icons.refresh), - onPressed: refresh, + onPressed: reload, ); closeButton = IconButton( @@ -79,13 +85,15 @@ class _BasalProfileDetailScreenState extends State { bottomNav = detailBottomRow; } - void refresh({String? message}) { - setState(() { - if (widget.basalProfile != null) { - widget.basalProfile!.basalRates = - Basal.fetchAllForBasalProfile(widget.basalProfile!); - } - }); + void reload({String? message}) { + if (widget.id != 0) { + setState(() { + _basalProfile = BasalProfile.get(widget.id); + _basalRates = Basal.getAllForProfile(widget.id); + }); + _isNew = _basalProfile == null; + } + setState(() { if (message != null) { var snackBar = SnackBar( @@ -100,12 +108,11 @@ class _BasalProfileDetailScreenState extends State { } Future checkActiveProfiles() async { - int _activeCount = await BasalProfile.getActiveCount(); - bool isNew = widget.basalProfile == null; + int _activeCount = BasalProfile.activeCount(); if (_active && (_activeCount > 1 || - _activeCount == 1 && (isNew || !widget.basalProfile!.active))) { + _activeCount == 1 && (_isNew || !_basalProfile!.active))) { await showDialog( context: context, builder: (BuildContext context) { @@ -134,12 +141,12 @@ class _BasalProfileDetailScreenState extends State { _active = false; }); } else if (value == 2) { - await BasalProfile.setAllInactive(); + BasalProfile.setAllInactive(); } }); } else if (!_active && - ((isNew && _activeCount == 0) || - (_activeCount == 1 && widget.basalProfile!.active))) { + ((_isNew && _activeCount == 0) || + (_activeCount == 1 && _basalProfile!.active))) { await showDialog( context: context, builder: (BuildContext context) { @@ -167,24 +174,22 @@ class _BasalProfileDetailScreenState extends State { } } - void handleAddNew() async { - List basalRates = - await Basal.fetchAllForBasalProfile(widget.basalProfile!); + void handleAddNewBasal() async { TimeOfDay? suggestedStartTime; TimeOfDay? suggestedEndTime; - basalRates.asMap().forEach((index, basal) { + _basalRates.asMap().forEach((index, basal) { if (suggestedStartTime == null && suggestedEndTime == null) { if (index == 0 && (basal.startTime.hour != 0 || basal.startTime.minute != 0)) { suggestedStartTime = const TimeOfDay(hour: 0, minute: 0); suggestedEndTime = TimeOfDay.fromDateTime(basal.startTime); - } else if ((index == basalRates.length - 1) && + } else if ((index == _basalRates.length - 1) && (basal.endTime.hour != 0 || basal.endTime.minute != 0)) { suggestedStartTime = TimeOfDay.fromDateTime(basal.endTime); suggestedEndTime = const TimeOfDay(hour: 0, minute: 0); } else if (index != 0) { - var lastEndTime = basalRates[index - 1].endTime; + var lastEndTime = _basalRates[index - 1].endTime; if (basal.startTime.isAfter(lastEndTime)) { suggestedStartTime = TimeOfDay.fromDateTime(lastEndTime); suggestedEndTime = TimeOfDay.fromDateTime(basal.startTime); @@ -198,13 +203,13 @@ class _BasalProfileDetailScreenState extends State { MaterialPageRoute( builder: (context) { return BasalDetailScreen( - basalProfile: widget.basalProfile!, + basalProfileId: widget.id, suggestedStartTime: suggestedStartTime, suggestedEndTime: suggestedEndTime, ); }, ), - ).then((message) => refresh(message: message)); + ).then((message) => reload(message: message)); } void handleSaveAction() async { @@ -213,19 +218,13 @@ class _BasalProfileDetailScreenState extends State { }); if (_basalProfileForm.currentState!.validate()) { await checkActiveProfiles(); - bool isNew = widget.basalProfile == null; - isNew - ? await BasalProfile.save( - name: _nameController.text, - active: _active, - notes: _notesController.text) - : await BasalProfile.update( - widget.basalProfile!.objectId!, - name: _nameController.text, - active: _active, - notes: _notesController.text, - ); - Navigator.pop(context, '${isNew ? 'New' : ''} Basal Profile saved'); + BasalProfile.put(BasalProfile( + id: widget.id, + name: _nameController.text, + active: _active, + notes: _notesController.text, + )); + Navigator.pop(context, '${_isNew ? 'New' : ''} Basal Profile saved'); } setState(() { _isSaving = false; @@ -233,20 +232,18 @@ class _BasalProfileDetailScreenState extends State { } void handleCancelAction() { - bool isNew = widget.basalProfile == null; - if (showConfirmationDialogOnCancel && - (isNew && + (_isNew && (_active != widget.active || _nameController.text != '' || _notesController.text != '')) || - (!isNew && - (widget.basalProfile!.active != _active || - widget.basalProfile!.name != _nameController.text || - (widget.basalProfile!.notes ?? '') != _notesController.text))) { + (!_isNew && + (_basalProfile!.active != _active || + _basalProfile!.name != _nameController.text || + (_basalProfile!.notes ?? '') != _notesController.text))) { Dialogs.showCancelConfirmationDialog( context: context, - isNew: isNew, + isNew: _isNew, onSave: handleSaveAction, ); } else { @@ -255,7 +252,7 @@ class _BasalProfileDetailScreenState extends State { } void renderTabButtons(index) { - if (widget.basalProfile != null) { + if (_basalProfile != null) { setState(() { switch (index) { case 1: @@ -274,13 +271,12 @@ class _BasalProfileDetailScreenState extends State { @override Widget build(BuildContext context) { - bool isNew = widget.basalProfile == null; return DefaultTabController( - length: isNew ? 1 : 2, + length: _isNew ? 1 : 2, child: Builder(builder: (BuildContext context) { final TabController tabController = DefaultTabController.of(context)!; tabController.addListener(() { - renderTabButtons(tabController.index); + renderTabButtons(tabController.index); }); List tabs = [ SingleChildScrollView( @@ -327,15 +323,14 @@ class _BasalProfileDetailScreenState extends State { ), ]; - if (!isNew) { - tabs.add(BasalListScreen(basalProfile: widget.basalProfile)); + if (!_isNew) { + tabs.add(BasalListScreen(basalProfile: _basalProfile!, basalRates: _basalRates, reload: reload)); } return Scaffold( appBar: AppBar( - title: - Text(isNew ? 'New Basal Profile' : widget.basalProfile!.name), - bottom: isNew + title: Text(_isNew ? 'New Basal Profile' : _basalProfile!.name), + bottom: _isNew ? PreferredSize(child: Container(), preferredSize: Size.zero) : const TabBar( tabs: [ @@ -350,8 +345,7 @@ class _BasalProfileDetailScreenState extends State { body: TabBarView(children: tabs), bottomNavigationBar: bottomNav, floatingActionButton: actionButton, - floatingActionButtonLocation: - FloatingActionButtonLocation.endFloat, + floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, ); }), ); diff --git a/lib/screens/basal/basal_profiles_list.dart b/lib/screens/basal/basal_profiles_list.dart index b8463f7..c2be7a7 100644 --- a/lib/screens/basal/basal_profiles_list.dart +++ b/lib/screens/basal/basal_profiles_list.dart @@ -2,7 +2,7 @@ import 'package:diameter/components/dialogs.dart'; import 'package:diameter/config.dart'; import 'package:diameter/navigation.dart'; import 'package:flutter/material.dart'; -import 'package:diameter/components/progress_indicator.dart'; +// import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/models/basal_profile.dart'; import 'package:diameter/screens/basal/basal_profile_detail.dart'; @@ -15,18 +15,17 @@ class BasalProfileListScreen extends StatefulWidget { } class _BasalProfileListScreenState extends State { - late Future?> _basalProfiles; + late List _basalProfiles; Widget banner = Container(); bool pickActiveProfileMode = false; void refresh({String? message}) { setState(() { pickActiveProfileMode = false; - _basalProfiles = BasalProfile.fetchAll(); + _basalProfiles = BasalProfile.getAll(); }); - _basalProfiles.then((list) => updateBanner( - list?.where((element) => element.active).length ?? 0, - list?.isNotEmpty ?? false)); + // _basalProfiles.then((list) => + updateBanner(); setState(() { if (message != null) { var snackBar = SnackBar( @@ -40,7 +39,8 @@ class _BasalProfileListScreenState extends State { }); } - void updateBanner(int activeProfileCount, bool isNotEmpty) { + void updateBanner() { + int activeProfileCount = BasalProfile.activeCount(); setState(() { banner = activeProfileCount != 1 ? MaterialBanner( @@ -51,7 +51,7 @@ class _BasalProfileListScreenState extends State { forceActionsBelow: true, actions: activeProfileCount == 0 ? [ - isNotEmpty + _basalProfiles.isNotEmpty ? TextButton( child: const Text('ACTIVATE A PROFILE'), onPressed: handlePickActiveProfileAction, @@ -74,9 +74,8 @@ class _BasalProfileListScreenState extends State { } void onDelete(BasalProfile basalProfile) { - basalProfile - .delete() - .then((_) => refresh(message: 'Basal Profile deleted')); + BasalProfile.remove(basalProfile.id); + refresh(message: 'Basal Profile deleted'); } void handleDeleteAction(BasalProfile basalProfile) async { @@ -92,10 +91,11 @@ class _BasalProfileListScreenState extends State { } void onPickActive(BasalProfile basalProfile) { - BasalProfile.setAllInactive(exception: basalProfile.objectId!).then((_) => - refresh( - message: - '${basalProfile.name} has been set as your active Profile')); + BasalProfile.setAllInactive; + basalProfile.active = true; + BasalProfile.put(basalProfile); + // (exception: basalProfile.objectId!).then((_) => + refresh(message: '${basalProfile.name} has been set as your active Profile'); } void handlePickActiveProfileAction() { @@ -120,7 +120,7 @@ class _BasalProfileListScreenState extends State { context, MaterialPageRoute( builder: (context) => BasalProfileDetailScreen( - basalProfile: basalProfile, active: active), + id: basalProfile?.id ?? 0, active: active), ), ).then((message) => refresh(message: message)); } @@ -155,56 +155,41 @@ class _BasalProfileListScreenState extends State { children: [ banner, Expanded( - child: FutureBuilder?>( - future: _basalProfiles, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Basal Profiles'), - ), - ]) - : ListView.builder( - itemCount: - snapshot.data != null ? snapshot.data!.length : 0, - itemBuilder: (context, index) { - final basalProfile = snapshot.data![index]; - return ListTile( - tileColor: basalProfile.active - ? Colors.green.shade100 - : null, - onTap: () { - pickActiveProfileMode - ? onPickActive(basalProfile) - : onEdit(basalProfile); - }, - title: Text( - basalProfile.name, - ), - subtitle: Text(basalProfile.notes!), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => - handleDeleteAction(basalProfile), - ), - ], - ), - ); - }, + child: _basalProfiles.isNotEmpty ? ListView.builder( + itemCount: _basalProfiles.length, + itemBuilder: (context, index) { + final basalProfile = _basalProfiles[index]; + + return ListTile( + tileColor: basalProfile.active + ? Colors.green.shade100 + : null, + onTap: () { + pickActiveProfileMode + ? onPickActive(basalProfile) + : onEdit(basalProfile); + }, + title: Text( + basalProfile.name, + ), + subtitle: Text(basalProfile.notes!), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, ), + onPressed: () => + handleDeleteAction(basalProfile), + ), + ], + ), ); }, + ) : const Center( + child: Text('You have not created any Basal Profiles yet!'), ), ), ], diff --git a/lib/screens/bolus/bolus_detail.dart b/lib/screens/bolus/bolus_detail.dart index 678e715..917f7e7 100644 --- a/lib/screens/bolus/bolus_detail.dart +++ b/lib/screens/bolus/bolus_detail.dart @@ -13,15 +13,15 @@ import 'package:diameter/models/bolus_profile.dart'; class BolusDetailScreen extends StatefulWidget { static const String routeName = '/bolus'; - final BolusProfile bolusProfile; - final Bolus? bolus; + final int bolusProfileId; + final int id; final TimeOfDay? suggestedStartTime; final TimeOfDay? suggestedEndTime; const BolusDetailScreen( {Key? key, - required this.bolusProfile, - this.bolus, + this.bolusProfileId = 0, + this.id = 0, this.suggestedStartTime, this.suggestedEndTime}) : super(key: key); @@ -31,6 +31,10 @@ class BolusDetailScreen extends StatefulWidget { } class _BolusDetailScreenState extends State { + Bolus? _bolus; + bool _isNew = true; + bool _isSaving = false; + final GlobalKey _bolusForm = GlobalKey(); TimeOfDay _startTime = const TimeOfDay(hour: 0, minute: 0); @@ -43,30 +47,41 @@ class _BolusDetailScreenState extends State { final _mgPerDlController = TextEditingController(text: ''); final _mmolPerLController = TextEditingController(text: ''); - bool _isSaving = false; - @override void initState() { super.initState(); + reload(); + if (widget.suggestedStartTime != null) { _startTime = widget.suggestedStartTime!; } if (widget.suggestedEndTime != null) { _endTime = widget.suggestedEndTime!; } - if (widget.bolus != null) { - _startTime = TimeOfDay.fromDateTime(widget.bolus!.startTime); - _endTime = TimeOfDay.fromDateTime(widget.bolus!.endTime); - _unitsController.text = widget.bolus!.units.toString(); - _carbsController.text = widget.bolus!.carbs.toString(); - _mgPerDlController.text = widget.bolus!.mgPerDl.toString(); - _mmolPerLController.text = widget.bolus!.mmolPerL.toString(); + if (_bolus != null) { + _startTime = TimeOfDay.fromDateTime(_bolus!.startTime); + _endTime = TimeOfDay.fromDateTime(_bolus!.endTime); + + _unitsController.text = _bolus!.units.toString(); + _carbsController.text = _bolus!.carbs.toString(); + _mgPerDlController.text = _bolus!.mgPerDl.toString(); + _mmolPerLController.text = _bolus!.mmolPerL.toString(); } + updateStartTime(); updateEndTime(); } + void reload() { + if (widget.id != 0) { + setState(() { + _bolus = Bolus.get(widget.id); + }); + } + _isNew = _bolus == null; + } + void updateStartTime() { _startTimeController.text = DateTimeUtils.displayTimeOfDay(_startTime); } @@ -77,14 +92,14 @@ class _BolusDetailScreenState extends State { Future validateTimePeriod() async { String? error; - List bolusRates = - await Bolus.fetchAllForBolusProfile(widget.bolusProfile); + List bolusRates = Bolus.getAllForProfile(widget.bolusProfileId); + // BolusProfile.get(widget.bolusProfileId)?.bolusRates ?? []; + // TODO use a query for the following checks instead? // check for duplicates if (bolusRates .where((other) => - (widget.bolus == null || - widget.bolus!.objectId != other.objectId) && + widget.id != other.id && _startTime.hour == other.startTime.hour && _startTime.minute == other.startTime.minute) .isNotEmpty) { @@ -93,8 +108,7 @@ class _BolusDetailScreenState extends State { if (bolusRates .where((other) => - (widget.bolus == null || - widget.bolus!.objectId != other.objectId) && + (widget.id != other.id) && DateTimeUtils.convertTimeOfDayToDateTime(_startTime) .isBefore(other.startTime) && DateTimeUtils.convertTimeOfDayToDateTime(_endTime) @@ -128,44 +142,34 @@ class _BolusDetailScreenState extends State { setState(() { _isSaving = true; }); + if (_bolusForm.currentState!.validate()) { await validateTimePeriod().then((value) async { if (value != 'CANCEL') { - bool isNew = widget.bolus == null; - isNew - ? await Bolus.save( - startTime: - DateTimeUtils.convertTimeOfDayToDateTime(_startTime), - endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime), - units: double.parse(_unitsController.text), - bolusProfile: widget.bolusProfile.objectId!, - carbs: double.parse(_carbsController.text), - mgPerDl: int.tryParse(_mgPerDlController.text), - mmolPerL: double.tryParse(_mmolPerLController.text), - ) - : await Bolus.update( - widget.bolus!.objectId!, - startTime: - DateTimeUtils.convertTimeOfDayToDateTime(_startTime), - endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime), - units: double.tryParse(_unitsController.text), - carbs: double.tryParse(_carbsController.text), - mgPerDl: int.tryParse(_mgPerDlController.text), - mmolPerL: double.parse(_mmolPerLController.text), - ); - Navigator.pop(context, '${isNew ? 'New' : ''} Bolus Rate saved'); + Bolus bolus = Bolus( + id: widget.id, + startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime), + endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime), + units: double.tryParse(_unitsController.text) ?? 0, + carbs: double.tryParse(_carbsController.text) ?? 0, + mgPerDl: int.tryParse(_mgPerDlController.text), + mmolPerL: double.parse(_mmolPerLController.text), + ); + bolus.bolusProfile.targetId = widget.bolusProfileId; + Bolus.put(bolus); + Navigator.pop(context, '${_isNew ? 'New' : ''} Bolus Rate saved'); } }); } + setState(() { _isSaving = false; }); } void handleCancelAction() { - bool isNew = widget.bolus == null; if (showConfirmationDialogOnCancel && - ((isNew && + ((_isNew && (_startTime.hour != (widget.suggestedStartTime?.hour ?? 0) || _endTime.hour != (widget.suggestedEndTime?.hour ?? 0) || _startTime.minute != @@ -175,21 +179,20 @@ class _BolusDetailScreenState extends State { (double.tryParse(_carbsController.text) ?? 0) != 0.0 || (int.tryParse(_mgPerDlController.text) ?? 0) != 0 || (double.tryParse(_mmolPerLController.text) ?? 0) != 0.0)) || - (!isNew && - (TimeOfDay.fromDateTime(widget.bolus!.startTime) != - _startTime || - TimeOfDay.fromDateTime(widget.bolus!.endTime) != _endTime || + (!_isNew && + (TimeOfDay.fromDateTime(_bolus!.startTime) != _startTime || + TimeOfDay.fromDateTime(_bolus!.endTime) != _endTime || (double.tryParse(_unitsController.text) ?? 0) != - widget.bolus!.units || + _bolus!.units || (double.tryParse(_carbsController.text) ?? 0) != - widget.bolus!.carbs || + _bolus!.carbs || (double.tryParse(_mgPerDlController.text) ?? 0) != - widget.bolus!.mgPerDl || + _bolus!.mgPerDl || (double.tryParse(_mmolPerLController.text) ?? 0) != - widget.bolus!.mmolPerL)))) { + _bolus!.mmolPerL)))) { Dialogs.showCancelConfirmationDialog( context: context, - isNew: isNew, + isNew: _isNew, onSave: handleSaveAction, ); } else { @@ -226,12 +229,10 @@ class _BolusDetailScreenState extends State { @override Widget build(BuildContext context) { - bool isNew = widget.bolus == null; - return Scaffold( appBar: AppBar( title: Text( - '${isNew ? 'New' : 'Edit'} Bolus Rate for ${widget.bolusProfile.name}'), + '${_isNew ? 'New' : 'Edit'} Bolus Rate for ${BolusProfile.get(widget.bolusProfileId)?.name}'), ), drawer: const Navigation(currentLocation: BolusDetailScreen.routeName), body: SingleChildScrollView( diff --git a/lib/screens/bolus/bolus_list.dart b/lib/screens/bolus/bolus_list.dart index 8ce34d0..2c2576e 100644 --- a/lib/screens/bolus/bolus_list.dart +++ b/lib/screens/bolus/bolus_list.dart @@ -3,28 +3,27 @@ import 'package:diameter/config.dart'; import 'package:diameter/settings.dart'; import 'package:diameter/utils/date_time_utils.dart'; import 'package:flutter/material.dart'; -import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/models/bolus.dart'; import 'package:diameter/models/bolus_profile.dart'; import 'package:diameter/screens/bolus/bolus_detail.dart'; class BolusListScreen extends StatefulWidget { - final BolusProfile? bolusProfile; + final BolusProfile bolusProfile; + final List bolusRates; + final Function() reload; - const BolusListScreen({Key? key, this.bolusProfile}) : super(key: key); + const BolusListScreen( + {Key? key, required this.bolusProfile, this.bolusRates = const [], required this.reload}) + : super(key: key); @override _BolusListScreenState createState() => _BolusListScreenState(); } class _BolusListScreenState extends State { - void refresh({String? message}) { - setState(() { - if (widget.bolusProfile != null) { - widget.bolusProfile!.bolusRates = - Bolus.fetchAllForBolusProfile(widget.bolusProfile!); - } - }); + void reload({String? message}) { + widget.reload(); + setState(() { if (message != null) { var snackBar = SnackBar( @@ -43,15 +42,16 @@ class _BolusListScreenState extends State { context, MaterialPageRoute( builder: (context) => BolusDetailScreen( - bolusProfile: widget.bolusProfile!, - bolus: bolus, + bolusProfileId: widget.bolusProfile.id, + id: bolus.id, ), ), - ).then((message) => refresh(message: message)); + ).then((message) => reload(message: message)); } void onDelete(Bolus bolus) { - bolus.delete().then((_) => refresh(message: 'Bolus Rate deleted')); + Bolus.remove(bolus.id); + reload(message: 'Bolus Rate deleted'); } void handleDeleteAction(Bolus bolus) async { @@ -66,9 +66,11 @@ class _BolusListScreenState extends State { } } - String? validateTimePeriod(List bolusRates, int index) { + String? validateTimePeriod(int index) { + List bolusRates = widget.bolusRates; Bolus bolus = bolusRates[index]; + // TODO: use queries for all this // check for gaps if (index == 0 && (bolus.startTime.toLocal().hour != 0 || bolus.startTime.minute != 0)) { @@ -103,75 +105,54 @@ class _BolusListScreenState extends State { } } - @override - void initState() { - super.initState(); - refresh(); - } - @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.only(top: 10.0), child: Column( children: [ - FutureBuilder>( - future: widget.bolusProfile!.bolusRates, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? const Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Basal Rates for this Profile'), - ) - : ListView.builder( - shrinkWrap: true, - itemCount: - snapshot.data != null ? snapshot.data!.length : 0, - itemBuilder: (context, index) { - final bolus = snapshot.data![index]; - final error = - validateTimePeriod(snapshot.data!, index); - return ListTile( - isThreeLine: true, - tileColor: - error != null ? Colors.red.shade100 : null, - onTap: () { - handleEditAction(bolus); - }, - 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}${nutritionMeasurement == NutritionMeasurement.grams ? ' g' : ' oz'} carbs/${glucoseMeasurement == GlucoseMeasurement.mgPerDl ? bolus.mgPerDl : bolus.mmolPerL} ${glucoseMeasurement == GlucoseMeasurement.mgPerDl ? 'mg/dl' : 'mmol/l'}'), - error != null - ? Text(error, - style: const TextStyle( - color: Colors.red)) - : const Text('') - ]), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => handleDeleteAction(bolus), - ), - ], - ), - ); - }, + widget.bolusRates.isNotEmpty ? ListView.builder( + shrinkWrap: true, + itemCount: widget.bolusRates.length, + itemBuilder: (context, index) { + final bolus = widget.bolusRates[index]; + final error = validateTimePeriod(index); + return ListTile( + isThreeLine: true, + tileColor: error != null ? Colors.red.shade100 : null, + onTap: () { + handleEditAction(bolus); + }, + 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}${nutritionMeasurement == NutritionMeasurement.grams ? ' g' : ' oz'} carbs/${glucoseMeasurement == GlucoseMeasurement.mgPerDl ? bolus.mgPerDl : bolus.mmolPerL} ${glucoseMeasurement == GlucoseMeasurement.mgPerDl ? 'mg/dl' : 'mmol/l'}'), + error != null + ? Text(error, + style: const TextStyle(color: Colors.red)) + : const Text('') + ]), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, ), + onPressed: () => handleDeleteAction(bolus), + ), + ], + ), ); }, - ), + ) : const Center( + child: Text('You have not created any Bolus Rates yet!'), + ), ], ), ); diff --git a/lib/screens/bolus/bolus_profile_detail.dart b/lib/screens/bolus/bolus_profile_detail.dart index 1cc6fc0..4e87dd4 100644 --- a/lib/screens/bolus/bolus_profile_detail.dart +++ b/lib/screens/bolus/bolus_profile_detail.dart @@ -11,12 +11,10 @@ import 'package:diameter/screens/bolus/bolus_list.dart'; class BolusProfileDetailScreen extends StatefulWidget { static const String routeName = '/bolus-profile'; - - final BolusProfile? bolusProfile; + final int id; final bool active; - const BolusProfileDetailScreen( - {Key? key, this.active = false, this.bolusProfile}) + const BolusProfileDetailScreen({Key? key, this.active = false, this.id = 0}) : super(key: key); @override @@ -25,6 +23,11 @@ class BolusProfileDetailScreen extends StatefulWidget { } class _BolusProfileDetailScreenState extends State { + BolusProfile? _bolusProfile; + List _bolusRates = []; + bool _isNew = true; + bool _isSaving = false; + final GlobalKey _bolusProfileForm = GlobalKey(); late FloatingActionButton addBolusButton; @@ -40,28 +43,29 @@ class _BolusProfileDetailScreenState extends State { final _notesController = TextEditingController(text: ''); bool _active = false; - bool _isSaving = false; - @override void initState() { super.initState(); - if (widget.bolusProfile != null) { - _nameController.text = widget.bolusProfile!.name; - _active = widget.bolusProfile!.active; - _notesController.text = widget.bolusProfile!.notes ?? ''; + + reload(); + + if (_bolusProfile != null) { + _nameController.text = _bolusProfile!.name; + _active = _bolusProfile!.active; + _notesController.text = _bolusProfile!.notes ?? ''; } if (widget.active) { _active = true; } addBolusButton = FloatingActionButton( - onPressed: handleAddNew, + onPressed: handleAddNewBolus, child: const Icon(Icons.add), ); refreshButton = IconButton( icon: const Icon(Icons.refresh), - onPressed: refresh, + onPressed: reload, ); closeButton = IconButton( @@ -80,13 +84,15 @@ class _BolusProfileDetailScreenState extends State { bottomNav = detailBottomRow; } - void refresh({String? message}) { - setState(() { - if (widget.bolusProfile != null) { - widget.bolusProfile!.bolusRates = - Bolus.fetchAllForBolusProfile(widget.bolusProfile!); - } - }); + void reload({String? message}) { + if (widget.id != 0) { + setState(() { + _bolusProfile = BolusProfile.get(widget.id); + _bolusRates = Bolus.getAllForProfile(widget.id); + }); + _isNew = _bolusProfile == null; + } + setState(() { if (message != null) { var snackBar = SnackBar( @@ -101,12 +107,11 @@ class _BolusProfileDetailScreenState extends State { } Future checkActiveProfiles() async { - int _activeCount = await BolusProfile.getActiveCount(); - bool isNew = widget.bolusProfile == null; + int _activeCount = BolusProfile.activeCount(); if (_active && (_activeCount > 1 || - _activeCount == 1 && (isNew || !widget.bolusProfile!.active))) { + _activeCount == 1 && (_isNew || !_bolusProfile!.active))) { await showDialog( context: context, builder: (BuildContext context) { @@ -120,8 +125,7 @@ class _BolusProfileDetailScreenState extends State { ), TextButton( onPressed: () => Navigator.pop(context, 1), - child: - Text('DEACTIVATE ${_nameController.text.toUpperCase()}'), + child: const Text('DEACTIVATE THIS PROFILE'), ), ElevatedButton( onPressed: () => Navigator.pop(context, 2), @@ -135,12 +139,12 @@ class _BolusProfileDetailScreenState extends State { _active = false; }); } else if (value == 2) { - await BolusProfile.setAllInactive(); + BolusProfile.setAllInactive(); } }); } else if (!_active && - ((isNew && _activeCount == 0) || - (_activeCount == 1 && widget.bolusProfile!.active))) { + ((_isNew && _activeCount == 0) || + (_activeCount == 1 && _bolusProfile!.active))) { await showDialog( context: context, builder: (BuildContext context) { @@ -168,24 +172,22 @@ class _BolusProfileDetailScreenState extends State { } } - void handleAddNew() async { - List bolusRates = - await Bolus.fetchAllForBolusProfile(widget.bolusProfile!); + void handleAddNewBolus() async { TimeOfDay? suggestedStartTime; TimeOfDay? suggestedEndTime; - bolusRates.asMap().forEach((index, bolus) { + _bolusRates.asMap().forEach((index, bolus) { if (suggestedStartTime == null && suggestedEndTime == null) { if (index == 0 && (bolus.startTime.hour != 0 || bolus.startTime.minute != 0)) { suggestedStartTime = const TimeOfDay(hour: 0, minute: 0); suggestedEndTime = TimeOfDay.fromDateTime(bolus.startTime); - } else if ((index == bolusRates.length - 1) && + } else if ((index == _bolusRates.length - 1) && (bolus.endTime.hour != 0 || bolus.endTime.minute != 0)) { suggestedStartTime = TimeOfDay.fromDateTime(bolus.endTime); suggestedEndTime = const TimeOfDay(hour: 0, minute: 0); } else if (index != 0) { - var lastEndTime = bolusRates[index - 1].endTime; + var lastEndTime = _bolusRates[index - 1].endTime; if (bolus.startTime.isAfter(lastEndTime)) { suggestedStartTime = TimeOfDay.fromDateTime(lastEndTime); suggestedEndTime = TimeOfDay.fromDateTime(bolus.startTime); @@ -199,55 +201,51 @@ class _BolusProfileDetailScreenState extends State { MaterialPageRoute( builder: (context) { return BolusDetailScreen( - bolusProfile: widget.bolusProfile!, + bolusProfileId: widget.id, suggestedStartTime: suggestedStartTime, suggestedEndTime: suggestedEndTime, ); }, ), - ).then((message) => refresh(message: message)); + ).then((message) => reload(message: message)); } void handleSaveAction() async { setState(() { _isSaving = true; }); + if (_bolusProfileForm.currentState!.validate()) { await checkActiveProfiles(); - bool isNew = widget.bolusProfile == null; - isNew - ? await BolusProfile.save( - name: _nameController.text, - active: _active, - notes: _notesController.text) - : await BolusProfile.update( - widget.bolusProfile!.objectId!, - name: _nameController.text, - active: _active, - notes: _notesController.text, - ); - Navigator.pop(context, '${isNew ? 'New' : ''} Bolus Profile saved'); + BolusProfile.put( + BolusProfile( + id: widget.id, + name: _nameController.text, + active: _active, + notes: _notesController.text, + ), + ); + Navigator.pop(context, '${_isNew ? 'New' : ''} Bolus Profile saved'); } + setState(() { _isSaving = false; }); - } + } void handleCancelAction() { - bool isNew = widget.bolusProfile == null; - if (showConfirmationDialogOnCancel && - (isNew && + (_isNew && (_active != widget.active || _nameController.text != '' || _notesController.text != '')) || - (!isNew && - (widget.bolusProfile!.active != _active || - widget.bolusProfile!.name != _nameController.text || - (widget.bolusProfile!.notes ?? '') != _notesController.text))) { + (!_isNew && + (_bolusProfile!.active != _active || + _bolusProfile!.name != _nameController.text || + (_bolusProfile!.notes ?? '') != _notesController.text))) { Dialogs.showCancelConfirmationDialog( context: context, - isNew: isNew, + isNew: _isNew, onSave: handleSaveAction, ); } else { @@ -256,7 +254,7 @@ class _BolusProfileDetailScreenState extends State { } void renderTabButtons(index) { - if (widget.bolusProfile != null) { + if (_bolusProfile != null) { setState(() { switch (index) { case 1: @@ -275,13 +273,12 @@ class _BolusProfileDetailScreenState extends State { @override Widget build(BuildContext context) { - bool isNew = widget.bolusProfile == null; return DefaultTabController( - length: isNew ? 1 : 2, + length: _isNew ? 1 : 2, child: Builder(builder: (BuildContext context) { final TabController tabController = DefaultTabController.of(context)!; tabController.addListener(() { - renderTabButtons(tabController.index); + renderTabButtons(tabController.index); }); List tabs = [ @@ -328,15 +325,15 @@ class _BolusProfileDetailScreenState extends State { ), ]; - if (!isNew) { - tabs.add(BolusListScreen(bolusProfile: widget.bolusProfile)); + if (!_isNew) { + tabs.add( + BolusListScreen(bolusProfile: _bolusProfile!, bolusRates: _bolusRates, reload: reload)); } return Scaffold( appBar: AppBar( - title: - Text(isNew ? 'New Bolus Profile' : widget.bolusProfile!.name), - bottom: isNew + title: Text(_isNew ? 'New Bolus Profile' : _bolusProfile!.name), + bottom: _isNew ? PreferredSize(child: Container(), preferredSize: Size.zero) : const TabBar( tabs: [ @@ -353,8 +350,7 @@ class _BolusProfileDetailScreenState extends State { ), bottomNavigationBar: bottomNav, floatingActionButton: actionButton, - floatingActionButtonLocation: - FloatingActionButtonLocation.endFloat, + floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, ); }), ); diff --git a/lib/screens/bolus/bolus_profile_list.dart b/lib/screens/bolus/bolus_profile_list.dart index a295451..d6579a9 100644 --- a/lib/screens/bolus/bolus_profile_list.dart +++ b/lib/screens/bolus/bolus_profile_list.dart @@ -2,7 +2,6 @@ import 'package:diameter/components/dialogs.dart'; import 'package:diameter/config.dart'; import 'package:diameter/navigation.dart'; import 'package:flutter/material.dart'; -import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/models/bolus_profile.dart'; import 'package:diameter/screens/bolus/bolus_profile_detail.dart'; @@ -15,18 +14,18 @@ class BolusProfileListScreen extends StatefulWidget { } class _BolusProfileListScreenState extends State { - late Future?> _bolusProfiles; + List _bolusProfiles = []; Widget banner = Container(); bool pickActiveProfileMode = false; - void refresh({String? message}) { + void reload({String? message}) { setState(() { pickActiveProfileMode = false; - _bolusProfiles = BolusProfile.fetchAll(); + _bolusProfiles = BolusProfile.getAll(); }); - _bolusProfiles.then((list) => updateBanner( - list?.where((element) => element.active).length ?? 0, - list?.isNotEmpty ?? false)); + + updateBanner(); + setState(() { if (message != null) { var snackBar = SnackBar( @@ -40,7 +39,9 @@ class _BolusProfileListScreenState extends State { }); } - void updateBanner(int activeProfileCount, bool isNotEmpty) { + void updateBanner() { + int activeProfileCount = BolusProfile.activeCount(); + setState(() { banner = activeProfileCount != 1 ? MaterialBanner( @@ -51,7 +52,7 @@ class _BolusProfileListScreenState extends State { forceActionsBelow: true, actions: activeProfileCount == 0 ? [ - isNotEmpty + _bolusProfiles.isNotEmpty ? TextButton( child: const Text('ACTIVATE A PROFILE'), onPressed: handlePickActiveProfileAction, @@ -74,9 +75,8 @@ class _BolusProfileListScreenState extends State { } void onDelete(BolusProfile bolusProfile) { - bolusProfile - .delete() - .then((_) => refresh(message: 'Bolus Profile deleted')); + BolusProfile.remove(bolusProfile.id); + reload(message: 'Bolus Profile deleted'); } void handleDeleteAction(BolusProfile bolusProfile) async { @@ -92,10 +92,11 @@ class _BolusProfileListScreenState extends State { } void onPickActive(BolusProfile bolusProfile) { - BolusProfile.setAllInactive(exception: bolusProfile.objectId!).then((_) => - refresh( - message: - '${bolusProfile.name} has been set as your active Profile')); + BolusProfile.setAllInactive; + bolusProfile.active = true; + BolusProfile.put(bolusProfile); + reload( + message: '${bolusProfile.name} has been set as your active Profile'); } void handlePickActiveProfileAction() { @@ -120,9 +121,9 @@ class _BolusProfileListScreenState extends State { context, MaterialPageRoute( builder: (context) => BolusProfileDetailScreen( - bolusProfile: bolusProfile, active: active), + id: bolusProfile?.id ?? 0, active: active), ), - ).then((message) => refresh(message: message)); + ).then((message) => reload(message: message)); } void onNew(bool active) { @@ -136,7 +137,7 @@ class _BolusProfileListScreenState extends State { @override void initState() { super.initState(); - refresh(); + reload(); } @override @@ -145,7 +146,7 @@ class _BolusProfileListScreenState extends State { appBar: AppBar( title: const Text('Bolus Profiles'), actions: [ - IconButton(onPressed: refresh, icon: const Icon(Icons.refresh)) + IconButton(onPressed: reload, icon: const Icon(Icons.refresh)) ], ), drawer: @@ -155,56 +156,41 @@ class _BolusProfileListScreenState extends State { children: [ banner, Expanded( - child: FutureBuilder?>( - future: _bolusProfiles, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Bolus Profiles'), - ), - ]) - : ListView.builder( - itemCount: - snapshot.data != null ? snapshot.data!.length : 0, - itemBuilder: (context, index) { - final bolusProfile = snapshot.data![index]; - return ListTile( - tileColor: bolusProfile.active - ? Colors.green.shade100 - : null, - onTap: () { - pickActiveProfileMode - ? onPickActive(bolusProfile) - : onEdit(bolusProfile); - }, - title: Text( - bolusProfile.name, - ), - subtitle: Text(bolusProfile.notes!), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => - handleDeleteAction(bolusProfile), - ), - ], - ), - ); - }, + child: _bolusProfiles.isNotEmpty ? ListView.builder( + itemCount: _bolusProfiles.length, + itemBuilder: (context, index) { + final bolusProfile = _bolusProfiles[index]; + return ListTile( + tileColor: bolusProfile.active + ? Colors.green.shade100 + : null, + onTap: () { + // TODO: make pick active profile visually distinct + pickActiveProfileMode + ? onPickActive(bolusProfile) + : onEdit(bolusProfile); + }, + title: Text( + bolusProfile.name, + ), + subtitle: Text(bolusProfile.notes!), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, ), + onPressed: () => + handleDeleteAction(bolusProfile), + ), + ], + ), ); }, + ) : const Center( + child: Text('You have not created any Bolus Profiles yet!'), ), ), ], diff --git a/lib/screens/log/active_log_event_list.dart b/lib/screens/log/active_log_event_list.dart index f8d6f79..b16c82d 100644 --- a/lib/screens/log/active_log_event_list.dart +++ b/lib/screens/log/active_log_event_list.dart @@ -2,10 +2,11 @@ import 'package:diameter/components/dialogs.dart'; import 'package:diameter/config.dart'; import 'package:diameter/models/log_entry.dart'; import 'package:diameter/models/log_event.dart'; -import 'package:diameter/models/log_event_type.dart'; +// import 'package:diameter/models/log_event_type.dart'; import 'package:diameter/screens/log/log_event_detail.dart'; +import 'package:diameter/utils/date_time_utils.dart'; import 'package:flutter/material.dart'; -import 'package:diameter/components/progress_indicator.dart'; +// import 'package:diameter/components/progress_indicator.dart'; class ActiveLogEventListScreen extends StatefulWidget { static const String routeName = '/active-log-events'; @@ -23,16 +24,11 @@ class ActiveLogEventListScreen extends StatefulWidget { } class _ActiveLogEventListScreenState extends State { - late Future> _activeLogEvents; - late Future> _logEventTypes; + List _activeLogEvents = []; void refresh({String? message}) { setState(() { - _logEventTypes = LogEventType.fetchAll(); - }); - - setState(() { - _activeLogEvents = LogEvent.fetchAllForLogEntry(widget.endLogEntry!); + _activeLogEvents = LogEvent.getAllOngoing(); }); setState(() { @@ -49,12 +45,10 @@ class _ActiveLogEventListScreenState extends State { } void onStop(LogEvent event) async { - // TODO: create new entry if no existing entry is given - await LogEvent.update( - event.objectId!, - endTime: DateTime.now(), - endLogEntry: widget.endLogEntry!.objectId!, - ); + event.endTime = DateTime.now(); + event.endLogEntry.target = + widget.endLogEntry ?? LogEntry(time: DateTime.now()); + LogEvent.put(event); refresh(); if (widget.onSetEndTime != null) { widget.onSetEndTime!(); @@ -74,7 +68,8 @@ class _ActiveLogEventListScreenState extends State { } void onDelete(LogEvent event) { - event.delete().then((_) => refresh(message: 'Event deleted')); + LogEvent.remove(event.id); + refresh(message: 'Event deleted'); } void handleDeleteAction(LogEvent event) async { @@ -97,90 +92,75 @@ class _ActiveLogEventListScreenState extends State { @override Widget build(BuildContext context) { - bool isNew = widget.endLogEntry == null; - return isNew - ? Container() - : Container( - padding: const EdgeInsets.only(top: 10.0), - child: Column( - children: [ - // TODO: make action button instead of appbar - AppBar( - title: const Text('Active Events'), - primary: false, - automaticallyImplyLeading: false, - actions: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => LogEventDetailScreen( - logEntry: widget.endLogEntry!, - ), - ), - ).then((message) => refresh(message: message)); - }, + return SingleChildScrollView( + padding: const EdgeInsets.only(top: 10.0), + child: Column( + children: [ + // TODO: make action button instead of appbar + AppBar( + title: const Text('Active Events'), + primary: false, + automaticallyImplyLeading: false, + actions: [ + IconButton( + icon: const Icon(Icons.add), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LogEventDetailScreen( + logEntry: widget.endLogEntry!, + ), + ), + ).then((message) => refresh(message: message)); + }, + ), + IconButton(icon: const Icon(Icons.refresh), onPressed: refresh), + ], + ), + _activeLogEvents.isNotEmpty ? + ListView.builder( + shrinkWrap: true, + itemCount: _activeLogEvents.length, + itemBuilder: (context, index) { + final event = _activeLogEvents[index]; + return ListTile( + title: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Text(event.eventType.target?.value ?? ''), ), - IconButton( - icon: const Icon(Icons.refresh), onPressed: refresh), ], ), - FutureBuilder>( - future: _activeLogEvents, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Container() - : ListBody( - children: [ - // TODO: fix problems that this futurebuilder in futurebuilder creates - FutureBuilder>( - future: _logEventTypes, - builder: (context, types) { - // return DataTable( - // columnSpacing: 10.0, - // showCheckboxColumn: false, - // rows: snapshot.data != null - // ? snapshot.data!.map((event) { - // return DataRow( - // cells: event.asDataTableCells( - // [ - // IconButton( - // icon: const Icon( - // Icons.stop), - // iconSize: 16.0, - // onPressed: () => - // handleStopAction( - // event), - // ), - // IconButton( - // icon: const Icon( - // Icons.delete), - // iconSize: 16.0, - // onPressed: () => - // handleDeleteAction( - // event), - // ), - // ], - // types: types.data, - // ), - // ); - // }).toList() - // : [], - // columns: LogEvent.asDataTableColumns(), - // ); - return Container(); - }) - ], - ), - ); - }, + subtitle: Text( + '${DateTimeUtils.displayDateTime(event.time)}${event.hasEndTime ? ' - ${DateTimeUtils.displayDateTime(event.endTime)}' : ''}'), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, + ), + onPressed: () => handleStopAction(event), + ), + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, + ), + onPressed: () => handleDeleteAction(event), + ), + ], ), - ], + ); + }, + ) : const Center( + child: Text('There are no currently ongoing events!'), ), - ); + ], + ), + ); } } diff --git a/lib/screens/log/log.dart b/lib/screens/log/log.dart index 367c8e1..910477d 100644 --- a/lib/screens/log/log.dart +++ b/lib/screens/log/log.dart @@ -1,5 +1,4 @@ import 'package:diameter/components/dialogs.dart'; -import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/config.dart'; import 'package:diameter/models/log_entry.dart'; import 'package:diameter/navigation.dart'; @@ -16,11 +15,11 @@ class LogScreen extends StatefulWidget { } class _LogScreenState extends State { - late Future>?> _logEntryDailyMap; + late Map> _logEntryDailyMap; void refresh({String? message}) { setState(() { - _logEntryDailyMap = LogEntry.createDailyEntryMap(); + _logEntryDailyMap = LogEntry.getDailyEntryMap(); }); setState(() { if (message != null) { @@ -36,7 +35,8 @@ class _LogScreenState extends State { } void onDelete(LogEntry logEntry) { - logEntry.delete().then((_) => refresh(message: 'Log Entry deleted')); + LogEntry.remove(logEntry.id); + refresh(message: 'Log Entry deleted'); } void handleDeleteAction(LogEntry logEntry) async { @@ -60,97 +60,84 @@ class _LogScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Log Entries'), actions: [ - IconButton(onPressed: refresh, icon: const Icon(Icons.refresh)) - ]), + appBar: AppBar( + title: const Text('Log Entries'), + actions: [ + IconButton( + onPressed: refresh, + icon: const Icon(Icons.refresh) + ), + ], + ), drawer: const Navigation(currentLocation: LogScreen.routeName), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( - child: FutureBuilder>?>( - future: _logEntryDailyMap, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Log Entries'), - ), - ], - ) - : SingleChildScrollView( - child: ListView.builder( - shrinkWrap: true, - padding: const EdgeInsets.all(10.0), - itemCount: snapshot.data != null - ? snapshot.data!.length - : 0, - itemBuilder: (context, dateIndex) { - List dateList = - snapshot.data!.keys.toList(); - dateList.sort((a, b) => a.compareTo(b) * -1); - final date = dateList[dateIndex]; - final entryList = snapshot.data![date]; - return ListBody( - children: [ - Text(DateTimeUtils.displayDate(date)), - entryList != null && entryList.isNotEmpty - ? ListView.builder( - shrinkWrap: true, - itemCount: entryList.length, - itemBuilder: (context, index) { - final logEntry = entryList[index]; - return ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - LogEntryScreen( - entry: logEntry), - ), - ).then((message) => refresh( - message: message)); - }, - title: Text( - DateTimeUtils.displayTime( - logEntry.time)), - // TODO: add additional fields (event icons...) - // TODO: display glucose in colors according to target settings - subtitle: Text(logEntry - .mgPerDl != - null - ? '${logEntry.mgPerDl.toString()} mg/dl' - : ''), - trailing: Row( - mainAxisSize: - MainAxisSize.min, - children: [ - IconButton( - onPressed: () => - handleDeleteAction( - logEntry), - icon: const Icon( - Icons.delete, - color: Colors.blue), - ) - ], - ), - ); - }) - : Container(), - ], - ); + child: SingleChildScrollView( + child: _logEntryDailyMap.isNotEmpty ? ListView.builder( + shrinkWrap: true, + padding: const EdgeInsets.all(10.0), + itemCount: _logEntryDailyMap.length, + itemBuilder: (context, dateIndex) { + List dateList = _logEntryDailyMap.keys.toList(); + final date = dateList[dateIndex]; + final entryList = _logEntryDailyMap[date]; + return ListBody( + children: [ + Text(DateTimeUtils.displayDate(date)), + entryList != null && entryList.isNotEmpty + ? ListView.builder( + shrinkWrap: true, + itemCount: entryList.length, + itemBuilder: (context, index) { + final logEntry = entryList[index]; + return ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + LogEntryScreen( + id: logEntry.id), + ), + ).then((message) => refresh( + message: message)); }, - ), - ), + title: Text( + DateTimeUtils.displayTime( + logEntry.time)), + // TODO: add additional fields (event icons...) + // TODO: display glucose in colors according to target settings + subtitle: Text(logEntry + .mgPerDl != + null + ? '${logEntry.mgPerDl.toString()} mg/dl' + : ''), + trailing: Row( + mainAxisSize: + MainAxisSize.min, + children: [ + IconButton( + onPressed: () => + handleDeleteAction( + logEntry), + icon: const Icon( + Icons.delete, + color: Colors.blue), + ) + ], + ), + ); + } + ) : Container(), + ], ); - }), + }, + ) : const Center( + child: Text('You have not created any Log Entries yet!'), + ), + ), ), ], ), diff --git a/lib/screens/log/log_entry.dart b/lib/screens/log/log_entry.dart index f1fadf3..37ac86e 100644 --- a/lib/screens/log/log_entry.dart +++ b/lib/screens/log/log_entry.dart @@ -2,8 +2,6 @@ import 'package:diameter/components/detail.dart'; import 'package:diameter/components/dialogs.dart'; import 'package:diameter/config.dart'; import 'package:diameter/models/log_entry.dart'; -import 'package:diameter/models/log_event.dart'; -import 'package:diameter/models/log_meal.dart'; import 'package:diameter/navigation.dart'; import 'package:diameter/screens/log/log_entry_form.dart'; import 'package:diameter/screens/log/log_event_detail.dart'; @@ -14,14 +12,19 @@ import 'package:flutter/material.dart'; class LogEntryScreen extends StatefulWidget { static const String routeName = '/log-entry'; - final LogEntry? entry; - const LogEntryScreen({Key? key, this.entry}) : super(key: key); + final int id; + + const LogEntryScreen({Key? key, this.id = 0}) : super(key: key); @override _LogEntryScreenState createState() => _LogEntryScreenState(); } class _LogEntryScreenState extends State { + LogEntry? _logEntry; + bool _isNew = true; + bool _isSaving = false; + final GlobalKey logEntryForm = GlobalKey(); late FloatingActionButton addMealButton; @@ -34,8 +37,6 @@ class _LogEntryScreenState extends State { List appBarActions = []; DetailBottomRow? bottomNav; - bool _isSaving = false; - final formDataControllers = { 'time': TextEditingController(text: ''), 'mgPerDl': TextEditingController(text: ''), @@ -46,151 +47,42 @@ class _LogEntryScreenState extends State { 'notes': TextEditingController(text: ''), }; - void refreshLists({String? message}) { - if (widget.entry != null) { - setState(() { - widget.entry!.meals = LogMeal.fetchAllForLogEntry(widget.entry!); - widget.entry!.events = LogEvent.fetchAllForLogEntry(widget.entry!); - widget.entry!.endedEvents = - LogEvent.fetchAllEndedByEntry(widget.entry!); - }); - } - } - - void handleSaveAction() async { - setState(() { - _isSaving = true; - }); - if (logEntryForm.currentState!.validate()) { - bool isNew = widget.entry == null; - isNew - ? await LogEntry.save( - time: DateTime.parse(formDataControllers['time']!.text), - mgPerDl: int.tryParse(formDataControllers['mgPerDl']!.text), - mmolPerL: double.tryParse(formDataControllers['mmolPerL']!.text), - bolusGlucose: - double.tryParse(formDataControllers['bolusGlucose']!.text), - delayedBolusDuration: int.tryParse( - formDataControllers['delayedBolusDuration']!.text), - delayedBolusRatio: double.tryParse( - formDataControllers['delayedBolusRate']!.text), - notes: formDataControllers['notes']!.text, - ) - : await LogEntry.update( - widget.entry!.objectId!, - time: DateTime.parse(formDataControllers['time']!.text), - mgPerDl: int.tryParse(formDataControllers['mgPerDl']!.text), - mmolPerL: double.tryParse(formDataControllers['mmolPerL']!.text), - bolusGlucose: double.tryParse( - formDataControllers['delayedBolusRate']!.text), - delayedBolusDuration: int.tryParse( - formDataControllers['delayedBolusDuration']!.text), - delayedBolusRatio: double.tryParse( - formDataControllers['delayedBolusRate']!.text), - notes: formDataControllers['notes']!.text, - ); - Navigator.pushReplacementNamed(context, '/log', - arguments: '${isNew ? 'New' : ''} Log Entry Saved'); - } - setState(() { - _isSaving = false; - }); - } - - void handleCancelAction() { - bool isNew = widget.entry == null; - if (showConfirmationDialogOnCancel && - ((isNew && - (int.tryParse(formDataControllers['mgPerDl']?.text ?? '') != - null || - double.tryParse(formDataControllers['mmolPerL']?.text ?? '') != - null || - double.tryParse(formDataControllers['bolusGlucose']?.text ?? '') != - null || - int.tryParse(formDataControllers['delayedBolusDuration']?.text ?? '') != - null || - double.tryParse(formDataControllers['delayedBolusRate']?.text ?? '') != - null || - formDataControllers['notes']?.text != '')) || - (!isNew && - (int.tryParse(formDataControllers['mgPerDl']?.text ?? '') != - widget.entry!.mgPerDl || - double.tryParse(formDataControllers['mmolPerL']?.text ?? '') != - widget.entry!.mmolPerL || - double.tryParse(formDataControllers['bolusGlucose']?.text ?? '') != - widget.entry!.bolusGlucose || - int.tryParse( - formDataControllers['delayedBolusDuration']?.text ?? - '') != - widget.entry!.delayedBolusDuration || - double.tryParse(formDataControllers['delayedBolusRate']?.text ?? '') != - widget.entry!.delayedBolusRatio || - formDataControllers['notes']?.text != - (widget.entry!.notes ?? ''))))) { - Dialogs.showCancelConfirmationDialog( - context: context, - isNew: isNew, - onSave: handleSaveAction, - onDiscard: (context) => Navigator.pushReplacementNamed(context, '/log'), - ); - } else { - Navigator.pushReplacementNamed(context, '/log', - arguments: '${isNew ? 'New' : ''} Log Entry Saved'); - } - } - @override void initState() { super.initState(); - if (widget.entry != null) { - formDataControllers['time']!.text = widget.entry!.time.toString(); + reload(); + + if (_logEntry != null) { + formDataControllers['time']!.text = _logEntry!.time.toString(); formDataControllers['mgPerDl']!.text = - (widget.entry!.mgPerDl ?? '').toString(); + (_logEntry!.mgPerDl ?? '').toString(); formDataControllers['mmolPerL']!.text = - (widget.entry!.mmolPerL ?? '').toString(); + (_logEntry!.mmolPerL ?? '').toString(); formDataControllers['bolusGlucose']!.text = - (widget.entry!.bolusGlucose ?? '').toString(); + (_logEntry!.bolusGlucose ?? '').toString(); formDataControllers['delayedBolusRate']!.text = - (widget.entry!.delayedBolusRatio ?? '').toString(); + (_logEntry!.delayedBolusRate ?? '').toString(); formDataControllers['delayedBolusDuration']!.text = - (widget.entry!.delayedBolusDuration ?? '').toString(); - formDataControllers['notes']!.text = widget.entry!.notes ?? ''; + (_logEntry!.delayedBolusDuration ?? '').toString(); + formDataControllers['notes']!.text = _logEntry!.notes ?? ''; } else { formDataControllers['time']!.text = DateTime.now().toString(); } addMealButton = FloatingActionButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return LogMealDetailScreen(logEntry: widget.entry!); - }, - ), - ).then((message) => refreshLists(message: message)); - }, + onPressed: handleAddNewMeal, child: const Icon(Icons.add), ); addEventButton = FloatingActionButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return LogEventDetailScreen(logEntry: widget.entry!); - }, - ), - ).then((message) => refreshLists(message: message)); - }, + onPressed: handleAddNewEvent, child: const Icon(Icons.add), ); refreshButton = IconButton( icon: const Icon(Icons.refresh), - onPressed: refreshLists, + onPressed: reload, ); closeButton = IconButton( @@ -208,8 +100,118 @@ class _LogEntryScreenState extends State { bottomNav = detailBottomRow; } + void reload({String? message}) { + if (widget.id != 0) { + setState(() { + _logEntry = LogEntry.get(widget.id); + }); + _isNew = _logEntry == null; + } + + setState(() { + if (message != null) { + var snackBar = SnackBar( + content: Text(message), + duration: const Duration(seconds: 2), + ); + ScaffoldMessenger.of(context) + ..removeCurrentSnackBar() + ..showSnackBar(snackBar); + } + }); + } + + void handleAddNewMeal() async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return LogMealDetailScreen(logEntry: _logEntry!); + }, + ), + ).then((message) => reload(message: message)); + } + + void handleAddNewEvent() async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return LogEventDetailScreen(logEntry: _logEntry!); + }, + ), + ).then((message) => reload(message: message)); + } + + void handleSaveAction() async { + setState(() { + _isSaving = true; + }); + if (logEntryForm.currentState!.validate()) { + LogEntry.put(LogEntry( + id: widget.id, + time: DateTime.parse(formDataControllers['time']!.text), + mgPerDl: int.tryParse(formDataControllers['mgPerDl']!.text), + mmolPerL: double.tryParse(formDataControllers['mmolPerL']!.text), + bolusGlucose: + double.tryParse(formDataControllers['delayedBolusRate']!.text), + delayedBolusDuration: + int.tryParse(formDataControllers['delayedBolusDuration']!.text), + delayedBolusRate: + double.tryParse(formDataControllers['delayedBolusRate']!.text), + notes: formDataControllers['notes']!.text, + )); + Navigator.pushReplacementNamed(context, '/log', + arguments: '${_isNew ? 'New' : ''} Log Entry Saved'); + } + setState(() { + _isSaving = false; + }); + } + + void handleCancelAction() { + if (showConfirmationDialogOnCancel && + ((_isNew && + (int.tryParse(formDataControllers['mgPerDl']?.text ?? '') != + null || + double.tryParse(formDataControllers['mmolPerL']?.text ?? '') != + null || + double.tryParse(formDataControllers['bolusGlucose']?.text ?? '') != + null || + int.tryParse(formDataControllers['delayedBolusDuration']?.text ?? '') != + null || + double.tryParse(formDataControllers['delayedBolusRate']?.text ?? '') != + null || + formDataControllers['notes']?.text != '')) || + (!_isNew && + (int.tryParse(formDataControllers['mgPerDl']?.text ?? '') != + _logEntry!.mgPerDl || + double.tryParse(formDataControllers['mmolPerL']?.text ?? '') != + _logEntry!.mmolPerL || + double.tryParse(formDataControllers['bolusGlucose']?.text ?? '') != + _logEntry!.bolusGlucose || + int.tryParse( + formDataControllers['delayedBolusDuration']?.text ?? + '') != + _logEntry!.delayedBolusDuration || + double.tryParse(formDataControllers['delayedBolusRate']?.text ?? '') != + _logEntry!.delayedBolusRate || + formDataControllers['notes']?.text != + (_logEntry!.notes ?? ''))))) { + Dialogs.showCancelConfirmationDialog( + context: context, + isNew: _isNew, + onSave: handleSaveAction, + onDiscard: (context) => Navigator.pushReplacementNamed(context, '/log'), + ); + } else { + Navigator.pushReplacementNamed(context, '/log', + arguments: '${_isNew ? 'New' : ''} Log Entry Saved'); + } + } + void renderTabButtons(index) { - if (widget.entry != null) { + if (_logEntry != null) { setState(() { switch (index) { case 1: @@ -233,29 +235,27 @@ class _LogEntryScreenState extends State { @override Widget build(BuildContext context) { - bool isNew = widget.entry == null; - return DefaultTabController( - length: isNew ? 1 : 3, + length: _isNew ? 1 : 3, child: Builder(builder: (BuildContext context) { final TabController tabController = DefaultTabController.of(context)!; tabController.addListener(() { - renderTabButtons(tabController.index); + renderTabButtons(tabController.index); }); List tabs = [ LogEntryForm( formState: logEntryForm, controllers: formDataControllers), ]; - if (!isNew) { - tabs.add(LogMealListScreen(logEntry: widget.entry)); - tabs.add(LogEventListScreen(logEntry: widget.entry)); + if (!_isNew) { + tabs.add(LogMealListScreen(logEntry: _logEntry!, reload: reload)); + tabs.add(LogEventListScreen(logEntry: _logEntry!, reload: reload)); } return Scaffold( appBar: AppBar( - title: Text(isNew ? 'New Log Entry' : 'Edit Log Entry'), - bottom: isNew + title: Text(_isNew ? 'New Log Entry' : 'Edit Log Entry'), + bottom: _isNew ? PreferredSize(child: Container(), preferredSize: Size.zero) : const TabBar( tabs: [ @@ -273,7 +273,7 @@ class _LogEntryScreenState extends State { bottomNavigationBar: bottomNav, floatingActionButton: actionButton, floatingActionButtonLocation: - FloatingActionButtonLocation.centerDocked, + FloatingActionButtonLocation.endFloat, ); }), ); diff --git a/lib/screens/log/log_entry_form.dart b/lib/screens/log/log_entry_form.dart index 86120c5..c969c2b 100644 --- a/lib/screens/log/log_entry_form.dart +++ b/lib/screens/log/log_entry_form.dart @@ -48,7 +48,7 @@ class _LogEntryFormState extends State { @override Widget build(BuildContext context) { - final _timeController = widget.controllers['time']; + // final _timeController = widget.controllers['time']; final _mgPerDlController = widget.controllers['mgPerDl']; final _mmolPerLController = widget.controllers['mmolPerL']; final _bolusGlucoseController = widget.controllers['bolusGlucose']; diff --git a/lib/screens/log/log_event_detail.dart b/lib/screens/log/log_event_detail.dart index 632d8a6..61145d9 100644 --- a/lib/screens/log/log_event_detail.dart +++ b/lib/screens/log/log_event_detail.dart @@ -25,10 +25,10 @@ class _LogEventDetailScreenState extends State { final GlobalKey _logEventForm = GlobalKey(); final _notesController = TextEditingController(text: ''); - String? _eventType; + LogEventType? _eventType; bool _hasEndTime = false; - late Future> _logEventTypes; + List _logEventTypes = []; bool _isSaving = false; @@ -38,11 +38,11 @@ class _LogEventDetailScreenState extends State { if (widget.logEvent != null) { _notesController.text = widget.logEvent!.notes ?? ''; - _eventType = widget.logEvent!.eventType; + _eventType = widget.logEvent!.eventType.target; _hasEndTime = widget.logEvent!.hasEndTime; } - _logEventTypes = LogEventType.fetchAll(); + _logEventTypes = LogEventType.getAll(); } void handleSaveAction() async { @@ -51,21 +51,29 @@ class _LogEventDetailScreenState extends State { }); if (_logEventForm.currentState!.validate()) { bool isNew = widget.logEvent == null; - isNew - ? await LogEvent.save( - logEntry: widget.logEntry!.objectId!, - eventType: _eventType!, - time: widget.logEntry!.time, - hasEndTime: _hasEndTime, - notes: _notesController.text, - ) - : await LogEvent.update( - widget.logEvent!.objectId!, - eventType: _eventType!, - time: widget.logEntry!.time, - hasEndTime: _hasEndTime, - notes: _notesController.text, - ); + // isNew + // ? await LogEvent.save( + // logEntry: widget.logEntry!.objectId!, + // eventType: _eventType!, + // time: widget.logEntry!.time, + // hasEndTime: _hasEndTime, + // notes: _notesController.text, + // ) + // : await LogEvent.update( + // widget.logEvent!.objectId!, + // eventType: _eventType!, + // time: widget.logEntry!.time, + // hasEndTime: _hasEndTime, + // notes: _notesController.text, + // ); + LogEvent event = LogEvent( + id: widget.logEvent?.id ?? 0, + time: widget.logEntry!.time, + hasEndTime: _hasEndTime, + notes: _notesController.text, + ); + event.eventType.target = _eventType; + LogEvent.put(event); Navigator.pop(context, '${isNew ? 'New' : ''} Event Saved'); } setState(() { @@ -82,7 +90,7 @@ class _LogEventDetailScreenState extends State { _hasEndTime)) || (!isNew && (_notesController.text != (widget.logEvent!.notes ?? '') || - _eventType != widget.logEvent!.eventType || + _eventType != widget.logEvent!.eventType.target || _hasEndTime != widget.logEvent!.hasEndTime)))) { Dialogs.showCancelConfirmationDialog( context: context, @@ -109,11 +117,10 @@ class _LogEventDetailScreenState extends State { StyledForm( formState: _logEventForm, fields: [ - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _eventType, label: 'Event Type', items: _logEventTypes, - getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { @@ -121,6 +128,18 @@ class _LogEventDetailScreenState extends State { }); }, ), + // StyledFutureDropdownButton( + // selectedItem: _eventType, + // label: 'Event Type', + // items: _logEventTypes, + // getItemValue: (item) => item.objectId, + // renderItem: (item) => Text(item.value), + // onChanged: (value) { + // setState(() { + // _eventType = value; + // }); + // }, + // ), StyledBooleanFormField( value: _hasEndTime, onChanged: (value) { diff --git a/lib/screens/log/log_event_list.dart b/lib/screens/log/log_event_list.dart index 9c06ecd..bd9503d 100644 --- a/lib/screens/log/log_event_list.dart +++ b/lib/screens/log/log_event_list.dart @@ -2,35 +2,25 @@ import 'package:diameter/components/dialogs.dart'; import 'package:diameter/config.dart'; import 'package:diameter/models/log_entry.dart'; import 'package:diameter/models/log_event.dart'; -import 'package:diameter/models/log_event_type.dart'; -import 'package:diameter/screens/log/active_log_event_list.dart'; import 'package:diameter/screens/log/log_event_detail.dart'; import 'package:diameter/utils/date_time_utils.dart'; -import 'package:flex_color_scheme/flex_color_scheme.dart'; import 'package:flutter/material.dart'; -import 'package:diameter/components/progress_indicator.dart'; class LogEventListScreen extends StatefulWidget { - final LogEntry? logEntry; + final LogEntry logEntry; + final Function() reload; - const LogEventListScreen({Key? key, this.logEntry}) : super(key: key); + const LogEventListScreen({Key? key, required this.logEntry, required this.reload}) + : super(key: key); @override _LogEventListScreenState createState() => _LogEventListScreenState(); } class _LogEventListScreenState extends State { - late Future> _logEventTypes; + void reload({String? message}) { + widget.reload(); - void refresh({String? message}) { - if (widget.logEntry != null) { - setState(() { - widget.logEntry!.events = - LogEvent.fetchAllForLogEntry(widget.logEntry!); - widget.logEntry!.endedEvents = - LogEvent.fetchAllEndedByEntry(widget.logEntry!); - }); - } setState(() { if (message != null) { var snackBar = SnackBar( @@ -42,7 +32,6 @@ class _LogEventListScreenState extends State { ..showSnackBar(snackBar); } }); - _logEventTypes = LogEventType.fetchAll(); } void handleEditAction(LogEvent event) { @@ -50,15 +39,16 @@ class _LogEventListScreenState extends State { context, MaterialPageRoute( builder: (context) => LogEventDetailScreen( - endLogEntry: widget.logEntry!, + endLogEntry: widget.logEntry, logEvent: event, ), ), - ).then((message) => refresh(message: message)); + ).then((message) => reload(message: message)); } void onDelete(LogEvent logEvent) { - logEvent.delete().then((_) => refresh(message: 'Event deleted')); + LogEvent.remove(logEvent.id); + reload(message: 'Event deleted'); } void handleDeleteAction(LogEvent logEvent) async { @@ -73,135 +63,51 @@ class _LogEventListScreenState extends State { } } - @override - void initState() { - super.initState(); - refresh(); - } - @override Widget build(BuildContext context) { - return SingleChildScrollView( - padding: const EdgeInsets.only(top: 10.0), - child: Column( + return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ // TODO: add button for active events - FutureBuilder>( - future: widget.logEntry!.events, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? const Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Events for this Log Entry'), - ) - : FutureBuilder>( - future: _logEventTypes, - builder: (context, types) { - return ListView.builder( - shrinkWrap: true, - itemCount: snapshot.data != null - ? snapshot.data!.length - : 0, - itemBuilder: (context, index) { - final event = snapshot.data![index]; - return ListTile( - onTap: () { - handleEditAction(event); - }, - title: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: Text(types.data - ?.firstWhere((element) => - element.objectId == - event.eventType) - .value ?? - '')), - ], - ), - subtitle: Text( - '${DateTimeUtils.displayDateTime(event.time)}${event.hasEndTime ? ' - ${DateTimeUtils.displayDateTime(event.endTime, fallback: '(ongoing)')}' : ''}'), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => - handleDeleteAction(event), - ), - ], - ), - ); - }, - ); - }), - ); - }, - ), - FutureBuilder>( - future: widget.logEntry!.endedEvents, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Container() - : FutureBuilder>( - future: _logEventTypes, - builder: (context, types) { - return ListView.builder( - shrinkWrap: true, - itemCount: snapshot.data != null - ? snapshot.data!.length - : 0, - itemBuilder: (context, index) { - final event = snapshot.data![index]; - return ListTile( - onTap: () { - handleEditAction(event); - }, - title: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: Text(types.data - ?.firstWhere((element) => - element.objectId == - event.eventType) - .value ?? - '')), - ], - ), - subtitle: Text( - '${DateTimeUtils.displayDateTime(event.time)}${event.hasEndTime ? ' - ${DateTimeUtils.displayDateTime(event.endTime)}' : ''}'), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => - handleDeleteAction(event), - ), - ], - ), - ); - }, - ); - }), - ); - }, + Expanded( + child: (widget.logEntry.events.isNotEmpty || widget.logEntry.endedEvents.isNotEmpty) + ? ListView.builder( + shrinkWrap: true, + itemCount: widget.logEntry.events.length + widget.logEntry.endedEvents.length, + itemBuilder: (context, index) { + final event = (widget.logEntry.events + widget.logEntry.endedEvents)[index]; + return ListTile( + onTap: () { + handleEditAction(event); + }, + title: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Text(event.eventType.target?.value ?? '')), + ], + ), + subtitle: Text( + '${DateTimeUtils.displayDateTime(event.time)}${event.hasEndTime ? ' - ${DateTimeUtils.displayDateTime(event.endTime, fallback: '(ongoing)')}' : ''}'), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, + ), + onPressed: () => handleDeleteAction(event), + ), + ], + ), + ); + }) + : const Center( + child: Text('You have not added any Events to this Log Entry yet!'), + ), ), ], - ), ); } } diff --git a/lib/screens/log/log_event_type_detail.dart b/lib/screens/log/log_event_type_detail.dart index 367eed3..9bfa4db 100644 --- a/lib/screens/log/log_event_type_detail.dart +++ b/lib/screens/log/log_event_type_detail.dart @@ -45,22 +45,30 @@ class _LogEventTypeDetailScreenState extends State { }); if (_logEventTypeForm.currentState!.validate()) { bool isNew = widget.logEventType == null; - isNew - ? await LogEventType.save( - value: _valueController.text, - notes: _notesController.text, - defaultReminderDuration: - int.tryParse(_defaultReminderDurationController.text), - hasEndTime: _hasEndTime, - ) - : await LogEventType.update( - widget.logEventType!.objectId!, - value: _valueController.text, - notes: _notesController.text, - defaultReminderDuration: - int.tryParse(_defaultReminderDurationController.text), - hasEndTime: _hasEndTime, - ); + // isNew + // ? await LogEventType.save( + // value: _valueController.text, + // notes: _notesController.text, + // defaultReminderDuration: + // int.tryParse(_defaultReminderDurationController.text), + // hasEndTime: _hasEndTime, + // ) + // : await LogEventType.update( + // widget.logEventType!.objectId!, + // value: _valueController.text, + // notes: _notesController.text, + // defaultReminderDuration: + // int.tryParse(_defaultReminderDurationController.text), + // hasEndTime: _hasEndTime, + // ); + LogEventType.put(LogEventType( + id: widget.logEventType?.id ?? 0, + value: _valueController.text, + notes: _notesController.text, + defaultReminderDuration: + int.tryParse(_defaultReminderDurationController.text), + hasEndTime: _hasEndTime, + )); Navigator.pop(context, '${isNew ? 'New' : ''} Log Event Type Saved'); } setState(() { diff --git a/lib/screens/log/log_event_type_list.dart b/lib/screens/log/log_event_type_list.dart index 55ba33a..e6c7cfb 100644 --- a/lib/screens/log/log_event_type_list.dart +++ b/lib/screens/log/log_event_type_list.dart @@ -1,4 +1,4 @@ -import 'package:diameter/components/progress_indicator.dart'; +// import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/models/log_event_type.dart'; import 'package:diameter/navigation.dart'; import 'package:diameter/screens/log/log_event_type_detail.dart'; @@ -13,11 +13,11 @@ class LogEventTypeListScreen extends StatefulWidget { } class _LogEventTypeListScreenState extends State { - late Future?> _logEventTypes; + List _logEventTypes = []; void refresh({String? message}) { setState(() { - _logEventTypes = LogEventType.fetchAll(); + _logEventTypes = LogEventType.getAll(); }); setState(() { if (message != null) { @@ -50,60 +50,45 @@ class _LogEventTypeListScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( - child: FutureBuilder?>( - future: _logEventTypes, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Log Event Types'), - ), - ], - ) - : ListView.builder( - padding: const EdgeInsets.all(10.0), - itemCount: - snapshot.data != null ? snapshot.data!.length : 0, - itemBuilder: (context, index) { - final logEventType = snapshot.data![index]; - return ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - LogEventTypeDetailScreen( - logEventType: logEventType), - ), - ).then((message) => refresh(message: message)); - }, - title: Text(logEventType.value), - subtitle: Text(logEventType.notes ?? ''), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - onPressed: () async { - await logEventType.delete().then((_) { - refresh( - message: 'Log Event Type deleted'); - }); - }, - icon: const Icon(Icons.delete, - color: Colors.blue), - ) - ], - ), - ); - }, - ), + child: _logEventTypes.isNotEmpty ? ListView.builder( + padding: const EdgeInsets.all(10.0), + itemCount: _logEventTypes.length, + itemBuilder: (context, index) { + // final logEventType = snapshot.data![index]; + final logEventType = _logEventTypes[index]; + return ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + LogEventTypeDetailScreen( + logEventType: logEventType), + ), + ).then((message) => refresh(message: message)); + }, + title: Text(logEventType.value), + subtitle: Text(logEventType.notes ?? ''), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + onPressed: () async { + LogEventType.remove(logEventType.id); + // await logEventType.delete().then((_) { + refresh( + message: 'Log Event Type deleted'); + // }); + }, + icon: const Icon(Icons.delete, + color: Colors.blue), + ) + ], + ), ); }, + ) : const Center( + child: Text('You have not created any Log Event Types yet!'), ), ), ], diff --git a/lib/screens/log/log_meal_detail.dart b/lib/screens/log/log_meal_detail.dart index b0da88f..540e302 100644 --- a/lib/screens/log/log_meal_detail.dart +++ b/lib/screens/log/log_meal_detail.dart @@ -27,6 +27,7 @@ class LogMealDetailScreen extends StatefulWidget { class _LogMealDetailScreenState extends State { final GlobalKey _logMealForm = GlobalKey(); + final _valueController = TextEditingController(text: ''); final _carbsRatioController = TextEditingController(text: ''); final _portionSizeController = TextEditingController(text: ''); @@ -35,19 +36,19 @@ class _LogMealDetailScreenState extends State { final _delayedBolusRateController = TextEditingController(text: ''); final _delayedBolusDurationController = TextEditingController(text: ''); final _notesController = TextEditingController(text: ''); - String? _meal; - String? _source; - String? _category; - String? _portionType; - String? _portionSizeAccuracy; - String? _carbsRatioAccuracy; + Meal? _meal; + MealSource? _mealSource; + MealCategory? _mealCategory; + MealPortionType? _mealPortionType; + Accuracy? _portionSizeAccuracy; + Accuracy? _carbsRatioAccuracy; - late Future> _meals; - late Future> _mealCategories; - late Future> _mealPortionTypes; - late Future> _mealSources; - late Future> _portionSizeAccuracies; - late Future> _carbsRatioAccuracies; + List _meals = []; + List _mealCategories = []; + List _mealPortionTypes = []; + List _mealSources = []; + List _portionSizeAccuracies = []; + List _carbsRatioAccuracies = []; bool _isSaving = false; @@ -55,6 +56,13 @@ class _LogMealDetailScreenState extends State { void initState() { super.initState(); + _portionSizeAccuracies = Accuracy.getAllForPortionSize(); + _carbsRatioAccuracies = Accuracy.getAllForCarbsRatio(); + _meals = Meal.getAll(); + _mealCategories = MealCategory.getAll(); + _mealPortionTypes = MealPortionType.getAll(); + _mealSources = MealSource.getAll(); + if (widget.logMeal != null) { _valueController.text = widget.logMeal!.value; _carbsRatioController.text = @@ -70,63 +78,56 @@ class _LogMealDetailScreenState extends State { (widget.logMeal!.delayedBolusDuration ?? '').toString(); _notesController.text = widget.logMeal!.notes ?? ''; - _meal = widget.logMeal!.meal; - _source = widget.logMeal!.source; - _category = widget.logMeal!.category; - _portionType = widget.logMeal!.portionType; - _portionSizeAccuracy = widget.logMeal!.portionSizeAccuracy; - _carbsRatioAccuracy = widget.logMeal!.carbsRatioAccuracy; + // _meal = widget.logMeal!.meal; + // _source = widget.logMeal!.source; + // _category = widget.logMeal!.category; + // _portionType = widget.logMeal!.portionType; + // _portionSizeAccuracy = _portionSizeAccuracies.firstWhere((element) => + // element.id == + // int.tryParse(widget.logMeal!.portionSizeAccuracy ?? '')); + // _carbsRatioAccuracy = _carbsRatioAccuracies.firstWhere((element) => + // element.id == int.tryParse(widget.logMeal!.carbsRatioAccuracy ?? '')); + // _portionSizeAccuracy = widget.meal!.portionSizeAccuracy; + // _carbsRatioAccuracy = widget.meal!.carbsRatioAccuracy; } - - _meals = Meal.fetchAll(); - _mealCategories = MealCategory.fetchAll(); - _mealPortionTypes = MealPortionType.fetchAll(); - _mealSources = MealSource.fetchAll(); - _portionSizeAccuracies = Accuracy.fetchAllForPortionSize(); - _carbsRatioAccuracies = Accuracy.fetchAllForCarbsRatio(); } - Future onSelectMeal(String? objectId) async { - if (objectId != null) { - Meal? meal = await Meal.get(objectId); - if (meal != null) { - setState(() { - _meal = objectId; - _valueController.text = meal.value; - 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.delayedBolusRate != null) { - _delayedBolusRateController.text = meal.delayedBolusRate.toString(); - } - if (meal.delayedBolusDuration != null) { - _delayedBolusDurationController.text = - meal.delayedBolusDuration.toString(); - } - if (meal.source != null) { - _source = meal.source; - } - if (meal.category != null) { - _category = meal.category; - } - if (meal.portionType != null) { - _portionType = meal.portionType; - } - if (meal.portionSizeAccuracy != null) { - _portionSizeAccuracy = meal.portionSizeAccuracy; - } - if (meal.carbsRatioAccuracy != null) { - _carbsRatioAccuracy = meal.carbsRatioAccuracy; - } - }); + Future onSelectMeal(Meal meal) async { + setState(() { + _meal = meal; + _valueController.text = meal.value; + 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.delayedBolusRate != null) { + _delayedBolusRateController.text = meal.delayedBolusRate.toString(); + } + if (meal.delayedBolusDuration != null) { + _delayedBolusDurationController.text = + meal.delayedBolusDuration.toString(); + } + if (meal.mealSource.hasValue) { + _mealSource = meal.mealSource.target; + } + if (meal.mealCategory.hasValue) { + _mealCategory = meal.mealCategory.target; + } + if (meal.mealPortionType.hasValue) { + _mealPortionType = meal.mealPortionType.target; + } + if (meal.portionSizeAccuracy.hasValue) { + _portionSizeAccuracy = meal.portionSizeAccuracy.target; + } + if (meal.carbsRatioAccuracy.hasValue) { + _carbsRatioAccuracy = meal.carbsRatioAccuracy.target; + } + }); } void handleSaveAction() async { @@ -135,45 +136,69 @@ class _LogMealDetailScreenState extends State { }); if (_logMealForm.currentState!.validate()) { bool isNew = widget.logMeal == null; - isNew - ? await LogMeal.save( - logEntry: widget.logEntry.objectId!, - meal: _meal, - value: _valueController.text, - source: _source, - category: _category, - portionType: _portionType, - carbsRatio: double.tryParse(_carbsRatioController.text), - portionSize: double.tryParse(_portionSizeController.text), - carbsPerPortion: double.tryParse(_carbsPerPortionController.text), - portionSizeAccuracy: _portionSizeAccuracy, - carbsRatioAccuracy: _carbsRatioAccuracy, - bolus: double.tryParse(_bolusController.text), - delayedBolusDuration: - int.tryParse(_delayedBolusDurationController.text), - delayedBolusRate: - double.tryParse(_delayedBolusRateController.text), - notes: _notesController.text, - ) - : await LogMeal.update( - widget.logMeal!.objectId!, - meal: _meal, - value: _valueController.text, - source: _source, - category: _category, - portionType: _portionType, - carbsRatio: double.tryParse(_carbsRatioController.text), - portionSize: double.tryParse(_portionSizeController.text), - carbsPerPortion: double.tryParse(_carbsPerPortionController.text), - portionSizeAccuracy: _portionSizeAccuracy, - carbsRatioAccuracy: _carbsRatioAccuracy, - bolus: double.tryParse(_bolusController.text), - delayedBolusDuration: - int.tryParse(_delayedBolusDurationController.text), - delayedBolusRate: - double.tryParse(_delayedBolusRateController.text), - notes: _notesController.text, - ); + // isNew + // ? await LogMeal.save( + // logEntry: widget.logEntry.objectId!, + // meal: _meal, + // value: _valueController.text, + // source: _mealSource, + // category: _category, + // portionType: _portionType, + // carbsRatio: double.tryParse(_carbsRatioController.text), + // portionSize: double.tryParse(_portionSizeController.text), + // carbsPerPortion: double.tryParse(_carbsPerPortionController.text), + // // portionSizeAccuracy: _portionSizeAccuracy, + // // carbsRatioAccuracy: _carbsRatioAccuracy, + // portionSizeAccuracy: _portionSizeAccuracy?.id.toString(), + // carbsRatioAccuracy: _carbsRatioAccuracy?.id.toString(), + // bolus: double.tryParse(_bolusController.text), + // delayedBolusDuration: + // int.tryParse(_delayedBolusDurationController.text), + // delayedBolusRate: + // double.tryParse(_delayedBolusRateController.text), + // notes: _notesController.text, + // ) + // : await LogMeal.update( + // widget.logMeal!.objectId!, + // meal: _meal, + // value: _valueController.text, + // source: _mealSource, + // category: _category, + // portionType: _portionType, + // carbsRatio: double.tryParse(_carbsRatioController.text), + // portionSize: double.tryParse(_portionSizeController.text), + // carbsPerPortion: double.tryParse(_carbsPerPortionController.text), + // // portionSizeAccuracy: _portionSizeAccuracy, + // // carbsRatioAccuracy: _carbsRatioAccuracy, + // portionSizeAccuracy: _portionSizeAccuracy?.id.toString(), + // carbsRatioAccuracy: _carbsRatioAccuracy?.id.toString(), + // bolus: double.tryParse(_bolusController.text), + // delayedBolusDuration: + // int.tryParse(_delayedBolusDurationController.text), + // delayedBolusRate: + // double.tryParse(_delayedBolusRateController.text), + // notes: _notesController.text, + // ); + LogMeal logMeal = LogMeal( + id: widget.logMeal?.id ?? 0, + value: _valueController.text, + carbsRatio: double.tryParse(_carbsRatioController.text), + portionSize: double.tryParse(_portionSizeController.text), + carbsPerPortion: double.tryParse(_carbsPerPortionController.text), + bolus: double.tryParse(_bolusController.text), + delayedBolusDuration: + int.tryParse(_delayedBolusDurationController.text), + delayedBolusRate: double.tryParse(_delayedBolusRateController.text), + notes: _notesController.text, + ); + logMeal.meal.target = _meal; + logMeal.mealSource.target = _mealSource; + logMeal.mealCategory.target = _mealCategory; + logMeal.mealPortionType.target = _mealPortionType; + logMeal.portionSizeAccuracy.target = _portionSizeAccuracy; + logMeal.carbsRatioAccuracy.target = _carbsRatioAccuracy; + + LogMeal.put(logMeal); Navigator.pop(context, '${isNew ? 'New' : ''} Meal Saved'); } setState(() { @@ -187,9 +212,9 @@ class _LogMealDetailScreenState extends State { ((isNew && (_valueController.text != '' || _meal != null || - _source != null || - _category != null || - _portionType != null || + _mealSource != null || + _mealCategory != null || + _mealPortionType != null || double.tryParse(_carbsRatioController.text) != null || double.tryParse(_portionSizeController.text) != null || double.tryParse(_carbsPerPortionController.text) != null || @@ -202,20 +227,25 @@ class _LogMealDetailScreenState extends State { _notesController.text != '')) || (!isNew && (_valueController.text != widget.logMeal!.value || - _meal != widget.logMeal!.meal || - _source != widget.logMeal!.source || - _category != widget.logMeal!.category || - _portionType != widget.logMeal!.portionType || + _meal != widget.logMeal!.meal.target || + _mealSource != widget.logMeal!.mealSource.target || + _mealCategory != widget.logMeal!.mealCategory.target || + _mealPortionType != widget.logMeal!.mealPortionType.target || double.tryParse(_carbsRatioController.text) != widget.logMeal!.carbsRatio || double.tryParse(_portionSizeController.text) != widget.logMeal!.portionSize || double.tryParse(_carbsPerPortionController.text) != widget.logMeal!.carbsPerPortion || - _carbsRatioAccuracy != widget.logMeal!.carbsRatioAccuracy || + // _carbsRatioAccuracy != widget.logMeal!.carbsRatioAccuracy || + // _portionSizeAccuracy != + // widget.logMeal!.portionSizeAccuracy || + _carbsRatioAccuracy != + widget.logMeal!.carbsRatioAccuracy.target || _portionSizeAccuracy != - widget.logMeal!.portionSizeAccuracy || - double.tryParse(_bolusController.text) != widget.logMeal!.bolus || + widget.logMeal!.portionSizeAccuracy.target || + double.tryParse(_bolusController.text) != + widget.logMeal!.bolus || int.tryParse(_delayedBolusDurationController.text) != widget.logMeal!.delayedBolusDuration || double.tryParse(_delayedBolusRateController.text) != @@ -300,49 +330,51 @@ class _LogMealDetailScreenState extends State { return null; }, ), - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _meal, label: 'Meal', items: _meals, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { - onSelectMeal(value); + if (value != null) { + onSelectMeal(value); + } }, ), - StyledFutureDropdownButton( - selectedItem: _source, + StyledDropdownButton( + selectedItem: _mealSource, label: 'Meal Source', items: _mealSources, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { - _source = value; + _mealSource = value; }); }, ), - StyledFutureDropdownButton( - selectedItem: _category, + StyledDropdownButton( + selectedItem: _mealCategory, label: 'Meal Category', items: _mealCategories, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { - _category = value; + _mealCategory = value; }); }, ), - StyledFutureDropdownButton( - selectedItem: _portionType, + StyledDropdownButton( + selectedItem: _mealPortionType, label: 'Meal Portion Type', items: _mealPortionTypes, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { - _portionType = value; + _mealPortionType = value; }); }, ), @@ -402,11 +434,11 @@ class _LogMealDetailScreenState extends State { ), ], ), - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _portionSizeAccuracy, label: 'Portion Size Accuracy', items: _portionSizeAccuracies, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { @@ -414,6 +446,18 @@ class _LogMealDetailScreenState extends State { }); }, ), + // StyledFutureDropdownButton( + // selectedItem: _portionSizeAccuracy, + // label: 'Portion Size Accuracy', + // items: _portionSizeAccuracies, + // getItemValue: (item) => item.objectId, + // renderItem: (item) => Text(item.value), + // onChanged: (value) { + // setState(() { + // _portionSizeAccuracy = value; + // }); + // }, + // ), Row( children: [ Expanded( @@ -444,11 +488,11 @@ class _LogMealDetailScreenState extends State { ), ], ), - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _carbsRatioAccuracy, label: 'Carbs Ratio Accuracy', items: _carbsRatioAccuracies, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { @@ -456,6 +500,18 @@ class _LogMealDetailScreenState extends State { }); }, ), + // StyledFutureDropdownButton( + // selectedItem: _carbsRatioAccuracy, + // label: 'Carbs Ratio Accuracy', + // items: _carbsRatioAccuracies, + // getItemValue: (item) => item.objectId, + // renderItem: (item) => Text(item.value), + // onChanged: (value) { + // setState(() { + // _carbsRatioAccuracy = value; + // }); + // }, + // ), TextFormField( decoration: const InputDecoration( labelText: 'Bolus Units', diff --git a/lib/screens/log/log_meal_list.dart b/lib/screens/log/log_meal_list.dart index 05945e1..cb0c0ea 100644 --- a/lib/screens/log/log_meal_list.dart +++ b/lib/screens/log/log_meal_list.dart @@ -4,24 +4,22 @@ import 'package:diameter/models/log_entry.dart'; import 'package:diameter/models/log_meal.dart'; import 'package:diameter/screens/log/log_meal_detail.dart'; import 'package:flutter/material.dart'; -import 'package:diameter/components/progress_indicator.dart'; class LogMealListScreen extends StatefulWidget { - final LogEntry? logEntry; + final LogEntry logEntry; + final Function() reload; - const LogMealListScreen({Key? key, this.logEntry}) : super(key: key); + const LogMealListScreen({Key? key, required this.logEntry, required this.reload}) + : super(key: key); @override _LogMealListScreenState createState() => _LogMealListScreenState(); } class _LogMealListScreenState extends State { - void refresh({String? message}) { - if (widget.logEntry != null) { - setState(() { - widget.logEntry!.meals = LogMeal.fetchAllForLogEntry(widget.logEntry!); - }); - } + void reload({String? message}) { + widget.reload(); + setState(() { if (message != null) { var snackBar = SnackBar( @@ -40,15 +38,16 @@ class _LogMealListScreenState extends State { context, MaterialPageRoute( builder: (context) => LogMealDetailScreen( - logEntry: widget.logEntry!, + logEntry: widget.logEntry, logMeal: meal, ), ), - ).then((message) => refresh(message: message)); + ).then((message) => reload(message: message)); } - void onDelete(LogMeal meal) { - meal.delete().then((_) => refresh(message: 'Meal deleted')); + void onDelete(LogMeal logMeal) { + LogMeal.remove(logMeal.id); + reload(message: 'Meal deleted'); } void handleDeleteAction(LogMeal meal) async { @@ -63,60 +62,46 @@ class _LogMealListScreenState extends State { } } - @override - void initState() { - super.initState(); - refresh(); - } - @override Widget build(BuildContext context) { - return SingleChildScrollView( - padding: const EdgeInsets.only(top: 10.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - FutureBuilder>( - future: widget.logEntry!.meals, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? const Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Meals for this Log Entry'), - ) - : ListView.builder( - shrinkWrap: true, - itemCount: snapshot.data != null ? snapshot.data!.length : 0, - itemBuilder: (context, index) { - final meal = snapshot.data![index]; - return ListTile( - onTap: () => handleEditAction(meal), - title: Row( - 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' : '')) - ], - ), - trailing: IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => handleDeleteAction(meal), - ), - ); - }, + return Column( + children: [ + Expanded( + child: widget.logEntry.meals.isNotEmpty ? ListView.builder( + shrinkWrap: true, + itemCount: widget.logEntry.meals.length, + itemBuilder: (context, index) { + final meal = widget.logEntry.meals[index]; + return ListTile( + onTap: () => handleEditAction(meal), + title: Row( + 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' + : '')) + ], + ), + trailing: IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, ), - ); - }, + onPressed: () => handleDeleteAction(meal), + ), + ); + }, + ) : const Center( + child: Text( + 'You have not added any Meals to this Log Entry yet!'), + ), ), ], - ), ); } } diff --git a/lib/screens/meal/meal_category_detail.dart b/lib/screens/meal/meal_category_detail.dart index 4dc5c8e..0414f45 100644 --- a/lib/screens/meal/meal_category_detail.dart +++ b/lib/screens/meal/meal_category_detail.dart @@ -35,11 +35,13 @@ class _MealCategoryDetailScreenState extends State { void handleSaveAction() async { if (_mealCategoryForm.currentState!.validate()) { bool isNew = widget.mealCategory == null; - isNew - ? await MealCategory.save( - value: _valueController.text, notes: _notesController.text) - : await MealCategory.update(widget.mealCategory!.objectId!, - value: _valueController.text, notes: _notesController.text); + // isNew + // ? await MealCategory.save( + // value: _valueController.text, notes: _notesController.text) + // : await MealCategory.update(widget.mealCategory!.objectId!, + // value: _valueController.text, notes: _notesController.text); + MealCategory.put(MealCategory(id: widget.mealCategory?.id ?? 0, + value: _valueController.text, notes: _notesController.text)); Navigator.pop(context, '${isNew ? 'New' : ''} Meal Category saved'); } } diff --git a/lib/screens/meal/meal_category_list.dart b/lib/screens/meal/meal_category_list.dart index 0304a01..ead7fde 100644 --- a/lib/screens/meal/meal_category_list.dart +++ b/lib/screens/meal/meal_category_list.dart @@ -1,5 +1,5 @@ import 'package:diameter/components/dialogs.dart'; -import 'package:diameter/components/progress_indicator.dart'; +// import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/config.dart'; import 'package:diameter/navigation.dart'; import 'package:diameter/screens/meal/meal_category_detail.dart'; @@ -16,11 +16,11 @@ class MealCategoryListScreen extends StatefulWidget { } class _MealCategoryListScreenState extends State { - late Future?> _mealCategories; + List _mealCategories = []; void refresh({String? message}) { setState(() { - _mealCategories = MealCategory.fetchAll(); + _mealCategories = MealCategory.getAll(); }); setState(() { if (message != null) { @@ -36,9 +36,8 @@ class _MealCategoryListScreenState extends State { } void onDelete(MealCategory mealCategory) { - mealCategory - .delete() - .then((_) => refresh(message: 'Meal Category deleted')); + MealCategory.remove(mealCategory.id); + refresh(message: 'Meal Category deleted'); } void handleDeleteAction(MealCategory mealCategory) async { @@ -77,58 +76,43 @@ class _MealCategoryListScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( - child: FutureBuilder?>( - future: _mealCategories, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Meal Categories'), - ), - ], - ) - : ListView.builder( - padding: const EdgeInsets.only(top: 10.0), - itemCount: - snapshot.data != null ? snapshot.data!.length : 0, - itemBuilder: (context, index) { - final mealCategory = snapshot.data![index]; - return ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - MealCategoryDetailScreen( - mealCategory: mealCategory, - ), - ), - ).then((message) => refresh(message: message)); - }, - title: Text(mealCategory.value), - subtitle: Text(mealCategory.notes ?? ''), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => - handleDeleteAction(mealCategory), - ), - ], - ), - ); - }), + child: _mealCategories.isNotEmpty ? ListView.builder( + padding: const EdgeInsets.only(top: 10.0), + itemCount: _mealCategories.length, + itemBuilder: (context, index) { + final mealCategory = _mealCategories[index]; + + return ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + MealCategoryDetailScreen( + mealCategory: mealCategory, + ), + ), + ).then((message) => refresh(message: message)); + }, + title: Text(mealCategory.value), + subtitle: Text(mealCategory.notes ?? ''), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, + ), + onPressed: () => + handleDeleteAction(mealCategory), + ), + ], + ), ); }, + ): const Center( + child: Text('You have not created any Meal Categories yet!'), ), ), ], diff --git a/lib/screens/meal/meal_detail.dart b/lib/screens/meal/meal_detail.dart index 97f56f0..c7ca8b3 100644 --- a/lib/screens/meal/meal_detail.dart +++ b/lib/screens/meal/meal_detail.dart @@ -8,6 +8,7 @@ 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/navigation.dart'; +// import 'package:diameter/objectbox.g.dart'; import 'package:diameter/settings.dart'; import 'package:diameter/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -24,6 +25,7 @@ class MealDetailScreen extends StatefulWidget { class _MealDetailScreenState extends State { final GlobalKey _mealForm = GlobalKey(); + final _valueController = TextEditingController(text: ''); final _carbsRatioController = TextEditingController(text: ''); final _portionSizeController = TextEditingController(text: ''); @@ -31,17 +33,18 @@ class _MealDetailScreenState extends State { final _delayedBolusRateController = TextEditingController(text: ''); final _delayedBolusDurationController = TextEditingController(text: ''); final _notesController = TextEditingController(text: ''); - String? _source; - String? _category; - String? _portionType; - String? _portionSizeAccuracy; - String? _carbsRatioAccuracy; - late Future> _mealCategories; - late Future> _mealPortionTypes; - late Future> _mealSources; - late Future> _portionSizeAccuracies; - late Future> _carbsRatioAccuracies; + MealSource? _mealSource; + MealCategory? _mealCategory; + MealPortionType? _mealPortionType; + Accuracy? _portionSizeAccuracy; + Accuracy? _carbsRatioAccuracy; + + List _mealCategories = []; + List _mealPortionTypes = []; + List _mealSources = []; + List _portionSizeAccuracies = []; + List _carbsRatioAccuracies = []; bool isSaving = false; @@ -49,6 +52,12 @@ class _MealDetailScreenState extends State { void initState() { super.initState(); + _portionSizeAccuracies = Accuracy.getAllForPortionSize(); + _carbsRatioAccuracies = Accuracy.getAllForCarbsRatio(); + _mealCategories = MealCategory.getAll(); + _mealPortionTypes = MealPortionType.getAll(); + _mealSources = MealSource.getAll(); + if (widget.meal != null) { _valueController.text = widget.meal!.value; _carbsRatioController.text = (widget.meal!.carbsRatio ?? '').toString(); @@ -61,18 +70,12 @@ class _MealDetailScreenState extends State { (widget.meal!.delayedBolusDuration ?? '').toString(); _notesController.text = widget.meal!.notes ?? ''; - _source = widget.meal!.source; - _category = widget.meal!.category; - _portionType = widget.meal!.portionType; - _portionSizeAccuracy = widget.meal!.portionSizeAccuracy; - _carbsRatioAccuracy = widget.meal!.carbsRatioAccuracy; + _mealSource = widget.meal!.mealSource.target; + _mealCategory = widget.meal!.mealCategory.target; + _mealPortionType = widget.meal!.mealPortionType.target; + _portionSizeAccuracy = widget.meal!.portionSizeAccuracy.target; + _carbsRatioAccuracy = widget.meal!.carbsRatioAccuracy.target; } - - _mealCategories = MealCategory.fetchAll(); - _mealPortionTypes = MealPortionType.fetchAll(); - _mealSources = MealSource.fetchAll(); - _portionSizeAccuracies = Accuracy.fetchAllForPortionSize(); - _carbsRatioAccuracies = Accuracy.fetchAllForCarbsRatio(); } void handleSaveAction() async { @@ -81,40 +84,62 @@ class _MealDetailScreenState extends State { }); if (_mealForm.currentState!.validate()) { bool isNew = widget.meal == null; - isNew - ? await Meal.save( - value: _valueController.text, - source: _source, - category: _category, - portionType: _portionType, - carbsRatio: double.tryParse(_carbsRatioController.text), - portionSize: double.tryParse(_portionSizeController.text), - carbsPerPortion: double.tryParse(_carbsPerPortionController.text), - portionSizeAccuracy: _portionSizeAccuracy, - carbsRatioAccuracy: _carbsRatioAccuracy, - delayedBolusDuration: - int.tryParse(_delayedBolusDurationController.text), - delayedBolusRate: - double.tryParse(_delayedBolusRateController.text), - notes: _notesController.text, - ) - : await Meal.update( - widget.meal!.objectId!, - value: _valueController.text, - source: _source, - category: _category, - portionType: _portionType, - carbsRatio: double.tryParse(_carbsRatioController.text), - portionSize: double.tryParse(_portionSizeController.text), - carbsPerPortion: double.tryParse(_carbsPerPortionController.text), - portionSizeAccuracy: _portionSizeAccuracy, - carbsRatioAccuracy: _carbsRatioAccuracy, - delayedBolusDuration: - int.tryParse(_delayedBolusDurationController.text), - delayedBolusRate: - double.tryParse(_delayedBolusRateController.text), - notes: _notesController.text, - ); + // isNew + // ? await Meal.save( + // value: _valueController.text, + // source: _mealSource, + // category: _mealCategory, + // portionType: _mealPortionType, + // carbsRatio: double.tryParse(_carbsRatioController.text), + // portionSize: double.tryParse(_portionSizeController.text), + // carbsPerPortion: double.tryParse(_carbsPerPortionController.text), + // // portionSizeAccuracy: _portionSizeAccuracy, + // // carbsRatioAccuracy: _carbsRatioAccuracy, + // portionSizeAccuracy: _portionSizeAccuracy?.id.toString(), + // carbsRatioAccuracy: _carbsRatioAccuracy?.id.toString(), + // delayedBolusDuration: + // int.tryParse(_delayedBolusDurationController.text), + // delayedBolusRate: + // double.tryParse(_delayedBolusRateController.text), + // notes: _notesController.text, + // ) + // : await Meal.update( + // widget.meal!.objectId!, + // value: _valueController.text, + // source: _mealSource, + // category: _mealCategory, + // portionType: _mealPortionType, + // carbsRatio: double.tryParse(_carbsRatioController.text), + // portionSize: double.tryParse(_portionSizeController.text), + // carbsPerPortion: double.tryParse(_carbsPerPortionController.text), + // // portionSizeAccuracy: _portionSizeAccuracy, + // // carbsRatioAccuracy: _carbsRatioAccuracy, + // portionSizeAccuracy: _portionSizeAccuracy?.id.toString(), + // carbsRatioAccuracy: _carbsRatioAccuracy?.id.toString(), + // delayedBolusDuration: + // int.tryParse(_delayedBolusDurationController.text), + // delayedBolusRate: + // double.tryParse(_delayedBolusRateController.text), + // notes: _notesController.text, + // ); + Meal meal = Meal( + id: widget.meal?.id ?? 0, + value: _valueController.text, + carbsRatio: double.tryParse(_carbsRatioController.text), + portionSize: double.tryParse(_portionSizeController.text), + carbsPerPortion: double.tryParse(_carbsPerPortionController.text), + delayedBolusDuration: + int.tryParse(_delayedBolusDurationController.text), + delayedBolusRate: double.tryParse(_delayedBolusRateController.text), + notes: _notesController.text, + ); + meal.mealSource.target = _mealSource; + meal.mealCategory.target = _mealCategory; + meal.mealPortionType.target = _mealPortionType; + meal.portionSizeAccuracy.target = _portionSizeAccuracy; + meal.carbsRatioAccuracy.target = _carbsRatioAccuracy; + + Meal.put(meal); Navigator.pop(context, '${isNew ? 'New' : ''} Meal Saved'); } setState(() { @@ -127,9 +152,9 @@ class _MealDetailScreenState extends State { if (showConfirmationDialogOnCancel && ((isNew && (_valueController.text != '' || - _source != null || - _category != null || - _portionType != null || + _mealSource != null || + _mealCategory != null || + _mealPortionType != null || double.tryParse(_carbsRatioController.text) != null || double.tryParse(_portionSizeController.text) != null || double.tryParse(_carbsPerPortionController.text) != null || @@ -141,17 +166,17 @@ class _MealDetailScreenState extends State { _notesController.text != '')) || (!isNew && (_valueController.text != widget.meal!.value || - _source != widget.meal!.source || - _category != widget.meal!.category || - _portionType != widget.meal!.portionType || + _mealSource != widget.meal!.mealSource.target || + _mealCategory != widget.meal!.mealCategory.target || + _mealPortionType != widget.meal!.mealPortionType.target || double.tryParse(_carbsRatioController.text) != widget.meal!.carbsRatio || double.tryParse(_portionSizeController.text) != widget.meal!.portionSize || double.tryParse(_carbsPerPortionController.text) != widget.meal!.carbsPerPortion || - _carbsRatioAccuracy != widget.meal!.carbsRatioAccuracy || - _portionSizeAccuracy != widget.meal!.portionSizeAccuracy || + _carbsRatioAccuracy != widget.meal!.carbsRatioAccuracy.target || + _portionSizeAccuracy != widget.meal!.portionSizeAccuracy.target || int.tryParse(_delayedBolusDurationController.text) != widget.meal!.delayedBolusDuration || double.tryParse(_delayedBolusRateController.text) != @@ -167,29 +192,24 @@ class _MealDetailScreenState extends State { } } - Future onSelectMealSource(String? objectId) async { - if (objectId != null) { - MealSource? mealSource = await MealSource.get(objectId); - if (mealSource != null) { - setState(() { - _source = objectId; - if (mealSource.defaultCarbsRatioAccuracy != null) { - _carbsRatioAccuracy = - mealSource.defaultCarbsRatioAccuracy.toString(); - } - if (mealSource.defaultPortionSizeAccuracy != null) { - _portionSizeAccuracy = - mealSource.defaultPortionSizeAccuracy.toString(); - } - if (mealSource.defaultMealCategory != null) { - _category = mealSource.defaultMealCategory.toString(); - } - if (mealSource.defaultMealPortionType != null) { - _portionType = mealSource.defaultMealPortionType.toString(); - } - }); + Future onSelectMealSource(MealSource mealSource) async { + setState(() { + _mealSource = mealSource; + if (mealSource.defaultCarbsRatioAccuracy.hasValue) { + _carbsRatioAccuracy = + mealSource.defaultCarbsRatioAccuracy.target; } - } + if (mealSource.defaultPortionSizeAccuracy.hasValue) { + _portionSizeAccuracy = + mealSource.defaultPortionSizeAccuracy.target; + } + if (mealSource.defaultMealCategory.hasValue) { + _mealCategory = mealSource.defaultMealCategory.target; + } + if (mealSource.defaultMealPortionType.hasValue) { + _mealPortionType = mealSource.defaultMealPortionType.target; + } + }); } void calculateThirdMeasurementOfPortionCarbsRelation( @@ -261,37 +281,39 @@ class _MealDetailScreenState extends State { return null; }, ), - StyledFutureDropdownButton( - selectedItem: _source, + StyledDropdownButton( + selectedItem: _mealSource, label: 'Meal Source', items: _mealSources, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { - onSelectMealSource(value); + if (value != null) { + onSelectMealSource(value); + } }, ), - StyledFutureDropdownButton( - selectedItem: _category, + StyledDropdownButton( + selectedItem: _mealCategory, label: 'Meal Category', items: _mealCategories, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { - _category = value; + _mealCategory = value; }); }, ), - StyledFutureDropdownButton( - selectedItem: _portionType, + StyledDropdownButton( + selectedItem: _mealPortionType, label: 'Meal Portion Type', items: _mealPortionTypes, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { - _portionType = value; + _mealPortionType = value; }); }, ), @@ -351,11 +373,11 @@ class _MealDetailScreenState extends State { ), ], ), - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _portionSizeAccuracy, label: 'Portion Size Accuracy', items: _portionSizeAccuracies, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { @@ -363,6 +385,18 @@ class _MealDetailScreenState extends State { }); }, ), + // StyledFutureDropdownButton( + // selectedItem: _portionSizeAccuracy, + // label: 'Portion Size Accuracy', + // items: _portionSizeAccuracies, + // getItemValue: (item) => item.objectId, + // renderItem: (item) => Text(item.value), + // onChanged: (value) { + // setState(() { + // _portionSizeAccuracy = value; + // }); + // }, + // ), Row( children: [ Expanded( @@ -393,11 +427,11 @@ class _MealDetailScreenState extends State { ), ], ), - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _carbsRatioAccuracy, label: 'Carbs Ratio Accuracy', items: _carbsRatioAccuracies, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { @@ -405,6 +439,18 @@ class _MealDetailScreenState extends State { }); }, ), + // StyledFutureDropdownButton( + // selectedItem: _carbsRatioAccuracy, + // label: 'Carbs Ratio Accuracy', + // items: _carbsRatioAccuracies, + // getItemValue: (item) => item.objectId, + // renderItem: (item) => Text(item.value), + // onChanged: (value) { + // setState(() { + // _carbsRatioAccuracy = value; + // }); + // }, + // ), // TODO: display according to time format TextFormField( decoration: const InputDecoration( diff --git a/lib/screens/meal/meal_list.dart b/lib/screens/meal/meal_list.dart index af43d46..d0f37b6 100644 --- a/lib/screens/meal/meal_list.dart +++ b/lib/screens/meal/meal_list.dart @@ -1,5 +1,5 @@ import 'package:diameter/components/dialogs.dart'; -import 'package:diameter/components/progress_indicator.dart'; +// import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/config.dart'; import 'package:diameter/models/meal.dart'; import 'package:diameter/navigation.dart'; @@ -16,11 +16,11 @@ class MealListScreen extends StatefulWidget { } class _MealListScreenState extends State { - late Future?> _meals; + List _meals = []; void refresh({String? message}) { setState(() { - _meals = Meal.fetchAll(); + _meals = Meal.getAll(); }); setState(() { if (message != null) { @@ -36,7 +36,8 @@ class _MealListScreenState extends State { } void onDelete(Meal meal) { - meal.delete().then((_) => refresh(message: 'Meal deleted')); + Meal.remove(meal.id); + refresh(message: 'Meal deleted'); } void handleDeleteAction(Meal meal) async { @@ -68,54 +69,38 @@ class _MealListScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( - child: FutureBuilder?>( - future: _meals, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Meals'), - ), - ], - ) - : ListView.builder( - padding: const EdgeInsets.all(10.0), - itemCount: - snapshot.data != null ? snapshot.data!.length : 0, - itemBuilder: (context, index) { - final meal = snapshot.data![index]; - return ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - MealDetailScreen(meal: meal), - ), - ).then((message) => refresh(message: message)); - }, - title: Text(meal.value), - subtitle: Text(meal.notes ?? ''), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - onPressed: () => handleDeleteAction(meal), - icon: const Icon(Icons.delete, - color: Colors.blue), - ) - ], - ), - ); - }, - ), + child: _meals.isNotEmpty ? ListView.builder( + padding: const EdgeInsets.all(10.0), + itemCount: _meals.length, + itemBuilder: (context, index) { + final meal = _meals[index]; + + return ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + MealDetailScreen(meal: meal), + ), + ).then((message) => refresh(message: message)); + }, + title: Text(meal.value), + subtitle: Text(meal.notes ?? ''), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + onPressed: () => handleDeleteAction(meal), + icon: const Icon(Icons.delete, + color: Colors.blue), + ) + ], + ), ); }, + ): const Center( + child: Text('You have not created any Meals yet!'), ), ), ], diff --git a/lib/screens/meal/meal_portion_type_detail.dart b/lib/screens/meal/meal_portion_type_detail.dart index b19ae40..1b6ef56 100644 --- a/lib/screens/meal/meal_portion_type_detail.dart +++ b/lib/screens/meal/meal_portion_type_detail.dart @@ -37,16 +37,21 @@ class _MealPortionTypeDetailScreenState void handleSaveAction() async { if (_mealPortionTypeForm.currentState!.validate()) { bool isNew = widget.mealPortionType == null; - isNew - ? MealPortionType.save( - value: _valueController.text, - notes: _notesController.text, - ) - : MealPortionType.update( - widget.mealPortionType!.objectId!, - value: _valueController.text, - notes: _notesController.text, - ); + // isNew + // ? MealPortionType.save( + // value: _valueController.text, + // notes: _notesController.text, + // ) + // : MealPortionType.update( + // widget.mealPortionType!.objectId!, + // value: _valueController.text, + // notes: _notesController.text, + // ); + MealPortionType.put(MealPortionType( + id: widget.mealPortionType?.id ?? 0, + value: _valueController.text, + notes: _notesController.text, + )); Navigator.pop(context, '${isNew ? 'New' : ''} Meal Portion Type saved'); } } diff --git a/lib/screens/meal/meal_portion_type_list.dart b/lib/screens/meal/meal_portion_type_list.dart index a67409d..c59a96e 100644 --- a/lib/screens/meal/meal_portion_type_list.dart +++ b/lib/screens/meal/meal_portion_type_list.dart @@ -1,5 +1,5 @@ import 'package:diameter/components/dialogs.dart'; -import 'package:diameter/components/progress_indicator.dart'; +// import 'package:diameter/components/progress_indicator.dart'; import 'package:diameter/config.dart'; import 'package:diameter/navigation.dart'; import 'package:diameter/screens/meal/meal_portion_type_detail.dart'; @@ -17,11 +17,11 @@ class MealPortionTypeListScreen extends StatefulWidget { } class _MealPortionTypeListScreenState extends State { - late Future?> _mealPortionTypes; + List _mealPortionTypes = []; void refresh({String? message}) { setState(() { - _mealPortionTypes = MealPortionType.fetchAll(); + _mealPortionTypes = MealPortionType.getAll(); }); setState(() { if (message != null) { @@ -37,9 +37,8 @@ class _MealPortionTypeListScreenState extends State { } void onDelete(MealPortionType mealPortionType) { - mealPortionType - .delete() - .then((_) => refresh(message: 'Meal Portion Type deleted')); + MealPortionType.remove(mealPortionType.id); + refresh(message: 'Meal Portion Type deleted'); } void handleDeleteAction(MealPortionType mealPortionType) async { @@ -75,59 +74,44 @@ class _MealPortionTypeListScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( - child: FutureBuilder?>( - future: _mealPortionTypes, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Meal Portion Types'), - ) - ], - ) - : ListView.builder( - padding: const EdgeInsets.only(top: 10.0), - itemCount: snapshot.data != null - ? snapshot.data!.length - : 0, - itemBuilder: (context, index) { - final mealPortionType = snapshot.data![index]; - return ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - MealPortionTypeDetailScreen( - mealPortionType: mealPortionType, - ), - ), - ).then( - (message) => refresh(message: message)); - }, - title: Text(mealPortionType.value), - subtitle: Text(mealPortionType.notes ?? ''), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () => - handleDeleteAction(mealPortionType), - ), - ], - ), - ); - })); + child: _mealPortionTypes.isNotEmpty ? ListView.builder( + padding: const EdgeInsets.only(top: 10.0), + itemCount: _mealPortionTypes.length, + itemBuilder: (context, index) { + final mealPortionType = _mealPortionTypes[index]; + + return ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + MealPortionTypeDetailScreen( + mealPortionType: mealPortionType, + ), + ), + ).then( + (message) => refresh(message: message)); + }, + title: Text(mealPortionType.value), + subtitle: Text(mealPortionType.notes ?? ''), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, + ), + onPressed: () => + handleDeleteAction(mealPortionType), + ), + ], + ), + ); }, + ) : const Center( + child: Text('You have not created any Meal Portion Types yet!'), ), ), ], diff --git a/lib/screens/meal/meal_source_detail.dart b/lib/screens/meal/meal_source_detail.dart index 1c53056..595286c 100644 --- a/lib/screens/meal/meal_source_detail.dart +++ b/lib/screens/meal/meal_source_detail.dart @@ -2,11 +2,13 @@ import 'package:diameter/components/detail.dart'; import 'package:diameter/components/dialogs.dart'; import 'package:diameter/components/forms.dart'; import 'package:diameter/config.dart'; +// import 'package:diameter/main.dart'; 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/navigation.dart'; +// import 'package:diameter/objectbox.g.dart'; import 'package:flutter/material.dart'; class MealSourceDetailScreen extends StatefulWidget { @@ -21,61 +23,79 @@ class MealSourceDetailScreen extends StatefulWidget { } class _MealSourceDetailScreenState extends State { - late Future> _portionSizeAccuracies; - late Future> _carbsRatioAccuracies; - late Future> _mealCategories; - late Future> _mealPortionTypes; + List _portionSizeAccuracies = []; + List _carbsRatioAccuracies = []; + List _mealCategories = []; + List _mealPortionTypes = []; final GlobalKey _mealSourceForm = GlobalKey(); + final _valueController = TextEditingController(text: ''); final _notesController = TextEditingController(text: ''); - String? _defaultCarbsRatioAccuracy; - String? _defaultPortionSizeAccuracy; - String? _defaultMealCategory; - String? _defaultMealPortionType; + Accuracy? _defaultCarbsRatioAccuracy; + Accuracy? _defaultPortionSizeAccuracy; + MealCategory? _defaultMealCategory; + MealPortionType? _defaultMealPortionType; @override void initState() { super.initState(); + _portionSizeAccuracies = Accuracy.getAllForPortionSize(); + _carbsRatioAccuracies = Accuracy.getAllForCarbsRatio(); + _mealCategories = MealCategory.getAll(); + _mealPortionTypes = MealPortionType.getAll(); + if (widget.mealSource != null) { _valueController.text = widget.mealSource!.value; _notesController.text = widget.mealSource!.notes ?? ''; - _defaultCarbsRatioAccuracy = widget.mealSource!.defaultCarbsRatioAccuracy; _defaultPortionSizeAccuracy = - widget.mealSource!.defaultPortionSizeAccuracy; - _defaultMealCategory = widget.mealSource!.defaultMealCategory; - _defaultMealPortionType = widget.mealSource!.defaultMealPortionType; - } + widget.mealSource!.defaultPortionSizeAccuracy.target; + _defaultCarbsRatioAccuracy = widget.mealSource!.defaultCarbsRatioAccuracy.target; - _portionSizeAccuracies = Accuracy.fetchAllForPortionSize(); - _carbsRatioAccuracies = Accuracy.fetchAllForCarbsRatio(); - _mealCategories = MealCategory.fetchAll(); - _mealPortionTypes = MealPortionType.fetchAll(); + _defaultMealCategory = widget.mealSource!.defaultMealCategory.target; + _defaultMealPortionType = + widget.mealSource!.defaultMealPortionType.target; + } } void handleSaveAction() async { bool isNew = widget.mealSource == null; if (_mealSourceForm.currentState!.validate()) { - isNew - ? await MealSource.save( - value: _valueController.text, - defaultCarbsRatioAccuracy: _defaultCarbsRatioAccuracy, - defaultPortionSizeAccuracy: _defaultPortionSizeAccuracy, - defaultMealCategory: _defaultMealCategory, - defaultMealPortionType: _defaultMealPortionType, - notes: _notesController.text, - ) - : await MealSource.update( - widget.mealSource!.objectId!, - value: _valueController.text, - defaultCarbsRatioAccuracy: _defaultCarbsRatioAccuracy, - defaultPortionSizeAccuracy: _defaultPortionSizeAccuracy, - defaultMealCategory: _defaultMealCategory, - defaultMealPortionType: _defaultMealPortionType, - notes: _notesController.text, - ); + // isNew + // ? await MealSource.save( + // value: _valueController.text, + // defaultCarbsRatioAccuracy: _defaultCarbsRatioAccuracy?.id.toString(), + // defaultPortionSizeAccuracy: _defaultPortionSizeAccuracy?.id.toString(), + // // defaultCarbsRatioAccuracy: _defaultCarbsRatioAccuracy, + // // defaultPortionSizeAccuracy: _defaultPortionSizeAccuracy, + // defaultMealCategory: _defaultMealCategory, + // defaultMealPortionType: _defaultMealPortionType, + // notes: _notesController.text, + // ) + // : await MealSource.update( + // widget.mealSource!.objectId!, + // value: _valueController.text, + // defaultCarbsRatioAccuracy: _defaultCarbsRatioAccuracy?.id.toString(), + // defaultPortionSizeAccuracy: _defaultPortionSizeAccuracy?.id.toString(), + // // defaultCarbsRatioAccuracy: _defaultCarbsRatioAccuracy, + // // defaultPortionSizeAccuracy: _defaultPortionSizeAccuracy, + // defaultMealCategory: _defaultMealCategory, + // defaultMealPortionType: _defaultMealPortionType, + // notes: _notesController.text, + // ); + MealSource mealSource = MealSource( + id: widget.mealSource?.id ?? 0, + value: _valueController.text, + notes: _notesController.text, + ); + mealSource.defaultCarbsRatioAccuracy.target = _defaultCarbsRatioAccuracy; + mealSource.defaultPortionSizeAccuracy.target = + _defaultPortionSizeAccuracy; + mealSource.defaultMealCategory.target = _defaultMealCategory; + mealSource.defaultMealPortionType.target = _defaultMealPortionType; + MealSource.put(mealSource); Navigator.pop(context, '${isNew ? 'New' : ''} Meal Source saved'); } } @@ -93,13 +113,13 @@ class _MealSourceDetailScreenState extends State { (!isNew && (_valueController.text != widget.mealSource!.value || _defaultCarbsRatioAccuracy != - widget.mealSource!.defaultCarbsRatioAccuracy || + widget.mealSource!.defaultCarbsRatioAccuracy.target || _defaultPortionSizeAccuracy != - widget.mealSource!.defaultPortionSizeAccuracy || + widget.mealSource!.defaultPortionSizeAccuracy.target || _defaultMealCategory != - widget.mealSource!.defaultMealCategory || + widget.mealSource!.defaultMealCategory.target || _defaultMealPortionType != - widget.mealSource!.defaultMealPortionType || + widget.mealSource!.defaultMealPortionType.target || _notesController.text != (widget.mealSource!.notes ?? ''))))) { Dialogs.showCancelConfirmationDialog( @@ -140,11 +160,10 @@ class _MealSourceDetailScreenState extends State { return null; }, ), - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _defaultCarbsRatioAccuracy, label: 'Default Carbs Ratio Accuracy', items: _carbsRatioAccuracies, - getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { @@ -152,11 +171,10 @@ class _MealSourceDetailScreenState extends State { }); }, ), - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _defaultPortionSizeAccuracy, label: 'Default Portion Size Accuracy', items: _portionSizeAccuracies, - getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { @@ -164,11 +182,35 @@ class _MealSourceDetailScreenState extends State { }); }, ), - StyledFutureDropdownButton( + // StyledFutureDropdownButton( + // selectedItem: _defaultCarbsRatioAccuracy, + // label: 'Default Carbs Ratio Accuracy', + // items: _carbsRatioAccuracies, + // getItemValue: (item) => item.objectId, + // renderItem: (item) => Text(item.value), + // onChanged: (value) { + // setState(() { + // _defaultCarbsRatioAccuracy = value; + // }); + // }, + // ), + // StyledFutureDropdownButton( + // selectedItem: _defaultPortionSizeAccuracy, + // label: 'Default Portion Size Accuracy', + // items: _portionSizeAccuracies, + // getItemValue: (item) => item.objectId, + // renderItem: (item) => Text(item.value), + // onChanged: (value) { + // setState(() { + // _defaultPortionSizeAccuracy = value; + // }); + // }, + // ), + StyledDropdownButton( selectedItem: _defaultMealCategory, label: 'Default Meal Category', items: _mealCategories, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { @@ -176,11 +218,11 @@ class _MealSourceDetailScreenState extends State { }); }, ), - StyledFutureDropdownButton( + StyledDropdownButton( selectedItem: _defaultMealPortionType, label: 'Default Meal Portion Type', items: _mealPortionTypes, - getItemValue: (item) => item.objectId, + // getItemValue: (item) => item.objectId, renderItem: (item) => Text(item.value), onChanged: (value) { setState(() { diff --git a/lib/screens/meal/meal_source_list.dart b/lib/screens/meal/meal_source_list.dart index 9478972..c72ed19 100644 --- a/lib/screens/meal/meal_source_list.dart +++ b/lib/screens/meal/meal_source_list.dart @@ -1,4 +1,6 @@ -import 'package:diameter/components/progress_indicator.dart'; +// import 'package:diameter/components/progress_indicator.dart'; +import 'package:diameter/components/dialogs.dart'; +import 'package:diameter/config.dart'; import 'package:diameter/models/meal_source.dart'; import 'package:diameter/navigation.dart'; import 'package:diameter/screens/meal/meal_source_detail.dart'; @@ -14,11 +16,11 @@ class MealSourceListScreen extends StatefulWidget { } class _MealSourceListScreenState extends State { - late Future?> _mealSources; + List _mealSources = []; void refresh({String? message}) { setState(() { - _mealSources = MealSource.fetchAll(); + _mealSources = MealSource.getAll(); }); setState(() { if (message != null) { @@ -33,6 +35,23 @@ class _MealSourceListScreenState extends State { }); } + void onDelete(MealSource mealSource) { + MealSource.remove(mealSource.id); + refresh(message: 'Meal Source deleted'); + } + + void handleDeleteAction(MealSource mealSource) async { + if (showConfirmationDialogOnDelete) { + Dialogs.showConfirmationDialog( + context: context, + onConfirm: () => onDelete(mealSource), + message: 'Are you sure you want to delete this Meal Source?', + ); + } else { + onDelete(mealSource); + } + } + @override void initState() { super.initState(); @@ -53,64 +72,43 @@ class _MealSourceListScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( - child: FutureBuilder?>( - future: _mealSources, - builder: (context, snapshot) { - return ViewWithProgressIndicator( - snapshot: snapshot, - child: snapshot.data == null || snapshot.data!.isEmpty - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Padding( - padding: EdgeInsets.all(10.0), - child: Text('No Meal Sources'), - ) - ], - ) - : ListView.builder( - padding: const EdgeInsets.only(top: 10.0), - itemCount: snapshot.data != null - ? snapshot.data!.length - : 0, - itemBuilder: (context, index) { - final mealSource = snapshot.data![index]; - return ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - MealSourceDetailScreen( - mealSource: mealSource, - ), - ), - ).then( - (message) => refresh(message: message)); - }, - title: Text(mealSource.value), - subtitle: Text(mealSource.notes ?? ''), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon( - Icons.delete, - color: Colors.blue, - ), - onPressed: () async { - // add confirmation dialog - await mealSource.delete().then((_) { - refresh( - message: 'Meal Source deleted'); - }); - }, - ), - ], - ), - ); - })); - }, + child: _mealSources.isNotEmpty ? ListView.builder( + padding: const EdgeInsets.only(top: 10.0), + itemCount: _mealSources.length, + itemBuilder: (context, index) { + final mealSource = _mealSources[index]; + + return ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MealSourceDetailScreen( + mealSource: mealSource, + ), + ), + ).then((message) => refresh(message: message)); + }, + title: Text(mealSource.value), + subtitle: Text(mealSource.notes ?? ''), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon( + Icons.delete, + color: Colors.blue, + ), + onPressed: () async { + handleDeleteAction(mealSource); + }, + ), + ], + ), + ); + } + ) : const Center( + child: Text('You have not created any Meal Sources yet!'), ), ), ], diff --git a/logs/parse-server.err.2021-10-31 b/logs/parse-server.err.2021-10-31 new file mode 100644 index 0000000..e69de29 diff --git a/logs/parse-server.info.2021-10-31 b/logs/parse-server.info.2021-10-31 new file mode 100644 index 0000000..e69de29 diff --git a/pubspec.lock b/pubspec.lock index 9863a55..3e177e8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,20 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "30.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "2.7.0" args: dependency: transitive description: @@ -14,7 +28,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.1" + version: "2.8.2" boolean_selector: dependency: transitive description: @@ -22,13 +36,69 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.4" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.2" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.1.3" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: @@ -36,6 +106,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -43,6 +127,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" collection: dependency: transitive description: @@ -92,6 +183,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" crypto: dependency: transitive description: @@ -106,6 +204,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.3" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" dbus: dependency: transitive description: @@ -141,6 +246,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" flex_color_scheme: dependency: "direct main" description: @@ -170,6 +282,27 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" http: dependency: transitive description: @@ -177,6 +310,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.13.4" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" http_parser: dependency: transitive description: @@ -198,6 +338,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" js: dependency: transitive description: @@ -205,6 +352,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.3.0" lints: dependency: transitive description: @@ -212,13 +366,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10" + version: "0.12.11" meta: dependency: transitive description: @@ -226,6 +387,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" mime_type: dependency: transitive description: @@ -247,6 +415,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.3.0" + objectbox: + dependency: "direct main" + description: + name: objectbox + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + objectbox_flutter_libs: + dependency: "direct main" + description: + name: objectbox_flutter_libs + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + objectbox_generator: + dependency: "direct dev" + description: + name: objectbox_generator + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" package_info_plus: dependency: transitive description: @@ -316,7 +512,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.6" path_provider_linux: dependency: transitive description: @@ -373,6 +569,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" process: dependency: transitive description: @@ -387,6 +590,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.0.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" sembast: dependency: transitive description: @@ -443,11 +660,32 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.2" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" source_span: dependency: transitive description: @@ -483,6 +721,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" string_scanner: dependency: transitive description: @@ -510,7 +755,14 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.2" + version: "0.4.3" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" typed_data: dependency: transitive description: @@ -531,7 +783,14 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" web_socket_channel: dependency: transitive description: @@ -567,6 +826,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" sdks: dart: ">=2.14.0 <3.0.0" flutter: ">=2.5.0" diff --git a/pubspec.yaml b/pubspec.yaml index f1e788a..95d9cfd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,33 +1,37 @@ name: diameter description: A logging app for type 1 diabetics. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=2.12.0 <3.0.0' + sdk: ">=2.12.0 <3.0.0" dependencies: - parse_server_sdk_flutter: ^3.1.0 - flutter: - sdk: flutter - sqflite: ^2.0.0+4 - path_provider: ^2.0.5 - cupertino_icons: ^1.0.2 - flex_color_scheme: ^3.0.1 - shared_preferences: ^2.0.8 - intl: ^0.17.0 + parse_server_sdk_flutter: ^3.1.0 + flutter: + sdk: flutter + sqflite: ^2.0.0+4 + path_provider: ^2.0.5 + cupertino_icons: ^1.0.2 + flex_color_scheme: ^3.0.1 + shared_preferences: ^2.0.8 + intl: ^0.17.0 + objectbox: ^1.2.0 + objectbox_flutter_libs: any dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^1.0.4 - provider: ^6.0.1 + flutter_test: + sdk: flutter + flutter_lints: ^1.0.4 + provider: ^6.0.1 + build_runner: ^2.0.0 + objectbox_generator: any flutter: - uses-material-design: true - fonts: - - family: RobotoCondensed - fonts: - - asset: assets/fonts/RobotoCondensed-Regular.ttf + uses-material-design: true + fonts: + - family: RobotoCondensed + fonts: + - asset: assets/fonts/RobotoCondensed-Regular.ttf