improve screens using tabs, disable save buttons while saving, redo log meal list screen, log meal model fixes
This commit is contained in:
parent
53fb4ac7fc
commit
b4db712719
19
.vscode/launch.json
vendored
Normal file
19
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "diameter",
|
||||
"request": "launch",
|
||||
"type": "dart"
|
||||
},
|
||||
{
|
||||
"name": "diameter (profile mode)",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"flutterMode": "profile"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DetailBottomRow extends StatefulWidget {
|
||||
final void Function() onCancel;
|
||||
final void Function() onSave;
|
||||
final void Function()? onCancel;
|
||||
final void Function()? onSave;
|
||||
|
||||
const DetailBottomRow(
|
||||
{Key? key, required this.onCancel, required this.onSave})
|
||||
|
@ -33,6 +33,7 @@ class _ViewWithProgressIndicatorState extends State<ViewWithProgressIndicator> {
|
||||
child: SizedBox(
|
||||
width: widget.progressIndicatorSize,
|
||||
height: widget.progressIndicatorSize,
|
||||
// TODO: only show if loading takes longer than 30ms
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
|
@ -23,7 +23,6 @@ import 'package:diameter/config.dart';
|
||||
import 'package:diameter/screens/basal/basal_profiles_list.dart';
|
||||
import 'package:diameter/screens/bolus/bolus_profile_list.dart';
|
||||
import 'package:diameter/navigation.dart';
|
||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
@ -24,39 +24,19 @@ class LogMeal extends DataTableContent {
|
||||
LogMeal(ParseObject object) {
|
||||
objectId = object.get<String>('objectId');
|
||||
logEntry = object.get<ParseObject>('logEntry')!.get<String>('objectId')!;
|
||||
meal = object.get<ParseObject>('meal') != null
|
||||
? object.get<ParseObject>('meal')!.get<String>('objectId')
|
||||
: null;
|
||||
meal = object.get<ParseObject>('meal')?.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')!.toDouble();
|
||||
portionSize = object.get<num>('portionSize')!.toDouble();
|
||||
carbsPerPortion = object.get<num>('carbsPerPortion')!.toDouble();
|
||||
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;
|
||||
bolus = object.get<num>('bolus') != null
|
||||
? object.get<num>('bolus')!.toDouble()
|
||||
: 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;
|
||||
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');
|
||||
}
|
||||
|
||||
@ -104,7 +84,7 @@ class LogMeal extends DataTableContent {
|
||||
double? delayedBolusRate,
|
||||
String? notes,
|
||||
}) async {
|
||||
final logMeal = ParseObject('Meal')
|
||||
final logMeal = ParseObject('LogMeal')
|
||||
..set('value', value)
|
||||
..set('logEntry',
|
||||
(ParseObject('LogEntry')..objectId = logEntry).toPointer())
|
||||
@ -161,7 +141,7 @@ class LogMeal extends DataTableContent {
|
||||
double? delayedBolusRate,
|
||||
String? notes,
|
||||
}) async {
|
||||
var logMeal = ParseObject('Meal')..objectId = objectId;
|
||||
var logMeal = ParseObject('LogMeal')..objectId = objectId;
|
||||
if (value != null) {
|
||||
logMeal.set('value', value);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ class _AccuracyDetailScreenState extends State<AccuracyDetailScreen> {
|
||||
bool _forCarbsRatio = false;
|
||||
bool _forPortionSize = false;
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -38,6 +40,9 @@ class _AccuracyDetailScreenState extends State<AccuracyDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (_accuracyForm.currentState!.validate()) {
|
||||
bool isNew = widget.accuracy == null;
|
||||
isNew
|
||||
@ -58,6 +63,9 @@ class _AccuracyDetailScreenState extends State<AccuracyDetailScreen> {
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Accuracy saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -154,7 +162,7 @@ class _AccuracyDetailScreenState extends State<AccuracyDetailScreen> {
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
final _endTimeController = TextEditingController(text: '');
|
||||
final _unitsController = TextEditingController(text: '');
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -114,6 +116,9 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (_basalForm.currentState!.validate()) {
|
||||
await validateTimePeriod().then((value) async {
|
||||
if (value != 'CANCEL') {
|
||||
@ -137,6 +142,9 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
}
|
||||
});
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -241,7 +249,7 @@ class _BasalDetailScreenState extends State<BasalDetailScreen> {
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -30,11 +30,18 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
late FloatingActionButton addBasalButton;
|
||||
late IconButton refreshButton;
|
||||
late IconButton closeButton;
|
||||
late DetailBottomRow detailBottomRow;
|
||||
|
||||
FloatingActionButton? actionButton;
|
||||
List<Widget> appBarActions = [];
|
||||
DetailBottomRow? bottomNav;
|
||||
|
||||
final _nameController = TextEditingController(text: '');
|
||||
final _notesController = TextEditingController(text: '');
|
||||
bool _active = false;
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -62,8 +69,14 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
icon: const Icon(Icons.close),
|
||||
);
|
||||
|
||||
detailBottomRow = DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
);
|
||||
|
||||
actionButton = null;
|
||||
appBarActions = [closeButton];
|
||||
bottomNav = detailBottomRow;
|
||||
}
|
||||
|
||||
void refresh({String? message}) {
|
||||
@ -195,6 +208,9 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (_basalProfileForm.currentState!.validate()) {
|
||||
await checkActiveProfiles();
|
||||
bool isNew = widget.basalProfile == null;
|
||||
@ -211,6 +227,9 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Basal Profile saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -235,9 +254,6 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
FloatingActionButton? actionButton;
|
||||
List<Widget> appBarActions = [];
|
||||
|
||||
void renderTabButtons(index) {
|
||||
if (widget.basalProfile != null) {
|
||||
setState(() {
|
||||
@ -245,10 +261,12 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
case 1:
|
||||
actionButton = addBasalButton;
|
||||
appBarActions = [refreshButton, closeButton];
|
||||
bottomNav = null;
|
||||
break;
|
||||
default:
|
||||
actionButton = null;
|
||||
appBarActions = [closeButton];
|
||||
bottomNav = detailBottomRow;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -262,9 +280,7 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
child: Builder(builder: (BuildContext context) {
|
||||
final TabController tabController = DefaultTabController.of(context)!;
|
||||
tabController.addListener(() {
|
||||
if (tabController.indexIsChanging) {
|
||||
renderTabButtons(tabController.index);
|
||||
}
|
||||
});
|
||||
List<Widget> tabs = [
|
||||
SingleChildScrollView(
|
||||
@ -332,13 +348,10 @@ class _BasalProfileDetailScreenState extends State<BasalProfileDetailScreen> {
|
||||
drawer: const Navigation(
|
||||
currentLocation: BasalProfileDetailScreen.routeName),
|
||||
body: TabBarView(children: tabs),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
),
|
||||
bottomNavigationBar: bottomNav,
|
||||
floatingActionButton: actionButton,
|
||||
floatingActionButtonLocation:
|
||||
FloatingActionButtonLocation.centerDocked,
|
||||
FloatingActionButtonLocation.endFloat,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
@ -43,6 +43,8 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
final _mgPerDlController = TextEditingController(text: '');
|
||||
final _mmolPerLController = TextEditingController(text: '');
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -123,6 +125,9 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (_bolusForm.currentState!.validate()) {
|
||||
await validateTimePeriod().then((value) async {
|
||||
if (value != 'CANCEL') {
|
||||
@ -152,6 +157,9 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
}
|
||||
});
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -391,7 +399,7 @@ class _BolusDetailScreenState extends State<BolusDetailScreen> {
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -30,11 +30,18 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
late FloatingActionButton addBolusButton;
|
||||
late IconButton refreshButton;
|
||||
late IconButton closeButton;
|
||||
late DetailBottomRow detailBottomRow;
|
||||
|
||||
FloatingActionButton? actionButton;
|
||||
List<Widget> appBarActions = [];
|
||||
DetailBottomRow? bottomNav;
|
||||
|
||||
final _nameController = TextEditingController(text: '');
|
||||
final _notesController = TextEditingController(text: '');
|
||||
bool _active = false;
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -62,8 +69,15 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
icon: const Icon(Icons.close),
|
||||
);
|
||||
|
||||
// TODO: fix (saving button doesnt get disabled)
|
||||
detailBottomRow = DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
);
|
||||
|
||||
actionButton = null;
|
||||
appBarActions = [closeButton];
|
||||
bottomNav = detailBottomRow;
|
||||
}
|
||||
|
||||
void refresh({String? message}) {
|
||||
@ -195,6 +209,9 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (_bolusProfileForm.currentState!.validate()) {
|
||||
await checkActiveProfiles();
|
||||
bool isNew = widget.bolusProfile == null;
|
||||
@ -211,6 +228,9 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Bolus Profile saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -235,9 +255,6 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
FloatingActionButton? actionButton;
|
||||
List<Widget> appBarActions = [];
|
||||
|
||||
void renderTabButtons(index) {
|
||||
if (widget.bolusProfile != null) {
|
||||
setState(() {
|
||||
@ -245,10 +262,12 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
case 1:
|
||||
actionButton = addBolusButton;
|
||||
appBarActions = [refreshButton, closeButton];
|
||||
bottomNav = null;
|
||||
break;
|
||||
default:
|
||||
actionButton = null;
|
||||
appBarActions = [closeButton];
|
||||
bottomNav = detailBottomRow;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -262,9 +281,7 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
child: Builder(builder: (BuildContext context) {
|
||||
final TabController tabController = DefaultTabController.of(context)!;
|
||||
tabController.addListener(() {
|
||||
if (tabController.indexIsChanging) {
|
||||
renderTabButtons(tabController.index);
|
||||
}
|
||||
});
|
||||
|
||||
List<Widget> tabs = [
|
||||
@ -334,13 +351,10 @@ class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
|
||||
body: TabBarView(
|
||||
children: tabs,
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
),
|
||||
bottomNavigationBar: bottomNav,
|
||||
floatingActionButton: actionButton,
|
||||
floatingActionButtonLocation:
|
||||
FloatingActionButtonLocation.centerDocked,
|
||||
FloatingActionButtonLocation.endFloat,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
@ -28,9 +28,13 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
late FloatingActionButton addEventButton;
|
||||
late IconButton refreshButton;
|
||||
late IconButton closeButton;
|
||||
late DetailBottomRow detailBottomRow;
|
||||
|
||||
static FloatingActionButton? actionButton;
|
||||
static List<Widget> appBarActions = [];
|
||||
FloatingActionButton? actionButton;
|
||||
List<Widget> appBarActions = [];
|
||||
DetailBottomRow? bottomNav;
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
final formDataControllers = <String, TextEditingController>{
|
||||
'time': TextEditingController(text: ''),
|
||||
@ -54,6 +58,9 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (logEntryForm.currentState!.validate()) {
|
||||
bool isNew = widget.entry == null;
|
||||
isNew
|
||||
@ -85,6 +92,9 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
Navigator.pushReplacementNamed(context, '/log',
|
||||
arguments: '${isNew ? 'New' : ''} Log Entry Saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -188,8 +198,14 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
icon: const Icon(Icons.close),
|
||||
);
|
||||
|
||||
detailBottomRow = DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
);
|
||||
|
||||
actionButton = null;
|
||||
appBarActions = [closeButton];
|
||||
bottomNav = detailBottomRow;
|
||||
}
|
||||
|
||||
void renderTabButtons(index) {
|
||||
@ -199,14 +215,17 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
case 1:
|
||||
actionButton = addMealButton;
|
||||
appBarActions = [refreshButton, closeButton];
|
||||
bottomNav = null;
|
||||
break;
|
||||
case 2:
|
||||
actionButton = addEventButton;
|
||||
appBarActions = [refreshButton, closeButton];
|
||||
bottomNav = null;
|
||||
break;
|
||||
default:
|
||||
actionButton = null;
|
||||
appBarActions = [closeButton];
|
||||
bottomNav = detailBottomRow;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -221,9 +240,7 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
child: Builder(builder: (BuildContext context) {
|
||||
final TabController tabController = DefaultTabController.of(context)!;
|
||||
tabController.addListener(() {
|
||||
if (tabController.indexIsChanging) {
|
||||
renderTabButtons(tabController.index);
|
||||
}
|
||||
});
|
||||
List<Widget> tabs = [
|
||||
LogEntryForm(
|
||||
@ -253,10 +270,7 @@ class _LogEntryScreenState extends State<LogEntryScreen> {
|
||||
body: TabBarView(
|
||||
children: tabs,
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
),
|
||||
bottomNavigationBar: bottomNav,
|
||||
floatingActionButton: actionButton,
|
||||
floatingActionButtonLocation:
|
||||
FloatingActionButtonLocation.centerDocked,
|
||||
|
@ -30,6 +30,8 @@ class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
|
||||
|
||||
late Future<List<LogEventType>> _logEventTypes;
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -44,6 +46,9 @@ class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (_logEventForm.currentState!.validate()) {
|
||||
bool isNew = widget.logEvent == null;
|
||||
isNew
|
||||
@ -63,6 +68,9 @@ class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Event Saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -138,7 +146,7 @@ class _LogEventDetailScreenState extends State<LogEventDetailScreen> {
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ class _LogEventTypeDetailScreenState extends State<LogEventTypeDetailScreen> {
|
||||
final _notesController = TextEditingController(text: '');
|
||||
bool _hasEndTime = false;
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -38,6 +40,9 @@ class _LogEventTypeDetailScreenState extends State<LogEventTypeDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (_logEventTypeForm.currentState!.validate()) {
|
||||
bool isNew = widget.logEventType == null;
|
||||
isNew
|
||||
@ -58,6 +63,9 @@ class _LogEventTypeDetailScreenState extends State<LogEventTypeDetailScreen> {
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Log Event Type Saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -148,7 +156,7 @@ class _LogEventTypeDetailScreenState extends State<LogEventTypeDetailScreen> {
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -49,6 +49,8 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
late Future<List<Accuracy>> _portionSizeAccuracies;
|
||||
late Future<List<Accuracy>> _carbsRatioAccuracies;
|
||||
|
||||
bool _isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -128,6 +130,9 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
_isSaving = true;
|
||||
});
|
||||
if (_logMealForm.currentState!.validate()) {
|
||||
bool isNew = widget.logMeal == null;
|
||||
isNew
|
||||
@ -143,6 +148,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
carbsPerPortion: double.tryParse(_carbsPerPortionController.text),
|
||||
portionSizeAccuracy: _portionSizeAccuracy,
|
||||
carbsRatioAccuracy: _carbsRatioAccuracy,
|
||||
bolus: double.tryParse(_bolusController.text),
|
||||
delayedBolusDuration:
|
||||
int.tryParse(_delayedBolusDurationController.text),
|
||||
delayedBolusRate:
|
||||
@ -161,6 +167,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
carbsPerPortion: double.tryParse(_carbsPerPortionController.text),
|
||||
portionSizeAccuracy: _portionSizeAccuracy,
|
||||
carbsRatioAccuracy: _carbsRatioAccuracy,
|
||||
bolus: double.tryParse(_bolusController.text),
|
||||
delayedBolusDuration:
|
||||
int.tryParse(_delayedBolusDurationController.text),
|
||||
delayedBolusRate:
|
||||
@ -169,6 +176,9 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Meal Saved');
|
||||
}
|
||||
setState(() {
|
||||
_isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -185,6 +195,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
double.tryParse(_carbsPerPortionController.text) != null ||
|
||||
_carbsRatioAccuracy != null ||
|
||||
_portionSizeAccuracy != null ||
|
||||
double.tryParse(_bolusController.text) != null ||
|
||||
int.tryParse(_delayedBolusDurationController.text) !=
|
||||
null ||
|
||||
double.tryParse(_delayedBolusRateController.text) != null ||
|
||||
@ -204,6 +215,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
_carbsRatioAccuracy != widget.logMeal!.carbsRatioAccuracy ||
|
||||
_portionSizeAccuracy !=
|
||||
widget.logMeal!.portionSizeAccuracy ||
|
||||
double.tryParse(_bolusController.text) != widget.logMeal!.bolus ||
|
||||
int.tryParse(_delayedBolusDurationController.text) !=
|
||||
widget.logMeal!.delayedBolusDuration ||
|
||||
double.tryParse(_delayedBolusRateController.text) !=
|
||||
@ -486,7 +498,7 @@ class _LogMealDetailScreenState extends State<LogMealDetailScreen> {
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
onSave: _isSaving ? null : handleSaveAction,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -86,34 +86,31 @@ class _LogMealListScreenState extends State<LogMealListScreen> {
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Text('No Meals for this Log Entry'),
|
||||
)
|
||||
: ListBody(
|
||||
: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: snapshot.data != null ? snapshot.data!.length : 0,
|
||||
itemBuilder: (context, index) {
|
||||
final meal = snapshot.data![index];
|
||||
return ListTile(
|
||||
onTap: () => handleEditAction(meal),
|
||||
title: Row(
|
||||
children: [
|
||||
DataTable(
|
||||
columnSpacing: 10.0,
|
||||
showCheckboxColumn: false,
|
||||
rows: snapshot.data != null
|
||||
? snapshot.data!.map((meal) {
|
||||
return DataRow(
|
||||
cells: meal.asDataTableCells(
|
||||
[
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
iconSize: 16.0,
|
||||
onPressed: () =>
|
||||
handleEditAction(meal)),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
iconSize: 16.0,
|
||||
onPressed: () =>
|
||||
handleDeleteAction(meal)),
|
||||
Expanded(
|
||||
child: Text(meal.value)),
|
||||
Expanded(
|
||||
child: Text(meal.carbsPerPortion != null ? '${meal.carbsPerPortion} g carbs' : '')),
|
||||
Expanded(child: Text(meal.bolus != null ? '${meal.bolus} U' : ''))
|
||||
],
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.delete,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () => handleDeleteAction(meal),
|
||||
),
|
||||
);
|
||||
}).toList()
|
||||
: [],
|
||||
columns: LogMeal.asDataTableColumns(),
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -43,6 +43,8 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
late Future<List<Accuracy>> _portionSizeAccuracies;
|
||||
late Future<List<Accuracy>> _carbsRatioAccuracies;
|
||||
|
||||
bool isSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -74,6 +76,9 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
}
|
||||
|
||||
void handleSaveAction() async {
|
||||
setState(() {
|
||||
isSaving = true;
|
||||
});
|
||||
if (_mealForm.currentState!.validate()) {
|
||||
bool isNew = widget.meal == null;
|
||||
isNew
|
||||
@ -112,6 +117,9 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
);
|
||||
Navigator.pop(context, '${isNew ? 'New' : ''} Meal Saved');
|
||||
}
|
||||
setState(() {
|
||||
isSaving = false;
|
||||
});
|
||||
}
|
||||
|
||||
void handleCancelAction() {
|
||||
@ -430,7 +438,7 @@ class _MealDetailScreenState extends State<MealDetailScreen> {
|
||||
),
|
||||
bottomNavigationBar: DetailBottomRow(
|
||||
onCancel: handleCancelAction,
|
||||
onSave: handleSaveAction,
|
||||
onSave: isSaving ? null : handleSaveAction,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
24
pubspec.lock
24
pubspec.lock
@ -14,7 +14,7 @@ packages:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
version: "2.8.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -28,7 +28,7 @@ packages:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.1.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -70,7 +70,7 @@ packages:
|
||||
name: connectivity_plus_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
connectivity_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -119,7 +119,7 @@ packages:
|
||||
name: dio
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.0.1"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -218,7 +218,7 @@ packages:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
version: "0.12.10"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -267,7 +267,7 @@ packages:
|
||||
name: package_info_plus_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
package_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -358,7 +358,7 @@ packages:
|
||||
name: petitparser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
version: "4.4.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -379,7 +379,7 @@ packages:
|
||||
name: process
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.2.3"
|
||||
version: "4.2.4"
|
||||
provider:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -510,7 +510,7 @@ packages:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.3"
|
||||
version: "0.4.2"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -531,7 +531,7 @@ packages:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.0"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -545,7 +545,7 @@ packages:
|
||||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.9"
|
||||
version: "2.2.10"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -559,7 +559,7 @@ packages:
|
||||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.3.0"
|
||||
version: "5.3.1"
|
||||
xxtea:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
Loading…
Reference in New Issue
Block a user