switch from back4app to local store using objectbox
This commit is contained in:
parent
ca89ab4eff
commit
f7d727e070
3
TODO
3
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
|
||||
✔ use local database instead of back4app @done(21-11-07 18:53)
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<ViewWithProgressIndicator> {
|
||||
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,
|
||||
|
@ -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<void> 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),
|
||||
|
@ -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<Accuracy> box = objectBox.store.box<Accuracy>();
|
||||
|
||||
Accuracy(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
value = object.get<String>('value')!;
|
||||
forCarbsRatio = object.get<bool>('forCarbsRatio')!;
|
||||
forPortionSize = object.get<bool>('forPortionSize')!;
|
||||
confidenceRating = object.get<num>('confidenceRating') != null
|
||||
? object.get<num>('confidenceRating')!.toInt()
|
||||
: null;
|
||||
notes = object.get<String>('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<Accuracy> getAll() {
|
||||
QueryBuilder<Accuracy> 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<Accuracy> getAllForPortionSize() {
|
||||
QueryBuilder<Accuracy> allForPortionSize = box
|
||||
.query(Accuracy_.forPortionSize.equals(true))
|
||||
..order(Accuracy_.confidenceRating);
|
||||
return allForPortionSize.build().find();
|
||||
}
|
||||
|
||||
static Future<List<Accuracy>> fetchAll() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<List<Accuracy>> fetchAllForCarbsRatio() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<List<Accuracy>> fetchAllForPortionSize() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<Accuracy?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('Accuracy'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return Accuracy(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> 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<void> 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<void> delete() async {
|
||||
var accuracy = ParseObject('Accuracy')..objectId = objectId;
|
||||
await accuracy.delete();
|
||||
static List<Accuracy> getAllForCarbsRatio() {
|
||||
QueryBuilder<Accuracy> allForCarbsRatio = box
|
||||
.query(Accuracy_.forCarbsRatio.equals(true))
|
||||
..order(Accuracy_.confidenceRating);
|
||||
return allForCarbsRatio.build().find();
|
||||
}
|
||||
}
|
||||
|
@ -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<Basal> box = objectBox.store.box<Basal>();
|
||||
|
||||
Basal(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
startTime = object.get<DateTime>('startTime')!.toLocal();
|
||||
endTime = object.get<DateTime>('endTime')!.toLocal();
|
||||
units = object.get<num>('units')! / 100;
|
||||
basalProfile =
|
||||
object.get<ParseObject>('basalProfile')!.get<String>('objectId')!;
|
||||
}
|
||||
}
|
||||
int id;
|
||||
|
||||
static Future<Basal?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('Basal'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
@Property(type: PropertyType.date)
|
||||
DateTime startTime;
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return Basal(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
@Property(type: PropertyType.date)
|
||||
DateTime endTime;
|
||||
|
||||
static Future<List<Basal>> fetchAllForBasalProfile(
|
||||
BasalProfile basalProfile) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('Basal'))
|
||||
..whereEqualTo(
|
||||
'basalProfile',
|
||||
(ParseObject('BasalProfile')..objectId = basalProfile.objectId!)
|
||||
.toPointer())
|
||||
..orderByAscending('startTime');
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
double units;
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return apiResponse.results!.map((e) => Basal(e as ParseObject)).toList();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
final basalProfile = ToOne<BasalProfile>();
|
||||
|
||||
static Future<void> 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();
|
||||
}
|
||||
Basal({
|
||||
this.id = 0,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
this.units = 0,
|
||||
});
|
||||
|
||||
static Future<void> 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();
|
||||
}
|
||||
static Basal? get(int id) => box.get(id);
|
||||
static void put(Basal basal) => box.put(basal);
|
||||
static void remove(int id) => box.remove(id);
|
||||
|
||||
Future<void> delete() async {
|
||||
var basal = ParseObject('Basal')..objectId = objectId;
|
||||
await basal.delete();
|
||||
static List<Basal> getAllForProfile(int id) {
|
||||
QueryBuilder<Basal> builder = box.query()..order(Basal_.startTime);
|
||||
builder.link(Basal_.basalProfile, BasalProfile_.id.equals(id));
|
||||
return builder.build().find();
|
||||
}
|
||||
//
|
||||
// @override
|
||||
// List<DataCell> asDataTableCells(List<Widget>? actions) {
|
||||
// return [
|
||||
// DataCell(Text(DateTimeUtils.displayTime(startTime))),
|
||||
// DataCell(Text(DateTimeUtils.displayTime(endTime))),
|
||||
// DataCell(Text('${units.toString()} U')),
|
||||
// DataCell(
|
||||
// Row(
|
||||
// children: actions ?? [],
|
||||
// ),
|
||||
// ),
|
||||
// ];
|
||||
// }
|
||||
//
|
||||
// static List<DataColumn> 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'))),
|
||||
// ];
|
||||
// }
|
||||
}
|
||||
|
@ -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<List<Basal>> basalRates;
|
||||
late String? notes;
|
||||
static final Box<BasalProfile> box = objectBox.store.box<BasalProfile>();
|
||||
|
||||
BasalProfile(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
name = object.get<String>('name')!;
|
||||
active = object.get<bool>('active')!;
|
||||
basalRates = Basal.fetchAllForBasalProfile(this);
|
||||
notes = object.get<String>('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<BasalProfile> getAll() => box.getAll();
|
||||
static void put(BasalProfile basalProfile) => box.put(basalProfile);
|
||||
static void remove(int id) => box.remove(id);
|
||||
|
||||
static int activeCount() {
|
||||
Query<BasalProfile> query =
|
||||
box.query(BasalProfile_.active.equals(true)).build();
|
||||
return query.find().length;
|
||||
}
|
||||
|
||||
static Future<List<BasalProfile>> fetchAll() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<BasalProfile?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('BasalProfile'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return BasalProfile(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<int> getActiveCount() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<void> setAllInactive({String? exception}) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('BasalProfile'));
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
for (var basalProfile in apiResponse.results as List<ParseObject>) {
|
||||
basalProfile.set(
|
||||
'active', basalProfile.objectId == exception ? true : false);
|
||||
await basalProfile.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> 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<void> 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<void> 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());
|
||||
}
|
||||
}
|
||||
|
@ -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<Bolus> box = objectBox.store.box<Bolus>();
|
||||
|
||||
Bolus(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
startTime = object.get<DateTime>('startTime')!.toLocal();
|
||||
endTime = object.get<DateTime>('endTime')!.toLocal();
|
||||
units = object.get<num>('units')! / 100;
|
||||
carbs = object.get<num>('carbs')!.toDouble();
|
||||
mgPerDl = object.get<num>('mgPerDl') != null
|
||||
? object.get<num>('mgPerDl')!.toInt()
|
||||
: null;
|
||||
mmolPerL = object.get<num>('mmolPerL') != null
|
||||
? object.get<num>('mmolPerL')! / 100
|
||||
: null;
|
||||
bolusProfile =
|
||||
object.get<ParseObject>('bolusProfile')!.get<String>('objectId')!;
|
||||
}
|
||||
}
|
||||
int id;
|
||||
@Property(type: PropertyType.date)
|
||||
DateTime startTime;
|
||||
@Property(type: PropertyType.date)
|
||||
DateTime endTime;
|
||||
double units;
|
||||
double carbs;
|
||||
int? mgPerDl;
|
||||
double? mmolPerL;
|
||||
|
||||
static Future<Bolus?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('Bolus'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final bolusProfile = ToOne<BolusProfile>();
|
||||
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
Bolus({
|
||||
this.id = 0,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
this.units = 0,
|
||||
this.carbs = 0,
|
||||
this.mgPerDl,
|
||||
this.mmolPerL,
|
||||
});
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return Bolus(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
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 Future<List<Bolus>> fetchAllForBolusProfile(
|
||||
BolusProfile bolusProfile) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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 List<Bolus> getAllForProfile(int id) {
|
||||
QueryBuilder<Bolus> builder = box.query()..order(Bolus_.startTime);
|
||||
builder.link(Bolus_.bolusProfile, BolusProfile_.id.equals(id));
|
||||
return builder.build().find();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> 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<void> 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<void> delete() async {
|
||||
var bolus = ParseObject('Bolus')..objectId = objectId;
|
||||
await bolus.delete();
|
||||
}
|
||||
//
|
||||
// @override
|
||||
// List<DataCell> asDataTableCells(List<Widget>? 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<DataColumn> 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;
|
||||
// }
|
||||
}
|
||||
|
@ -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<List<Bolus>> bolusRates;
|
||||
late String? notes;
|
||||
static final Box<BolusProfile> box = objectBox.store.box<BolusProfile>();
|
||||
|
||||
BolusProfile(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
name = object.get<String>('name')!;
|
||||
active = object.get<bool>('active')!;
|
||||
bolusRates = Bolus.fetchAllForBolusProfile(this);
|
||||
notes = object.get<String>('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<BolusProfile> getAll() => box.getAll();
|
||||
static void put(BolusProfile bolusProfile) => box.put(bolusProfile);
|
||||
static void remove(int id) => box.remove(id);
|
||||
|
||||
static int activeCount() {
|
||||
Query<BolusProfile> query =
|
||||
box.query(BolusProfile_.active.equals(true)).build();
|
||||
return query.find().length;
|
||||
}
|
||||
|
||||
static Future<List<BolusProfile>> fetchAll() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<BolusProfile?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('BolusProfile'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return BolusProfile(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<int> getActiveCount() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<void> setAllInactive({String? exception}) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('BolusProfile'));
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
for (var bolusProfile in apiResponse.results as List<ParseObject>) {
|
||||
bolusProfile.set(
|
||||
'active', bolusProfile.objectId == exception ? true : false);
|
||||
await bolusProfile.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> 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<void> 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<void> 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());
|
||||
}
|
||||
}
|
||||
|
@ -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<List<LogEvent>> events;
|
||||
late Future<List<LogEvent>> endedEvents;
|
||||
late Future<List<LogMeal>> meals;
|
||||
static final Box<LogEntry> box = objectBox.store.box<LogEntry>();
|
||||
|
||||
LogEntry(ParseObject object) {
|
||||
objectId = object.get<String>('objectId');
|
||||
time = object.get<DateTime>('time')!.toLocal();
|
||||
mgPerDl = object.get<num>('mgPerDl') != null
|
||||
? object.get<num>('mgPerDl')!.toInt()
|
||||
: null;
|
||||
mmolPerL = object.get<num>('mmolPerL') != null
|
||||
? object.get<num>('mmolPerL')!.toDouble()
|
||||
: null;
|
||||
bolusGlucose = object.get<num>('bolusGlucose') != null
|
||||
? object.get<num>('bolusGlucose')!.toDouble()
|
||||
: null;
|
||||
delayedBolusDuration = object.get<num>('delayedBolusDuration') != null
|
||||
? object.get<num>('delayedBolusDuration')!.toInt()
|
||||
: null;
|
||||
delayedBolusRatio = object.get<num>('delayedBolusRatio') != null
|
||||
? object.get<num>('delayedBolusRatio')!.toDouble()
|
||||
: null;
|
||||
events = LogEvent.fetchAllForLogEntry(this);
|
||||
endedEvents = LogEvent.fetchAllEndedByEntry(this);
|
||||
meals = LogMeal.fetchAllForLogEntry(this);
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
int id;
|
||||
|
||||
static Future<Map<DateTime, List<LogEntry>>> 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<LogEvent>();
|
||||
|
||||
@Backlink('endLogEntry')
|
||||
final endedEvents = ToMany<LogEvent>();
|
||||
|
||||
@Backlink('logEntry')
|
||||
final meals = ToMany<LogMeal>();
|
||||
|
||||
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<LogEntry> getAll() => box.getAll();
|
||||
static void put(LogEntry logEntry) => box.put(logEntry);
|
||||
static void remove(int id) => box.remove(id);
|
||||
|
||||
static Map<DateTime, List<LogEntry>> getDailyEntryMap() {
|
||||
Map<DateTime, List<LogEntry>> dateMap = <DateTime, List<LogEntry>>{};
|
||||
List<LogEntry> entries = await fetchAll();
|
||||
|
||||
QueryBuilder<LogEntry> allByDate = box.query()..order(LogEntry_.time, flags: Order.descending);
|
||||
List<LogEntry> entries = allByDate.build().find();
|
||||
DateTime? date;
|
||||
|
||||
for (LogEntry entry in entries) {
|
||||
@ -54,133 +59,4 @@ class LogEntry {
|
||||
|
||||
return dateMap;
|
||||
}
|
||||
|
||||
static Future<List<LogEntry>> fetchAllForRange(DateTimeRange range) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<List<LogEntry>> fetchAll() async {
|
||||
// TODO: consider adding pagination/lazy loading here
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<LogEntry?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('LogEntry'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return LogEntry(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> 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<void> 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<void> delete() async {
|
||||
var logEntry = ParseObject('LogEntry')..objectId = objectId;
|
||||
await logEntry.delete();
|
||||
}
|
||||
}
|
||||
|
@ -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<LogEvent> box = objectBox.store.box<LogEvent>();
|
||||
|
||||
LogEvent(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
logEntry = object.get<ParseObject>('logEntry')!.get<String>('objectId')!;
|
||||
endLogEntry =
|
||||
object.get<ParseObject>('endLogEntry')?.get<String>('objectId');
|
||||
eventType =
|
||||
object.get<ParseObject>('eventType')!.get<String>('objectId')!;
|
||||
time = object.get<DateTime>('time')!.toLocal();
|
||||
endTime = object.get<DateTime>('endTime')?.toLocal();
|
||||
hasEndTime = object.get<bool>('hasEndTime')!;
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
}
|
||||
int id;
|
||||
|
||||
static Future<LogEvent?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('LogEvent'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
@Property(type: PropertyType.date)
|
||||
DateTime time;
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return LogEvent(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
@Property(type: PropertyType.date)
|
||||
DateTime? endTime;
|
||||
|
||||
static Future<List<LogEvent>> fetchAllActive() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('LogEvent'))
|
||||
..whereEqualTo('hasEndTime', true)
|
||||
..whereEqualTo('endTime', null);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
bool hasEndTime;
|
||||
String? notes;
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return apiResponse.results!
|
||||
.map((e) => LogEvent(e as ParseObject))
|
||||
.toList();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
final logEntry = ToOne<LogEntry>();
|
||||
final endLogEntry = ToOne<LogEntry>();
|
||||
final eventType = ToOne<LogEventType>();
|
||||
|
||||
static Future<List<LogEvent>> fetchAllForLogEntry(LogEntry logEntry) async {
|
||||
QueryBuilder<ParseObject> query = QueryBuilder<ParseObject>(
|
||||
ParseObject('LogEvent'))
|
||||
..whereEqualTo('logEntry',
|
||||
(ParseObject('LogEntry')..objectId = logEntry.objectId!).toPointer());
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
LogEvent({
|
||||
this.id = 0,
|
||||
required this.time,
|
||||
this.endTime,
|
||||
this.hasEndTime = false,
|
||||
this.notes,
|
||||
});
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return apiResponse.results!
|
||||
.map((e) => LogEvent(e as ParseObject))
|
||||
.toList();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
static LogEvent? get(int id) => box.get(id);
|
||||
static List<LogEvent> getAll() => box.getAll();
|
||||
static void put(LogEvent logEvent) => box.put(logEvent);
|
||||
static void remove(int id) => box.remove(id);
|
||||
|
||||
static Future<List<LogEvent>> fetchAllEndedByEntry(LogEntry logEntry) async {
|
||||
QueryBuilder<ParseObject> query = QueryBuilder<ParseObject>(
|
||||
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 List<LogEvent> getAllOngoing() {
|
||||
QueryBuilder<LogEvent> query =
|
||||
box.query(LogEvent_.hasEndTime.equals(true) & LogEvent_.endTime.isNull())..order(LogEvent_.time);
|
||||
return query.build().find();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> 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<void> 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<void> delete() async {
|
||||
var logEvent = ParseObject('LogEvent')..objectId = objectId;
|
||||
await logEvent.delete();
|
||||
}
|
||||
//
|
||||
// @override
|
||||
// List<DataCell> asDataTableCells(List<Widget> actions,
|
||||
// {List<LogEventType>? 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<DataColumn> 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'))),
|
||||
// ];
|
||||
// }
|
||||
}
|
||||
|
@ -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<LogEventType> box = objectBox.store.box<LogEventType>();
|
||||
|
||||
LogEventType(ParseObject object) {
|
||||
objectId = object.get<String>('objectId');
|
||||
value = object.get<String>('value')!;
|
||||
hasEndTime = object.get<bool>('hasEndTime')!;
|
||||
defaultReminderDuration = object.get<num>('defaultReminderDuration') != null
|
||||
? object.get<num>('defaultReminderDuration')!.toInt()
|
||||
: null;
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
int id;
|
||||
String value;
|
||||
bool hasEndTime;
|
||||
int? defaultReminderDuration;
|
||||
String? notes;
|
||||
|
||||
static Future<List<LogEventType>> fetchAll() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<LogEventType?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('LogEventType'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return LogEventType(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> 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<void> 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<void> delete() async {
|
||||
var logEventType = ParseObject('LogEventType')..objectId = objectId;
|
||||
await logEventType.delete();
|
||||
}
|
||||
static LogEventType? get(int id) => box.get(id);
|
||||
static List<LogEventType> getAll() => box.getAll();
|
||||
static void put(LogEventType logEventType) => box.put(logEventType);
|
||||
static void remove(int id) => box.remove(id);
|
||||
}
|
||||
|
@ -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<LogMeal> box = objectBox.store.box<LogMeal>();
|
||||
|
||||
LogMeal(ParseObject object) {
|
||||
objectId = object.get<String>('objectId');
|
||||
logEntry = object.get<ParseObject>('logEntry')!.get<String>('objectId')!;
|
||||
meal = object.get<ParseObject>('meal')?.get<String>('objectId');
|
||||
value = object.get<String>('value')!;
|
||||
source = object.get<ParseObject>('source')?.get<String>('objectId');
|
||||
category = object.get<ParseObject>('category')?.get<String>('objectId');
|
||||
portionType = object.get<ParseObject>('portionType')?.get<String>('objectId');
|
||||
carbsRatio = object.get<num>('carbsRatio')?.toDouble();
|
||||
portionSize = object.get<num>('portionSize')?.toDouble();
|
||||
carbsPerPortion = object.get<num>('carbsPerPortion')?.toDouble();
|
||||
portionSizeAccuracy = object.get<ParseObject>('portionSizeAccuracy')?.get<String>('objectId');
|
||||
carbsRatioAccuracy = object.get<ParseObject>('carbsRatioAccuracy')?.get<String>('objectId');
|
||||
bolus = object.get<num>('bolus')?.toDouble();
|
||||
delayedBolusDuration = object.get<num>('delayedBolusDuration')?.toInt();
|
||||
delayedBolusRate = object.get<num>('delayedBolusRate')?.toDouble();
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
int id;
|
||||
String value;
|
||||
double? carbsRatio;
|
||||
double? portionSize;
|
||||
double? carbsPerPortion;
|
||||
double? bolus;
|
||||
int? delayedBolusDuration;
|
||||
double? delayedBolusRate;
|
||||
String? notes;
|
||||
|
||||
static Future<LogMeal?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('LogMeal'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
final logEntry = ToOne<LogEntry>();
|
||||
final meal = ToOne<Meal>();
|
||||
final mealSource = ToOne<MealSource>();
|
||||
final mealCategory = ToOne<MealCategory>();
|
||||
final mealPortionType = ToOne<MealPortionType>();
|
||||
final portionSizeAccuracy = ToOne<Accuracy>();
|
||||
final carbsRatioAccuracy = ToOne<Accuracy>();
|
||||
|
||||
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<List<LogMeal>> fetchAllForLogEntry(LogEntry logEntry) async {
|
||||
QueryBuilder<ParseObject> query = QueryBuilder<ParseObject>(
|
||||
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<void> 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<void> 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<void> delete() async {
|
||||
var logMeal = ParseObject('LogMeal')..objectId = objectId;
|
||||
await logMeal.delete();
|
||||
}
|
||||
|
||||
@override
|
||||
List<DataCell> asDataTableCells(List<Widget>? 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<DataColumn> 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<LogMeal> getAll() => box.getAll();
|
||||
static void put(LogMeal logMeal) => box.put(logMeal);
|
||||
static void remove(int id) => box.remove(id);
|
||||
}
|
||||
|
@ -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<Meal> box = objectBox.store.box<Meal>();
|
||||
|
||||
Meal(ParseObject object) {
|
||||
objectId = object.get<String>('objectId');
|
||||
value = object.get<String>('value')!;
|
||||
source = object.get<ParseObject>('source') != null
|
||||
? object.get<ParseObject>('source')!.get<String>('objectId')
|
||||
: null;
|
||||
category = object.get<ParseObject>('category') != null
|
||||
? object.get<ParseObject>('category')!.get<String>('objectId')
|
||||
: null;
|
||||
portionType = object.get<ParseObject>('portionType') != null
|
||||
? object.get<ParseObject>('portionType')!.get<String>('objectId')
|
||||
: null;
|
||||
carbsRatio = object.get<num>('carbsRatio') != null
|
||||
? object.get<num>('carbsRatio')!.toDouble()
|
||||
: null;
|
||||
portionSize = object.get<num>('portionSize') != null
|
||||
? object.get<num>('portionSize')!.toDouble()
|
||||
: null;
|
||||
carbsPerPortion = object.get<num>('carbsPerPortion') != null
|
||||
? object.get<num>('carbsPerPortion')!.toDouble()
|
||||
: null;
|
||||
portionSizeAccuracy = object.get<ParseObject>('portionSizeAccuracy') != null
|
||||
? object
|
||||
.get<ParseObject>('portionSizeAccuracy')!
|
||||
.get<String>('objectId')
|
||||
: null;
|
||||
carbsRatioAccuracy = object.get<ParseObject>('carbsRatioAccuracy') != null
|
||||
? object.get<ParseObject>('carbsRatioAccuracy')!.get<String>('objectId')
|
||||
: null;
|
||||
delayedBolusDuration = object.get<num>('delayedBolusDuration') != null
|
||||
? object.get<num>('delayedBolusDuration')!.toInt()
|
||||
: null;
|
||||
delayedBolusRate = object.get<num>('delayedBolusRate') != null
|
||||
? object.get<num>('delayedBolusRate')!.toDouble()
|
||||
: null;
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
int id;
|
||||
String value;
|
||||
double? carbsRatio;
|
||||
double? portionSize;
|
||||
double? carbsPerPortion;
|
||||
int? delayedBolusDuration;
|
||||
double? delayedBolusRate;
|
||||
String? notes;
|
||||
|
||||
static Future<List<Meal>> fetchAll() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<MealSource>();
|
||||
final mealCategory = ToOne<MealCategory>();
|
||||
final mealPortionType = ToOne<MealPortionType>();
|
||||
final portionSizeAccuracy = ToOne<Accuracy>();
|
||||
final carbsRatioAccuracy = ToOne<Accuracy>();
|
||||
|
||||
static Future<Meal?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<void> 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<void> 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<void> delete() async {
|
||||
var meal = ParseObject('Meal')..objectId = objectId;
|
||||
await meal.delete();
|
||||
}
|
||||
static Meal? get(int id) => box.get(id);
|
||||
static List<Meal> getAll() => box.getAll();
|
||||
static void put(Meal meal) => box.put(meal);
|
||||
static void remove(int id) => box.remove(id);
|
||||
}
|
||||
|
@ -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<MealCategory> box = objectBox.store.box<MealCategory>();
|
||||
|
||||
MealCategory(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
value = object.get<String>('value')!;
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
}
|
||||
int id;
|
||||
String value;
|
||||
String? notes;
|
||||
|
||||
static Future<List<MealCategory>> fetchAll() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<MealCategory?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('MealCategory'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return MealCategory(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> save({
|
||||
required String value,
|
||||
String? notes,
|
||||
}) async {
|
||||
final mealCategory = ParseObject('MealCategory')
|
||||
..set('value', value)
|
||||
..set('notes', notes);
|
||||
await mealCategory.save();
|
||||
}
|
||||
|
||||
static Future<void> 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<void> delete() async {
|
||||
var mealCategory = ParseObject('MealCategory')..objectId = objectId;
|
||||
await mealCategory.delete();
|
||||
}
|
||||
static MealCategory? get(int id) => box.get(id);
|
||||
static List<MealCategory> getAll() => box.getAll();
|
||||
static void put(MealCategory mealCategory) => box.put(mealCategory);
|
||||
static void remove(int id) => box.remove(id);
|
||||
}
|
||||
|
@ -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<MealPortionType> box = objectBox.store.box<MealPortionType>();
|
||||
|
||||
MealPortionType(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
value = object.get<String>('value')!;
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
}
|
||||
int id;
|
||||
String value;
|
||||
String? notes;
|
||||
|
||||
static Future<List<MealPortionType>> fetchAll() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(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<ParseObject>;
|
||||
return apiResponse.results!.map((e) => MealPortionType(e as ParseObject)).toList();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
static Future<MealPortionType?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('MealPortionType'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return MealPortionType(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> save({
|
||||
required String value,
|
||||
String? notes,
|
||||
}) async {
|
||||
final mealPortionType = ParseObject('MealPortionType')
|
||||
..set('value', value)
|
||||
..set('notes', notes);
|
||||
await mealPortionType.save();
|
||||
}
|
||||
|
||||
static Future<void> 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<void> delete() async {
|
||||
var mealPortionType = ParseObject('MealPortionType')..objectId = objectId;
|
||||
await mealPortionType.delete();
|
||||
}
|
||||
static MealPortionType? get(int id) => box.get(id);
|
||||
static List<MealPortionType> getAll() => box.getAll();
|
||||
static void put(MealPortionType mealPortionType) => box.put(mealPortionType);
|
||||
static void remove(int id) => box.remove(id);
|
||||
}
|
||||
|
@ -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<MealSource> box = objectBox.store.box<MealSource>();
|
||||
|
||||
MealSource(ParseObject? object) {
|
||||
if (object != null) {
|
||||
objectId = object.get<String>('objectId');
|
||||
value = object.get<String>('value')!;
|
||||
defaultCarbsRatioAccuracy =
|
||||
object.get<ParseObject>('defaultCarbsRatioAccuracy') != null
|
||||
? object
|
||||
.get<ParseObject>('defaultCarbsRatioAccuracy')!
|
||||
.get<String>('objectId')
|
||||
: null;
|
||||
defaultPortionSizeAccuracy =
|
||||
object.get<ParseObject>('defaultPortionSizeAccuracy') != null
|
||||
? object
|
||||
.get<ParseObject>('defaultPortionSizeAccuracy')!
|
||||
.get<String>('objectId')
|
||||
: null;
|
||||
defaultMealCategory =
|
||||
object.get<ParseObject>('defaultMealCategory') != null
|
||||
? object
|
||||
.get<ParseObject>('defaultMealCategory')!
|
||||
.get<String>('objectId')
|
||||
: null;
|
||||
defaultMealPortionType =
|
||||
object.get<ParseObject>('defaultMealPortionType') != null
|
||||
? object
|
||||
.get<ParseObject>('defaultMealPortionType')!
|
||||
.get<String>('objectId')
|
||||
: null;
|
||||
notes = object.get<String>('notes');
|
||||
}
|
||||
}
|
||||
int id;
|
||||
String value;
|
||||
String? notes;
|
||||
|
||||
static Future<List<MealSource>> fetchAll() async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('MealSource'));
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
final defaultMealCategory = ToOne<MealCategory>();
|
||||
final defaultMealPortionType = ToOne<MealPortionType>();
|
||||
final defaultCarbsRatioAccuracy = ToOne<Accuracy>();
|
||||
final defaultPortionSizeAccuracy = ToOne<Accuracy>();
|
||||
|
||||
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<MealSource?> get(String objectId) async {
|
||||
QueryBuilder<ParseObject> query =
|
||||
QueryBuilder<ParseObject>(ParseObject('MealSource'))
|
||||
..whereEqualTo('objectId', objectId);
|
||||
final ParseResponse apiResponse = await query.query();
|
||||
|
||||
if (apiResponse.success && apiResponse.results != null) {
|
||||
return MealSource(apiResponse.result.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> 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<void> 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<void> delete() async {
|
||||
var mealSource = ParseObject('MealSource')..objectId = objectId;
|
||||
await mealSource.delete();
|
||||
}
|
||||
static MealSource? get(int id) => box.get(id);
|
||||
static List<MealSource> getAll() => box.getAll();
|
||||
static void put(MealSource mealSource) => box.put(mealSource);
|
||||
static void remove(int id) => box.remove(id);
|
||||
}
|
||||
|
14
lib/object_box.dart
Normal file
14
lib/object_box.dart
Normal file
@ -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<ObjectBox> create() async {
|
||||
final store = await openStore();
|
||||
return ObjectBox._create(store);
|
||||
}
|
||||
}
|
648
lib/objectbox-model.json
Normal file
648
lib/objectbox-model.json
Normal file
@ -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
|
||||
}
|
1694
lib/objectbox.g.dart
Normal file
1694
lib/objectbox.g.dart
Normal file
File diff suppressed because it is too large
Load Diff
@ -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<AccuracyDetailScreen> {
|
||||
Accuracy? _accuracy;
|
||||
bool _isNew = true;
|
||||
bool _isSaving = false;
|
||||
|
||||
final GlobalKey<FormState> _accuracyForm = GlobalKey<FormState>();
|
||||
|
||||
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(
|
||||
Accuracy.box.put(Accuracy(
|
||||
id: widget.id,
|
||||
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');
|
||||
));
|
||||
Navigator.pop(context, '${_isNew ? 'New' : ''} Accuracy saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
@ -69,25 +73,23 @@ class _AccuracyDetailScreenState extends State<AccuracyDetailScreen> {
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
bool isNew = widget.accuracy == null;
|
||||
|
||||
if (showConfirmationDialogOnCancel &&
|
||||
(isNew &&
|
||||
(_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 ||
|
||||
(!_isNew &&
|
||||
(_forCarbsRatio != _accuracy!.forCarbsRatio ||
|
||||
_forPortionSize != _accuracy!.forPortionSize ||
|
||||
_accuracy!.value != _valueController.text ||
|
||||
int.tryParse(_confidenceRatingController.text) !=
|
||||
widget.accuracy!.confidenceRating ||
|
||||
(widget.accuracy!.notes ?? '') != _notesController.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<AccuracyDetailScreen> {
|
||||
|
||||
@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(
|
||||
|
@ -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<AccuracyListScreen> {
|
||||
late Future<List<Accuracy>?> _accuracies;
|
||||
List<Accuracy> _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<AccuracyListScreen> {
|
||||
}
|
||||
|
||||
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<AccuracyListScreen> {
|
||||
}
|
||||
|
||||
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,39 +83,20 @@ class _AccuracyListScreenState extends State<AccuracyListScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: FutureBuilder<List<Accuracy>?>(
|
||||
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(
|
||||
child: _accuracies.isNotEmpty ? ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
itemCount: snapshot.data != null
|
||||
? snapshot.data!.length
|
||||
: 0,
|
||||
itemCount: _accuracies.length,
|
||||
itemBuilder: (context, index) {
|
||||
final accuracy = snapshot.data![index];
|
||||
final accuracy = _accuracies[index];
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
AccuracyDetailScreen(
|
||||
accuracy: accuracy),
|
||||
AccuracyDetailScreen(id: accuracy.id),
|
||||
),
|
||||
).then(
|
||||
(message) => refresh(message: message));
|
||||
).then((message) => refresh(message: message));
|
||||
},
|
||||
title: Text(accuracy.value),
|
||||
leading: Row(
|
||||
@ -137,36 +114,35 @@ class _AccuracyListScreenState extends State<AccuracyListScreen> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.square_foot,
|
||||
icon: Icon(
|
||||
Icons.square_foot,
|
||||
color: accuracy.forPortionSize
|
||||
? Colors.blue
|
||||
: Colors.grey.shade300),
|
||||
onPressed: () =>
|
||||
handleToggleForPortionSizeAction(
|
||||
accuracy)),
|
||||
? Theme.of(context).toggleableActiveColor
|
||||
: Theme.of(context).highlightColor,
|
||||
),
|
||||
onPressed: () => handleToggleForPortionSizeAction(accuracy),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.pie_chart,
|
||||
icon: Icon(
|
||||
Icons.pie_chart,
|
||||
color: accuracy.forCarbsRatio
|
||||
? Colors.blue
|
||||
: Colors.grey.shade300),
|
||||
onPressed: () =>
|
||||
handleToggleForCarbsRatioAction(
|
||||
accuracy),
|
||||
? Theme.of(context).toggleableActiveColor
|
||||
: Theme.of(context).highlightColor,
|
||||
),
|
||||
onPressed: () => handleToggleForCarbsRatioAction(accuracy),
|
||||
),
|
||||
const SizedBox(width: 24),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.delete,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () =>
|
||||
handleDeleteAction(accuracy),
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: () => handleDeleteAction(accuracy),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}));
|
||||
}),
|
||||
}
|
||||
) : const Center(
|
||||
child: Text('You have not created any Accuracies yet!'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -176,7 +152,8 @@ class _AccuracyListScreenState extends State<AccuracyListScreen> {
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const AccuracyDetailScreen(),
|
||||
)).then((message) => refresh(message: message));
|
||||
),
|
||||
).then((message) => refresh(message: message));
|
||||
},
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
|
@ -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<BasalDetailScreen> {
|
||||
Basal? _basal;
|
||||
bool _isNew = true;
|
||||
bool _isSaving = false;
|
||||
|
||||
final GlobalKey<FormState> _basalForm = GlobalKey<FormState>();
|
||||
|
||||
TimeOfDay _startTime = const TimeOfDay(hour: 0, minute: 0);
|
||||
TimeOfDay _endTime = const TimeOfDay(hour: 0, minute: 0);
|
||||
|
||||
@ -37,27 +42,37 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
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<BasalDetailScreen> {
|
||||
|
||||
Future<String?> validateTimePeriod() async {
|
||||
String? error;
|
||||
List<Basal> basalRates =
|
||||
await Basal.fetchAllForBasalProfile(widget.basalProfile);
|
||||
List<Basal> 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<BasalDetailScreen> {
|
||||
|
||||
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<BasalDetailScreen> {
|
||||
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),
|
||||
Basal basal = Basal(
|
||||
id: widget.id,
|
||||
startTime: DateTimeUtils.convertTimeOfDayToDateTime(_startTime),
|
||||
endTime: DateTimeUtils.convertTimeOfDayToDateTime(_endTime),
|
||||
units: double.parse(_unitsController.text),
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Basal Rate saved');
|
||||
basal.basalProfile.targetId = widget.basalProfileId;
|
||||
Basal.put(basal);
|
||||
Navigator.pop(context, '${_isNew ? 'New' : ''} Basal Rate saved');
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -148,24 +153,23 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
}
|
||||
|
||||
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<BasalDetailScreen> {
|
||||
|
||||
@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(
|
||||
|
@ -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<Basal> 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<BasalListScreen> {
|
||||
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<BasalListScreen> {
|
||||
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<BasalListScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
String? validateTimePeriod(List<Basal> basalRates, int index) {
|
||||
String? validateTimePeriod(int index) {
|
||||
List<Basal> basalRates = widget.basalRates;
|
||||
Basal basal = basalRates[index];
|
||||
|
||||
// TODO: use queries for all this
|
||||
// check for gaps
|
||||
if (index == 0 &&
|
||||
(basal.startTime.hour != 0 || basal.startTime.minute != 0)) {
|
||||
@ -102,38 +107,19 @@ class _BasalListScreenState extends State<BasalListScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
refresh();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
FutureBuilder<List<Basal>>(
|
||||
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(
|
||||
widget.basalRates.isNotEmpty ? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount:
|
||||
snapshot.data != null ? snapshot.data!.length : 0,
|
||||
itemCount: widget.basalRates.length,
|
||||
itemBuilder: (context, index) {
|
||||
final basal = snapshot.data![index];
|
||||
final error =
|
||||
validateTimePeriod(snapshot.data!, index);
|
||||
final basal = widget.basalRates[index];
|
||||
final error = validateTimePeriod(index);
|
||||
return ListTile(
|
||||
tileColor:
|
||||
error != null ? Colors.red.shade100 : null,
|
||||
tileColor: error != null ? Colors.red.shade100 : null,
|
||||
onTap: () {
|
||||
handleEditAction(basal);
|
||||
},
|
||||
@ -148,8 +134,7 @@ class _BasalListScreenState extends State<BasalListScreen> {
|
||||
],
|
||||
),
|
||||
subtitle: error != null
|
||||
? Text(error,
|
||||
style: const TextStyle(color: Colors.red))
|
||||
? Text(error, style: const TextStyle(color: Colors.red))
|
||||
: Container(),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -165,9 +150,8 @@ class _BasalListScreenState extends State<BasalListScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
) : const Center(
|
||||
child: Text('You have not created any Basal Rates yet!'),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -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<BasalProfileDetailScreen> {
|
||||
BasalProfile? _basalProfile;
|
||||
List<Basal> _basalRates = [];
|
||||
bool _isNew = true;
|
||||
bool _isSaving = false;
|
||||
|
||||
final GlobalKey<FormState> _basalProfileForm = GlobalKey<FormState>();
|
||||
|
||||
late FloatingActionButton addBasalButton;
|
||||
@ -40,28 +44,30 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
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<BasalProfileDetailScreen> {
|
||||
bottomNav = detailBottomRow;
|
||||
}
|
||||
|
||||
void refresh({String? message}) {
|
||||
void reload({String? message}) {
|
||||
if (widget.id != 0) {
|
||||
setState(() {
|
||||
if (widget.basalProfile != null) {
|
||||
widget.basalProfile!.basalRates =
|
||||
Basal.fetchAllForBasalProfile(widget.basalProfile!);
|
||||
}
|
||||
_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<BasalProfileDetailScreen> {
|
||||
}
|
||||
|
||||
Future<void> 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<BasalProfileDetailScreen> {
|
||||
_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<BasalProfileDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void handleAddNew() async {
|
||||
List<Basal> 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<BasalProfileDetailScreen> {
|
||||
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<BasalProfileDetailScreen> {
|
||||
});
|
||||
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!,
|
||||
BasalProfile.put(BasalProfile(
|
||||
id: widget.id,
|
||||
name: _nameController.text,
|
||||
active: _active,
|
||||
notes: _notesController.text,
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Basal Profile saved');
|
||||
));
|
||||
Navigator.pop(context, '${_isNew ? 'New' : ''} Basal Profile saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
@ -233,20 +232,18 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
}
|
||||
|
||||
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<BasalProfileDetailScreen> {
|
||||
}
|
||||
|
||||
void renderTabButtons(index) {
|
||||
if (widget.basalProfile != null) {
|
||||
if (_basalProfile != null) {
|
||||
setState(() {
|
||||
switch (index) {
|
||||
case 1:
|
||||
@ -274,9 +271,8 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
|
||||
@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(() {
|
||||
@ -327,15 +323,14 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
),
|
||||
];
|
||||
|
||||
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<BasalProfileDetailScreen> {
|
||||
body: TabBarView(children: tabs),
|
||||
bottomNavigationBar: bottomNav,
|
||||
floatingActionButton: actionButton,
|
||||
floatingActionButtonLocation:
|
||||
FloatingActionButtonLocation.endFloat,
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
@ -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<BasalProfileListScreen> {
|
||||
late Future<List<BasalProfile>?> _basalProfiles;
|
||||
late List<BasalProfile> _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<BasalProfileListScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
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<BasalProfileListScreen> {
|
||||
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<BasalProfileListScreen> {
|
||||
}
|
||||
|
||||
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<BasalProfileListScreen> {
|
||||
}
|
||||
|
||||
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<BasalProfileListScreen> {
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => BasalProfileDetailScreen(
|
||||
basalProfile: basalProfile, active: active),
|
||||
id: basalProfile?.id ?? 0, active: active),
|
||||
),
|
||||
).then((message) => refresh(message: message));
|
||||
}
|
||||
@ -155,25 +155,11 @@ class _BasalProfileListScreenState extends State<BasalProfileListScreen> {
|
||||
children: [
|
||||
banner,
|
||||
Expanded(
|
||||
child: FutureBuilder<List<BasalProfile>?>(
|
||||
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,
|
||||
child: _basalProfiles.isNotEmpty ? ListView.builder(
|
||||
itemCount: _basalProfiles.length,
|
||||
itemBuilder: (context, index) {
|
||||
final basalProfile = snapshot.data![index];
|
||||
final basalProfile = _basalProfiles[index];
|
||||
|
||||
return ListTile(
|
||||
tileColor: basalProfile.active
|
||||
? Colors.green.shade100
|
||||
@ -202,9 +188,8 @@ class _BasalProfileListScreenState extends State<BasalProfileListScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
) : const Center(
|
||||
child: Text('You have not created any Basal Profiles yet!'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -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<BolusDetailScreen> {
|
||||
Bolus? _bolus;
|
||||
bool _isNew = true;
|
||||
bool _isSaving = false;
|
||||
|
||||
final GlobalKey<FormState> _bolusForm = GlobalKey<FormState>();
|
||||
|
||||
TimeOfDay _startTime = const TimeOfDay(hour: 0, minute: 0);
|
||||
@ -43,30 +47,41 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
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<BolusDetailScreen> {
|
||||
|
||||
Future<String?> validateTimePeriod() async {
|
||||
String? error;
|
||||
List<Bolus> bolusRates =
|
||||
await Bolus.fetchAllForBolusProfile(widget.bolusProfile);
|
||||
List<Bolus> bolusRates = Bolus.getAllForProfile(widget.bolusProfileId);
|
||||
// BolusProfile.get(widget.bolusProfileId)?.bolusRates ?? [];
|
||||
|
||||
// TODO use a query for the following checks instead?
|
||||
// check for duplicates
|
||||
if (bolusRates
|
||||
.where((other) =>
|
||||
(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<BolusDetailScreen> {
|
||||
|
||||
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<BolusDetailScreen> {
|
||||
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),
|
||||
Bolus bolus = Bolus(
|
||||
id: widget.id,
|
||||
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),
|
||||
units: double.tryParse(_unitsController.text) ?? 0,
|
||||
carbs: double.tryParse(_carbsController.text) ?? 0,
|
||||
mgPerDl: int.tryParse(_mgPerDlController.text),
|
||||
mmolPerL: double.parse(_mmolPerLController.text),
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Bolus Rate saved');
|
||||
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<BolusDetailScreen> {
|
||||
(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<BolusDetailScreen> {
|
||||
|
||||
@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(
|
||||
|
@ -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<Bolus> 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<BolusListScreen> {
|
||||
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<BolusListScreen> {
|
||||
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<BolusListScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
String? validateTimePeriod(List<Bolus> bolusRates, int index) {
|
||||
String? validateTimePeriod(int index) {
|
||||
List<Bolus> bolusRates = widget.bolusRates;
|
||||
Bolus bolus = bolusRates[index];
|
||||
|
||||
// TODO: use queries for all this
|
||||
// check for gaps
|
||||
if (index == 0 &&
|
||||
(bolus.startTime.toLocal().hour != 0 || bolus.startTime.minute != 0)) {
|
||||
@ -103,40 +105,21 @@ class _BolusListScreenState extends State<BolusListScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
refresh();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
child: Column(
|
||||
children: [
|
||||
FutureBuilder<List<Bolus>>(
|
||||
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(
|
||||
widget.bolusRates.isNotEmpty ? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount:
|
||||
snapshot.data != null ? snapshot.data!.length : 0,
|
||||
itemCount: widget.bolusRates.length,
|
||||
itemBuilder: (context, index) {
|
||||
final bolus = snapshot.data![index];
|
||||
final error =
|
||||
validateTimePeriod(snapshot.data!, index);
|
||||
final bolus = widget.bolusRates[index];
|
||||
final error = validateTimePeriod(index);
|
||||
return ListTile(
|
||||
isThreeLine: true,
|
||||
tileColor:
|
||||
error != null ? Colors.red.shade100 : null,
|
||||
tileColor: error != null ? Colors.red.shade100 : null,
|
||||
onTap: () {
|
||||
handleEditAction(bolus);
|
||||
},
|
||||
@ -150,8 +133,7 @@ class _BolusListScreenState extends State<BolusListScreen> {
|
||||
'${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))
|
||||
style: const TextStyle(color: Colors.red))
|
||||
: const Text('')
|
||||
]),
|
||||
trailing: Row(
|
||||
@ -168,9 +150,8 @@ class _BolusListScreenState extends State<BolusListScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
) : const Center(
|
||||
child: Text('You have not created any Bolus Rates yet!'),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -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<BolusProfileDetailScreen> {
|
||||
BolusProfile? _bolusProfile;
|
||||
List<Bolus> _bolusRates = [];
|
||||
bool _isNew = true;
|
||||
bool _isSaving = false;
|
||||
|
||||
final GlobalKey<FormState> _bolusProfileForm = GlobalKey<FormState>();
|
||||
|
||||
late FloatingActionButton addBolusButton;
|
||||
@ -40,28 +43,29 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
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<BolusProfileDetailScreen> {
|
||||
bottomNav = detailBottomRow;
|
||||
}
|
||||
|
||||
void refresh({String? message}) {
|
||||
void reload({String? message}) {
|
||||
if (widget.id != 0) {
|
||||
setState(() {
|
||||
if (widget.bolusProfile != null) {
|
||||
widget.bolusProfile!.bolusRates =
|
||||
Bolus.fetchAllForBolusProfile(widget.bolusProfile!);
|
||||
}
|
||||
_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<BolusProfileDetailScreen> {
|
||||
}
|
||||
|
||||
Future<void> 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<BolusProfileDetailScreen> {
|
||||
),
|
||||
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<BolusProfileDetailScreen> {
|
||||
_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<BolusProfileDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void handleAddNew() async {
|
||||
List<Bolus> 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<BolusProfileDetailScreen> {
|
||||
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!,
|
||||
BolusProfile.put(
|
||||
BolusProfile(
|
||||
id: widget.id,
|
||||
name: _nameController.text,
|
||||
active: _active,
|
||||
notes: _notesController.text,
|
||||
),
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Bolus Profile saved');
|
||||
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<BolusProfileDetailScreen> {
|
||||
}
|
||||
|
||||
void renderTabButtons(index) {
|
||||
if (widget.bolusProfile != null) {
|
||||
if (_bolusProfile != null) {
|
||||
setState(() {
|
||||
switch (index) {
|
||||
case 1:
|
||||
@ -275,9 +273,8 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
|
||||
@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(() {
|
||||
@ -328,15 +325,15 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
),
|
||||
];
|
||||
|
||||
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<BolusProfileDetailScreen> {
|
||||
),
|
||||
bottomNavigationBar: bottomNav,
|
||||
floatingActionButton: actionButton,
|
||||
floatingActionButtonLocation:
|
||||
FloatingActionButtonLocation.endFloat,
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
@ -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<BolusProfileListScreen> {
|
||||
late Future<List<BolusProfile>?> _bolusProfiles;
|
||||
List<BolusProfile> _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<BolusProfileListScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
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<BolusProfileListScreen> {
|
||||
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<BolusProfileListScreen> {
|
||||
}
|
||||
|
||||
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<BolusProfileListScreen> {
|
||||
}
|
||||
|
||||
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<BolusProfileListScreen> {
|
||||
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<BolusProfileListScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
refresh();
|
||||
reload();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -145,7 +146,7 @@ class _BolusProfileListScreenState extends State<BolusProfileListScreen> {
|
||||
appBar: AppBar(
|
||||
title: const Text('Bolus Profiles'),
|
||||
actions: <Widget>[
|
||||
IconButton(onPressed: refresh, icon: const Icon(Icons.refresh))
|
||||
IconButton(onPressed: reload, icon: const Icon(Icons.refresh))
|
||||
],
|
||||
),
|
||||
drawer:
|
||||
@ -155,30 +156,16 @@ class _BolusProfileListScreenState extends State<BolusProfileListScreen> {
|
||||
children: [
|
||||
banner,
|
||||
Expanded(
|
||||
child: FutureBuilder<List<BolusProfile>?>(
|
||||
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,
|
||||
child: _bolusProfiles.isNotEmpty ? ListView.builder(
|
||||
itemCount: _bolusProfiles.length,
|
||||
itemBuilder: (context, index) {
|
||||
final bolusProfile = snapshot.data![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);
|
||||
@ -202,9 +189,8 @@ class _BolusProfileListScreenState extends State<BolusProfileListScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
) : const Center(
|
||||
child: Text('You have not created any Bolus Profiles yet!'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -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<ActiveLogEventListScreen> {
|
||||
late Future<List<LogEvent>> _activeLogEvents;
|
||||
late Future<List<LogEventType>> _logEventTypes;
|
||||
List<LogEvent> _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<ActiveLogEventListScreen> {
|
||||
}
|
||||
|
||||
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<ActiveLogEventListScreen> {
|
||||
}
|
||||
|
||||
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,10 +92,7 @@ class _ActiveLogEventListScreenState extends State<ActiveLogEventListScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isNew = widget.endLogEntry == null;
|
||||
return isNew
|
||||
? Container()
|
||||
: Container(
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
child: Column(
|
||||
children: [
|
||||
@ -123,61 +115,49 @@ class _ActiveLogEventListScreenState extends State<ActiveLogEventListScreen> {
|
||||
).then((message) => refresh(message: message));
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh), onPressed: refresh),
|
||||
IconButton(icon: const Icon(Icons.refresh), onPressed: refresh),
|
||||
],
|
||||
),
|
||||
FutureBuilder<List<LogEvent>>(
|
||||
future: _activeLogEvents,
|
||||
builder: (context, snapshot) {
|
||||
return ViewWithProgressIndicator(
|
||||
snapshot: snapshot,
|
||||
child: snapshot.data == null || snapshot.data!.isEmpty
|
||||
? Container()
|
||||
: ListBody(
|
||||
_activeLogEvents.isNotEmpty ?
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: _activeLogEvents.length,
|
||||
itemBuilder: (context, index) {
|
||||
final event = _activeLogEvents[index];
|
||||
return ListTile(
|
||||
title: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
// TODO: fix problems that this futurebuilder in futurebuilder creates
|
||||
FutureBuilder<List<LogEventType>>(
|
||||
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();
|
||||
})
|
||||
Expanded(
|
||||
child: Text(event.eventType.target?.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: () => handleStopAction(event),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.delete,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () => handleDeleteAction(event),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
) : const Center(
|
||||
child: Text('There are no currently ongoing events!'),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -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<LogScreen> {
|
||||
late Future<Map<DateTime, List<LogEntry>>?> _logEntryDailyMap;
|
||||
late Map<DateTime, List<LogEntry>> _logEntryDailyMap;
|
||||
|
||||
void refresh({String? message}) {
|
||||
setState(() {
|
||||
_logEntryDailyMap = LogEntry.createDailyEntryMap();
|
||||
_logEntryDailyMap = LogEntry.getDailyEntryMap();
|
||||
});
|
||||
setState(() {
|
||||
if (message != null) {
|
||||
@ -36,7 +35,8 @@ class _LogScreenState extends State<LogScreen> {
|
||||
}
|
||||
|
||||
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,42 +60,29 @@ class _LogScreenState extends State<LogScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Log Entries'), actions: <Widget>[
|
||||
IconButton(onPressed: refresh, icon: const Icon(Icons.refresh))
|
||||
]),
|
||||
appBar: AppBar(
|
||||
title: const Text('Log Entries'),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
onPressed: refresh,
|
||||
icon: const Icon(Icons.refresh)
|
||||
),
|
||||
],
|
||||
),
|
||||
drawer: const Navigation(currentLocation: LogScreen.routeName),
|
||||
body: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: FutureBuilder<Map<DateTime, List<LogEntry>>?>(
|
||||
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(
|
||||
child: SingleChildScrollView(
|
||||
child: _logEntryDailyMap.isNotEmpty ? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
itemCount: snapshot.data != null
|
||||
? snapshot.data!.length
|
||||
: 0,
|
||||
itemCount: _logEntryDailyMap.length,
|
||||
itemBuilder: (context, dateIndex) {
|
||||
List<DateTime> dateList =
|
||||
snapshot.data!.keys.toList();
|
||||
dateList.sort((a, b) => a.compareTo(b) * -1);
|
||||
List<DateTime> dateList = _logEntryDailyMap.keys.toList();
|
||||
final date = dateList[dateIndex];
|
||||
final entryList = snapshot.data![date];
|
||||
final entryList = _logEntryDailyMap[date];
|
||||
return ListBody(
|
||||
children: [
|
||||
Text(DateTimeUtils.displayDate(date)),
|
||||
@ -112,7 +99,7 @@ class _LogScreenState extends State<LogScreen> {
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
LogEntryScreen(
|
||||
entry: logEntry),
|
||||
id: logEntry.id),
|
||||
),
|
||||
).then((message) => refresh(
|
||||
message: message));
|
||||
@ -142,15 +129,15 @@ class _LogScreenState extends State<LogScreen> {
|
||||
],
|
||||
),
|
||||
);
|
||||
})
|
||||
: Container(),
|
||||
}
|
||||
) : Container(),
|
||||
],
|
||||
);
|
||||
},
|
||||
) : const Center(
|
||||
child: Text('You have not created any Log Entries yet!'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -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<LogEntryScreen> {
|
||||
LogEntry? _logEntry;
|
||||
bool _isNew = true;
|
||||
bool _isSaving = false;
|
||||
|
||||
final GlobalKey<FormState> logEntryForm = GlobalKey<FormState>();
|
||||
|
||||
late FloatingActionButton addMealButton;
|
||||
@ -34,8 +37,6 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
List<Widget> appBarActions = [];
|
||||
DetailBottomRow? bottomNav;
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
final formDataControllers = <String, TextEditingController>{
|
||||
'time': TextEditingController(text: ''),
|
||||
'mgPerDl': TextEditingController(text: ''),
|
||||
@ -46,151 +47,42 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
'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<LogEntryScreen> {
|
||||
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,10 +235,8 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
|
||||
@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(() {
|
||||
@ -247,15 +247,15 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
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<LogEntryScreen> {
|
||||
bottomNavigationBar: bottomNav,
|
||||
floatingActionButton: actionButton,
|
||||
floatingActionButtonLocation:
|
||||
FloatingActionButtonLocation.centerDocked,
|
||||
FloatingActionButtonLocation.endFloat,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
@ -48,7 +48,7 @@ class _LogEntryFormState extends State<LogEntryForm> {
|
||||
|
||||
@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'];
|
||||
|
@ -25,10 +25,10 @@ class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
|
||||
final GlobalKey<FormState> _logEventForm = GlobalKey<FormState>();
|
||||
|
||||
final _notesController = TextEditingController(text: '');
|
||||
String? _eventType;
|
||||
LogEventType? _eventType;
|
||||
bool _hasEndTime = false;
|
||||
|
||||
late Future<List<LogEventType>> _logEventTypes;
|
||||
List<LogEventType> _logEventTypes = [];
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@ -38,11 +38,11 @@ class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
|
||||
|
||||
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<LogEventDetailScreen> {
|
||||
});
|
||||
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!,
|
||||
// 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<LogEventDetailScreen> {
|
||||
_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<LogEventDetailScreen> {
|
||||
StyledForm(
|
||||
formState: _logEventForm,
|
||||
fields: [
|
||||
StyledFutureDropdownButton<LogEventType>(
|
||||
StyledDropdownButton<LogEventType>(
|
||||
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<LogEventDetailScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
// StyledFutureDropdownButton<LogEventType>(
|
||||
// selectedItem: _eventType,
|
||||
// label: 'Event Type',
|
||||
// items: _logEventTypes,
|
||||
// getItemValue: (item) => item.objectId,
|
||||
// renderItem: (item) => Text(item.value),
|
||||
// onChanged: (value) {
|
||||
// setState(() {
|
||||
// _eventType = value;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
StyledBooleanFormField(
|
||||
value: _hasEndTime,
|
||||
onChanged: (value) {
|
||||
|
@ -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<LogEventListScreen> {
|
||||
late Future<List<LogEventType>> _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<LogEventListScreen> {
|
||||
..showSnackBar(snackBar);
|
||||
}
|
||||
});
|
||||
_logEventTypes = LogEventType.fetchAll();
|
||||
}
|
||||
|
||||
void handleEditAction(LogEvent event) {
|
||||
@ -50,15 +39,16 @@ class _LogEventListScreenState extends State<LogEventListScreen> {
|
||||
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,40 +63,19 @@ class _LogEventListScreenState extends State<LogEventListScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
@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<List<LogEvent>>(
|
||||
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<List<LogEventType>>(
|
||||
future: _logEventTypes,
|
||||
builder: (context, types) {
|
||||
return ListView.builder(
|
||||
Expanded(
|
||||
child: (widget.logEntry.events.isNotEmpty || widget.logEntry.endedEvents.isNotEmpty)
|
||||
? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: snapshot.data != null
|
||||
? snapshot.data!.length
|
||||
: 0,
|
||||
itemCount: widget.logEntry.events.length + widget.logEntry.endedEvents.length,
|
||||
itemBuilder: (context, index) {
|
||||
final event = snapshot.data![index];
|
||||
final event = (widget.logEntry.events + widget.logEntry.endedEvents)[index];
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
handleEditAction(event);
|
||||
@ -115,12 +84,7 @@ class _LogEventListScreenState extends State<LogEventListScreen> {
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(types.data
|
||||
?.firstWhere((element) =>
|
||||
element.objectId ==
|
||||
event.eventType)
|
||||
.value ??
|
||||
'')),
|
||||
child: Text(event.eventType.target?.value ?? '')),
|
||||
],
|
||||
),
|
||||
subtitle: Text(
|
||||
@ -133,75 +97,17 @@ class _LogEventListScreenState extends State<LogEventListScreen> {
|
||||
Icons.delete,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () =>
|
||||
handleDeleteAction(event),
|
||||
onPressed: () => handleDeleteAction(event),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
})
|
||||
: const Center(
|
||||
child: Text('You have not added any Events to this Log Entry yet!'),
|
||||
),
|
||||
FutureBuilder<List<LogEvent>>(
|
||||
future: widget.logEntry!.endedEvents,
|
||||
builder: (context, snapshot) {
|
||||
return ViewWithProgressIndicator(
|
||||
snapshot: snapshot,
|
||||
child: snapshot.data == null || snapshot.data!.isEmpty
|
||||
? Container()
|
||||
: FutureBuilder<List<LogEventType>>(
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -45,22 +45,30 @@ class _LogEventTypeDetailScreenState extends State<LogEventTypeDetailScreen> {
|
||||
});
|
||||
if (_logEventTypeForm.currentState!.validate()) {
|
||||
bool isNew = widget.logEventType == null;
|
||||
isNew
|
||||
? await LogEventType.save(
|
||||
// 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,
|
||||
)
|
||||
: await LogEventType.update(
|
||||
widget.logEventType!.objectId!,
|
||||
value: _valueController.text,
|
||||
notes: _notesController.text,
|
||||
defaultReminderDuration:
|
||||
int.tryParse(_defaultReminderDurationController.text),
|
||||
hasEndTime: _hasEndTime,
|
||||
);
|
||||
));
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Log Event Type Saved');
|
||||
}
|
||||
setState(() {
|
||||
|
@ -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<LogEventTypeListScreen> {
|
||||
late Future<List<LogEventType>?> _logEventTypes;
|
||||
List<LogEventType> _logEventTypes = [];
|
||||
|
||||
void refresh({String? message}) {
|
||||
setState(() {
|
||||
_logEventTypes = LogEventType.fetchAll();
|
||||
_logEventTypes = LogEventType.getAll();
|
||||
});
|
||||
setState(() {
|
||||
if (message != null) {
|
||||
@ -50,27 +50,12 @@ class _LogEventTypeListScreenState extends State<LogEventTypeListScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: FutureBuilder<List<LogEventType>?>(
|
||||
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(
|
||||
child: _logEventTypes.isNotEmpty ? ListView.builder(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
itemCount:
|
||||
snapshot.data != null ? snapshot.data!.length : 0,
|
||||
itemCount: _logEventTypes.length,
|
||||
itemBuilder: (context, index) {
|
||||
final logEventType = snapshot.data![index];
|
||||
// final logEventType = snapshot.data![index];
|
||||
final logEventType = _logEventTypes[index];
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
@ -89,10 +74,11 @@ class _LogEventTypeListScreenState extends State<LogEventTypeListScreen> {
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await logEventType.delete().then((_) {
|
||||
LogEventType.remove(logEventType.id);
|
||||
// await logEventType.delete().then((_) {
|
||||
refresh(
|
||||
message: 'Log Event Type deleted');
|
||||
});
|
||||
// });
|
||||
},
|
||||
icon: const Icon(Icons.delete,
|
||||
color: Colors.blue),
|
||||
@ -101,9 +87,8 @@ class _LogEventTypeListScreenState extends State<LogEventTypeListScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
) : const Center(
|
||||
child: Text('You have not created any Log Event Types yet!'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -27,6 +27,7 @@ class LogMealDetailScreen extends StatefulWidget {
|
||||
|
||||
class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
final GlobalKey<FormState> _logMealForm = GlobalKey<FormState>();
|
||||
|
||||
final _valueController = TextEditingController(text: '');
|
||||
final _carbsRatioController = TextEditingController(text: '');
|
||||
final _portionSizeController = TextEditingController(text: '');
|
||||
@ -35,19 +36,19 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
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<List<Meal>> _meals;
|
||||
late Future<List<MealCategory>> _mealCategories;
|
||||
late Future<List<MealPortionType>> _mealPortionTypes;
|
||||
late Future<List<MealSource>> _mealSources;
|
||||
late Future<List<Accuracy>> _portionSizeAccuracies;
|
||||
late Future<List<Accuracy>> _carbsRatioAccuracies;
|
||||
List<Meal> _meals = [];
|
||||
List<MealCategory> _mealCategories = [];
|
||||
List<MealPortionType> _mealPortionTypes = [];
|
||||
List<MealSource> _mealSources = [];
|
||||
List<Accuracy> _portionSizeAccuracies = [];
|
||||
List<Accuracy> _carbsRatioAccuracies = [];
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@ -55,6 +56,13 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
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,28 +78,23 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
(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<void> onSelectMeal(String? objectId) async {
|
||||
if (objectId != null) {
|
||||
Meal? meal = await Meal.get(objectId);
|
||||
if (meal != null) {
|
||||
Future<void> onSelectMeal(Meal meal) async {
|
||||
setState(() {
|
||||
_meal = objectId;
|
||||
_meal = meal;
|
||||
_valueController.text = meal.value;
|
||||
if (meal.carbsRatio != null) {
|
||||
_carbsRatioController.text = meal.carbsRatio.toString();
|
||||
@ -109,25 +112,23 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
_delayedBolusDurationController.text =
|
||||
meal.delayedBolusDuration.toString();
|
||||
}
|
||||
if (meal.source != null) {
|
||||
_source = meal.source;
|
||||
if (meal.mealSource.hasValue) {
|
||||
_mealSource = meal.mealSource.target;
|
||||
}
|
||||
if (meal.category != null) {
|
||||
_category = meal.category;
|
||||
if (meal.mealCategory.hasValue) {
|
||||
_mealCategory = meal.mealCategory.target;
|
||||
}
|
||||
if (meal.portionType != null) {
|
||||
_portionType = meal.portionType;
|
||||
if (meal.mealPortionType.hasValue) {
|
||||
_mealPortionType = meal.mealPortionType.target;
|
||||
}
|
||||
if (meal.portionSizeAccuracy != null) {
|
||||
_portionSizeAccuracy = meal.portionSizeAccuracy;
|
||||
if (meal.portionSizeAccuracy.hasValue) {
|
||||
_portionSizeAccuracy = meal.portionSizeAccuracy.target;
|
||||
}
|
||||
if (meal.carbsRatioAccuracy != null) {
|
||||
_carbsRatioAccuracy = meal.carbsRatioAccuracy;
|
||||
if (meal.carbsRatioAccuracy.hasValue) {
|
||||
_carbsRatioAccuracy = meal.carbsRatioAccuracy.target;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
@ -135,45 +136,69 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
});
|
||||
if (_logMealForm.currentState!.validate()) {
|
||||
bool isNew = widget.logMeal == null;
|
||||
isNew
|
||||
? await LogMeal.save(
|
||||
logEntry: widget.logEntry.objectId!,
|
||||
meal: _meal,
|
||||
// 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,
|
||||
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),
|
||||
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<LogMealDetailScreen> {
|
||||
((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<LogMealDetailScreen> {
|
||||
_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<LogMealDetailScreen> {
|
||||
return null;
|
||||
},
|
||||
),
|
||||
StyledFutureDropdownButton<Meal>(
|
||||
StyledDropdownButton<Meal>(
|
||||
selectedItem: _meal,
|
||||
label: 'Meal',
|
||||
items: _meals,
|
||||
getItemValue: (item) => item.objectId,
|
||||
// getItemValue: (item) => item.objectId,
|
||||
renderItem: (item) => Text(item.value),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
onSelectMeal(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
StyledFutureDropdownButton<MealSource>(
|
||||
selectedItem: _source,
|
||||
StyledDropdownButton<MealSource>(
|
||||
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<MealCategory>(
|
||||
selectedItem: _category,
|
||||
StyledDropdownButton<MealCategory>(
|
||||
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<MealPortionType>(
|
||||
selectedItem: _portionType,
|
||||
StyledDropdownButton<MealPortionType>(
|
||||
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<LogMealDetailScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
StyledFutureDropdownButton<Accuracy>(
|
||||
StyledDropdownButton<Accuracy>(
|
||||
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<LogMealDetailScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
// StyledFutureDropdownButton<Accuracy>(
|
||||
// selectedItem: _portionSizeAccuracy,
|
||||
// label: 'Portion Size Accuracy',
|
||||
// items: _portionSizeAccuracies,
|
||||
// getItemValue: (item) => item.objectId,
|
||||
// renderItem: (item) => Text(item.value),
|
||||
// onChanged: (value) {
|
||||
// setState(() {
|
||||
// _portionSizeAccuracy = value;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@ -444,11 +488,11 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
StyledFutureDropdownButton<Accuracy>(
|
||||
StyledDropdownButton<Accuracy>(
|
||||
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<LogMealDetailScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
// StyledFutureDropdownButton<Accuracy>(
|
||||
// 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',
|
||||
|
@ -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<LogMealListScreen> {
|
||||
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<LogMealListScreen> {
|
||||
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,43 +62,29 @@ class _LogMealListScreenState extends State<LogMealListScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
@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<List<LogMeal>>(
|
||||
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(
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: widget.logEntry.meals.isNotEmpty ? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: snapshot.data != null ? snapshot.data!.length : 0,
|
||||
itemCount: widget.logEntry.meals.length,
|
||||
itemBuilder: (context, index) {
|
||||
final meal = snapshot.data![index];
|
||||
final meal = widget.logEntry.meals[index];
|
||||
return ListTile(
|
||||
onTap: () => handleEditAction(meal),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(child: Text(meal.value)),
|
||||
Expanded(
|
||||
child: Text(meal.value)),
|
||||
child: Text(meal.carbsPerPortion != null
|
||||
? '${meal.carbsPerPortion} g carbs'
|
||||
: '')),
|
||||
Expanded(
|
||||
child: Text(meal.carbsPerPortion != null ? '${meal.carbsPerPortion} g carbs' : '')),
|
||||
Expanded(child: Text(meal.bolus != null ? '${meal.bolus} U' : ''))
|
||||
child: Text(meal.bolus != null
|
||||
? '${meal.bolus} U'
|
||||
: ''))
|
||||
],
|
||||
),
|
||||
trailing: IconButton(
|
||||
@ -111,12 +96,12 @@ class _LogMealListScreenState extends State<LogMealListScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
) : const Center(
|
||||
child: Text(
|
||||
'You have not added any Meals to this Log Entry yet!'),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -35,11 +35,13 @@ class _MealCategoryDetailScreenState extends State<MealCategoryDetailScreen> {
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
@ -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<MealCategoryListScreen> {
|
||||
late Future<List<MealCategory>?> _mealCategories;
|
||||
List<MealCategory> _mealCategories = [];
|
||||
|
||||
void refresh({String? message}) {
|
||||
setState(() {
|
||||
_mealCategories = MealCategory.fetchAll();
|
||||
_mealCategories = MealCategory.getAll();
|
||||
});
|
||||
setState(() {
|
||||
if (message != null) {
|
||||
@ -36,9 +36,8 @@ class _MealCategoryListScreenState extends State<MealCategoryListScreen> {
|
||||
}
|
||||
|
||||
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,27 +76,12 @@ class _MealCategoryListScreenState extends State<MealCategoryListScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: FutureBuilder<List<MealCategory>?>(
|
||||
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(
|
||||
child: _mealCategories.isNotEmpty ? ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
itemCount:
|
||||
snapshot.data != null ? snapshot.data!.length : 0,
|
||||
itemCount: _mealCategories.length,
|
||||
itemBuilder: (context, index) {
|
||||
final mealCategory = snapshot.data![index];
|
||||
final mealCategory = _mealCategories[index];
|
||||
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
@ -126,9 +110,9 @@ class _MealCategoryListScreenState extends State<MealCategoryListScreen> {
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
): const Center(
|
||||
child: Text('You have not created any Meal Categories yet!'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -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<MealDetailScreen> {
|
||||
final GlobalKey<FormState> _mealForm = GlobalKey<FormState>();
|
||||
|
||||
final _valueController = TextEditingController(text: '');
|
||||
final _carbsRatioController = TextEditingController(text: '');
|
||||
final _portionSizeController = TextEditingController(text: '');
|
||||
@ -31,17 +33,18 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
final _delayedBolusRateController = TextEditingController(text: '');
|
||||
final _delayedBolusDurationController = TextEditingController(text: '');
|
||||
final _notesController = TextEditingController(text: '');
|
||||
String? _source;
|
||||
String? _category;
|
||||
String? _portionType;
|
||||
String? _portionSizeAccuracy;
|
||||
String? _carbsRatioAccuracy;
|
||||
|
||||
late Future<List<MealCategory>> _mealCategories;
|
||||
late Future<List<MealPortionType>> _mealPortionTypes;
|
||||
late Future<List<MealSource>> _mealSources;
|
||||
late Future<List<Accuracy>> _portionSizeAccuracies;
|
||||
late Future<List<Accuracy>> _carbsRatioAccuracies;
|
||||
MealSource? _mealSource;
|
||||
MealCategory? _mealCategory;
|
||||
MealPortionType? _mealPortionType;
|
||||
Accuracy? _portionSizeAccuracy;
|
||||
Accuracy? _carbsRatioAccuracy;
|
||||
|
||||
List<MealCategory> _mealCategories = [];
|
||||
List<MealPortionType> _mealPortionTypes = [];
|
||||
List<MealSource> _mealSources = [];
|
||||
List<Accuracy> _portionSizeAccuracies = [];
|
||||
List<Accuracy> _carbsRatioAccuracies = [];
|
||||
|
||||
bool isSaving = false;
|
||||
|
||||
@ -49,6 +52,12 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
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<MealDetailScreen> {
|
||||
(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<MealDetailScreen> {
|
||||
});
|
||||
if (_mealForm.currentState!.validate()) {
|
||||
bool isNew = widget.meal == null;
|
||||
isNew
|
||||
? await Meal.save(
|
||||
// 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,
|
||||
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),
|
||||
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<MealDetailScreen> {
|
||||
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<MealDetailScreen> {
|
||||
_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,30 +192,25 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> onSelectMealSource(String? objectId) async {
|
||||
if (objectId != null) {
|
||||
MealSource? mealSource = await MealSource.get(objectId);
|
||||
if (mealSource != null) {
|
||||
Future<void> onSelectMealSource(MealSource mealSource) async {
|
||||
setState(() {
|
||||
_source = objectId;
|
||||
if (mealSource.defaultCarbsRatioAccuracy != null) {
|
||||
_mealSource = mealSource;
|
||||
if (mealSource.defaultCarbsRatioAccuracy.hasValue) {
|
||||
_carbsRatioAccuracy =
|
||||
mealSource.defaultCarbsRatioAccuracy.toString();
|
||||
mealSource.defaultCarbsRatioAccuracy.target;
|
||||
}
|
||||
if (mealSource.defaultPortionSizeAccuracy != null) {
|
||||
if (mealSource.defaultPortionSizeAccuracy.hasValue) {
|
||||
_portionSizeAccuracy =
|
||||
mealSource.defaultPortionSizeAccuracy.toString();
|
||||
mealSource.defaultPortionSizeAccuracy.target;
|
||||
}
|
||||
if (mealSource.defaultMealCategory != null) {
|
||||
_category = mealSource.defaultMealCategory.toString();
|
||||
if (mealSource.defaultMealCategory.hasValue) {
|
||||
_mealCategory = mealSource.defaultMealCategory.target;
|
||||
}
|
||||
if (mealSource.defaultMealPortionType != null) {
|
||||
_portionType = mealSource.defaultMealPortionType.toString();
|
||||
if (mealSource.defaultMealPortionType.hasValue) {
|
||||
_mealPortionType = mealSource.defaultMealPortionType.target;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void calculateThirdMeasurementOfPortionCarbsRelation(
|
||||
{PortionCarbsParameter? parameterToBeCalculated}) {
|
||||
@ -261,37 +281,39 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
return null;
|
||||
},
|
||||
),
|
||||
StyledFutureDropdownButton<MealSource>(
|
||||
selectedItem: _source,
|
||||
StyledDropdownButton<MealSource>(
|
||||
selectedItem: _mealSource,
|
||||
label: 'Meal Source',
|
||||
items: _mealSources,
|
||||
getItemValue: (item) => item.objectId,
|
||||
// getItemValue: (item) => item.objectId,
|
||||
renderItem: (item) => Text(item.value),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
onSelectMealSource(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
StyledFutureDropdownButton<MealCategory>(
|
||||
selectedItem: _category,
|
||||
StyledDropdownButton<MealCategory>(
|
||||
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<MealPortionType>(
|
||||
selectedItem: _portionType,
|
||||
StyledDropdownButton<MealPortionType>(
|
||||
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<MealDetailScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
StyledFutureDropdownButton<Accuracy>(
|
||||
StyledDropdownButton<Accuracy>(
|
||||
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<MealDetailScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
// StyledFutureDropdownButton<Accuracy>(
|
||||
// selectedItem: _portionSizeAccuracy,
|
||||
// label: 'Portion Size Accuracy',
|
||||
// items: _portionSizeAccuracies,
|
||||
// getItemValue: (item) => item.objectId,
|
||||
// renderItem: (item) => Text(item.value),
|
||||
// onChanged: (value) {
|
||||
// setState(() {
|
||||
// _portionSizeAccuracy = value;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@ -393,11 +427,11 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
StyledFutureDropdownButton<Accuracy>(
|
||||
StyledDropdownButton<Accuracy>(
|
||||
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<MealDetailScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
// StyledFutureDropdownButton<Accuracy>(
|
||||
// selectedItem: _carbsRatioAccuracy,
|
||||
// label: 'Carbs Ratio Accuracy',
|
||||
// items: _carbsRatioAccuracies,
|
||||
// getItemValue: (item) => item.objectId,
|
||||
// renderItem: (item) => Text(item.value),
|
||||
// onChanged: (value) {
|
||||
// setState(() {
|
||||
// _carbsRatioAccuracy = value;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// TODO: display according to time format
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
|
@ -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<MealListScreen> {
|
||||
late Future<List<Meal>?> _meals;
|
||||
List<Meal> _meals = [];
|
||||
|
||||
void refresh({String? message}) {
|
||||
setState(() {
|
||||
_meals = Meal.fetchAll();
|
||||
_meals = Meal.getAll();
|
||||
});
|
||||
setState(() {
|
||||
if (message != null) {
|
||||
@ -36,7 +36,8 @@ class _MealListScreenState extends State<MealListScreen> {
|
||||
}
|
||||
|
||||
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,27 +69,12 @@ class _MealListScreenState extends State<MealListScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: FutureBuilder<List<Meal>?>(
|
||||
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(
|
||||
child: _meals.isNotEmpty ? ListView.builder(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
itemCount:
|
||||
snapshot.data != null ? snapshot.data!.length : 0,
|
||||
itemCount: _meals.length,
|
||||
itemBuilder: (context, index) {
|
||||
final meal = snapshot.data![index];
|
||||
final meal = _meals[index];
|
||||
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
@ -113,9 +99,8 @@ class _MealListScreenState extends State<MealListScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
): const Center(
|
||||
child: Text('You have not created any Meals yet!'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -37,16 +37,21 @@ class _MealPortionTypeDetailScreenState
|
||||
void handleSaveAction() async {
|
||||
if (_mealPortionTypeForm.currentState!.validate()) {
|
||||
bool isNew = widget.mealPortionType == null;
|
||||
isNew
|
||||
? MealPortionType.save(
|
||||
// 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,
|
||||
)
|
||||
: MealPortionType.update(
|
||||
widget.mealPortionType!.objectId!,
|
||||
value: _valueController.text,
|
||||
notes: _notesController.text,
|
||||
);
|
||||
));
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Meal Portion Type saved');
|
||||
}
|
||||
}
|
||||
|
@ -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<MealPortionTypeListScreen> {
|
||||
late Future<List<MealPortionType>?> _mealPortionTypes;
|
||||
List<MealPortionType> _mealPortionTypes = [];
|
||||
|
||||
void refresh({String? message}) {
|
||||
setState(() {
|
||||
_mealPortionTypes = MealPortionType.fetchAll();
|
||||
_mealPortionTypes = MealPortionType.getAll();
|
||||
});
|
||||
setState(() {
|
||||
if (message != null) {
|
||||
@ -37,9 +37,8 @@ class _MealPortionTypeListScreenState extends State<MealPortionTypeListScreen> {
|
||||
}
|
||||
|
||||
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,28 +74,12 @@ class _MealPortionTypeListScreenState extends State<MealPortionTypeListScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: FutureBuilder<List<MealPortionType>?>(
|
||||
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(
|
||||
child: _mealPortionTypes.isNotEmpty ? ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
itemCount: snapshot.data != null
|
||||
? snapshot.data!.length
|
||||
: 0,
|
||||
itemCount: _mealPortionTypes.length,
|
||||
itemBuilder: (context, index) {
|
||||
final mealPortionType = snapshot.data![index];
|
||||
final mealPortionType = _mealPortionTypes[index];
|
||||
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
@ -126,8 +109,9 @@ class _MealPortionTypeListScreenState extends State<MealPortionTypeListScreen> {
|
||||
],
|
||||
),
|
||||
);
|
||||
}));
|
||||
},
|
||||
) : const Center(
|
||||
child: Text('You have not created any Meal Portion Types yet!'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -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<MealSourceDetailScreen> {
|
||||
late Future<List<Accuracy>> _portionSizeAccuracies;
|
||||
late Future<List<Accuracy>> _carbsRatioAccuracies;
|
||||
late Future<List<MealCategory>> _mealCategories;
|
||||
late Future<List<MealPortionType>> _mealPortionTypes;
|
||||
List<Accuracy> _portionSizeAccuracies = [];
|
||||
List<Accuracy> _carbsRatioAccuracies = [];
|
||||
List<MealCategory> _mealCategories = [];
|
||||
List<MealPortionType> _mealPortionTypes = [];
|
||||
|
||||
final GlobalKey<FormState> _mealSourceForm = GlobalKey<FormState>();
|
||||
|
||||
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(
|
||||
// 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,
|
||||
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,
|
||||
);
|
||||
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<MealSourceDetailScreen> {
|
||||
(!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<MealSourceDetailScreen> {
|
||||
return null;
|
||||
},
|
||||
),
|
||||
StyledFutureDropdownButton<Accuracy>(
|
||||
StyledDropdownButton<Accuracy>(
|
||||
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<MealSourceDetailScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
StyledFutureDropdownButton<Accuracy>(
|
||||
StyledDropdownButton<Accuracy>(
|
||||
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<MealSourceDetailScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
StyledFutureDropdownButton<MealCategory>(
|
||||
// StyledFutureDropdownButton<Accuracy>(
|
||||
// selectedItem: _defaultCarbsRatioAccuracy,
|
||||
// label: 'Default Carbs Ratio Accuracy',
|
||||
// items: _carbsRatioAccuracies,
|
||||
// getItemValue: (item) => item.objectId,
|
||||
// renderItem: (item) => Text(item.value),
|
||||
// onChanged: (value) {
|
||||
// setState(() {
|
||||
// _defaultCarbsRatioAccuracy = value;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// StyledFutureDropdownButton<Accuracy>(
|
||||
// selectedItem: _defaultPortionSizeAccuracy,
|
||||
// label: 'Default Portion Size Accuracy',
|
||||
// items: _portionSizeAccuracies,
|
||||
// getItemValue: (item) => item.objectId,
|
||||
// renderItem: (item) => Text(item.value),
|
||||
// onChanged: (value) {
|
||||
// setState(() {
|
||||
// _defaultPortionSizeAccuracy = value;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
StyledDropdownButton<MealCategory>(
|
||||
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<MealSourceDetailScreen> {
|
||||
});
|
||||
},
|
||||
),
|
||||
StyledFutureDropdownButton<MealPortionType>(
|
||||
StyledDropdownButton<MealPortionType>(
|
||||
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(() {
|
||||
|
@ -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<MealSourceListScreen> {
|
||||
late Future<List<MealSource>?> _mealSources;
|
||||
List<MealSource> _mealSources = [];
|
||||
|
||||
void refresh({String? message}) {
|
||||
setState(() {
|
||||
_mealSources = MealSource.fetchAll();
|
||||
_mealSources = MealSource.getAll();
|
||||
});
|
||||
setState(() {
|
||||
if (message != null) {
|
||||
@ -33,6 +35,23 @@ class _MealSourceListScreenState extends State<MealSourceListScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
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,40 +72,22 @@ class _MealSourceListScreenState extends State<MealSourceListScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: FutureBuilder<List<MealSource>?>(
|
||||
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(
|
||||
child: _mealSources.isNotEmpty ? ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
itemCount: snapshot.data != null
|
||||
? snapshot.data!.length
|
||||
: 0,
|
||||
itemCount: _mealSources.length,
|
||||
itemBuilder: (context, index) {
|
||||
final mealSource = snapshot.data![index];
|
||||
final mealSource = _mealSources[index];
|
||||
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
MealSourceDetailScreen(
|
||||
builder: (context) => MealSourceDetailScreen(
|
||||
mealSource: mealSource,
|
||||
),
|
||||
),
|
||||
).then(
|
||||
(message) => refresh(message: message));
|
||||
).then((message) => refresh(message: message));
|
||||
},
|
||||
title: Text(mealSource.value),
|
||||
subtitle: Text(mealSource.notes ?? ''),
|
||||
@ -99,18 +100,15 @@ class _MealSourceListScreenState extends State<MealSourceListScreen> {
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () async {
|
||||
// add confirmation dialog
|
||||
await mealSource.delete().then((_) {
|
||||
refresh(
|
||||
message: 'Meal Source deleted');
|
||||
});
|
||||
handleDeleteAction(mealSource);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}));
|
||||
},
|
||||
}
|
||||
) : const Center(
|
||||
child: Text('You have not created any Meal Sources yet!'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
0
logs/parse-server.err.2021-10-31
Normal file
0
logs/parse-server.err.2021-10-31
Normal file
0
logs/parse-server.info.2021-10-31
Normal file
0
logs/parse-server.info.2021-10-31
Normal file
278
pubspec.lock
278
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"
|
||||
|
@ -1,12 +1,12 @@
|
||||
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
|
||||
@ -18,12 +18,16 @@ dependencies:
|
||||
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
|
||||
build_runner: ^2.0.0
|
||||
objectbox_generator: any
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
Loading…
Reference in New Issue
Block a user