diameter/lib/screens/bolus/bolus_profile_detail.dart
2021-12-09 06:14:55 +01:00

371 lines
11 KiB
Dart

import 'package:diameter/components/detail.dart';
import 'package:diameter/components/dialogs.dart';
import 'package:diameter/models/bolus.dart';
import 'package:diameter/models/settings.dart';
import 'package:diameter/navigation.dart';
import 'package:diameter/screens/bolus/bolus_detail.dart';
import 'package:flutter/material.dart';
import 'package:diameter/components/forms.dart';
import 'package:diameter/models/bolus_profile.dart';
import 'package:diameter/screens/bolus/bolus_list.dart';
class BolusProfileDetailScreen extends StatefulWidget {
static const String routeName = '/bolus-profile';
final int id;
final bool active;
const BolusProfileDetailScreen({Key? key, this.active = false, this.id = 0})
: super(key: key);
@override
_BolusProfileDetailScreenState createState() =>
_BolusProfileDetailScreenState();
}
class _BolusProfileDetailScreenState extends State<BolusProfileDetailScreen> {
BolusProfile? _bolusProfile;
List<Bolus> _bolusRates = [];
bool _isNew = true;
final GlobalKey<FormState> _bolusProfileForm = GlobalKey<FormState>();
final ScrollController _scrollController = ScrollController();
late FloatingActionButton addBolusButton;
late IconButton refreshButton;
late IconButton closeButton;
late DetailBottomRow detailBottomRow;
late DetailBottomRow detailBottomRowWhileSaving;
FloatingActionButton? actionButton;
List<Widget> appBarActions = [];
DetailBottomRow? bottomNav;
final _nameController = TextEditingController(text: '');
final _notesController = TextEditingController(text: '');
bool _active = false;
@override
void initState() {
super.initState();
reload();
if (_bolusProfile != null) {
_nameController.text = _bolusProfile!.name;
_active = _bolusProfile!.active;
_notesController.text = _bolusProfile!.notes ?? '';
}
if (widget.active) {
_active = true;
}
addBolusButton = FloatingActionButton(
onPressed: handleAddNewBolus,
child: const Icon(Icons.add),
);
refreshButton = IconButton(
icon: const Icon(Icons.refresh),
onPressed: reload,
);
closeButton = IconButton(
onPressed: handleCancelAction,
icon: const Icon(Icons.close),
);
detailBottomRow = DetailBottomRow(
onCancel: handleCancelAction,
onSave: handleSaveAction,
);
detailBottomRowWhileSaving = DetailBottomRow(
onCancel: handleCancelAction,
onSave: null,
);
actionButton = null;
appBarActions = [closeButton];
bottomNav = detailBottomRow;
}
void reload({String? message}) {
if (widget.id != 0) {
setState(() {
_bolusProfile = BolusProfile.get(widget.id);
_bolusRates = Bolus.getAllForProfile(widget.id);
});
_isNew = _bolusProfile == null;
}
setState(() {
if (message != null) {
var snackBar = SnackBar(
content: Text(message),
duration: const Duration(seconds: 2),
);
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(snackBar);
}
});
}
Future<void> checkActiveProfiles() async {
int _activeCount = BolusProfile.activeCount();
if (_active &&
(_activeCount > 1 ||
_activeCount == 1 && (_isNew || !_bolusProfile!.active))) {
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: const Text(
'There are already one or more active profiles. What would you like to do?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, 0),
child: const Text('IGNORE'),
),
TextButton(
onPressed: () => Navigator.pop(context, 1),
child: const Text('DEACTIVATE THIS PROFILE'),
),
ElevatedButton(
onPressed: () => Navigator.pop(context, 2),
child: const Text('DEACTIVATE ALL OTHERS'),
)
],
);
}).then((value) async {
if (value == 1) {
setState(() {
_active = false;
});
} else if (value == 2) {
BolusProfile.setAllInactive();
}
});
} else if (!_active &&
((_isNew && _activeCount == 0) ||
(!_isNew && _activeCount == 1 && _bolusProfile!.active))) {
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: const Text(
'There is currently no active profile. Would you like to set this one as active?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, 0),
child: const Text('IGNORE'),
),
TextButton(
onPressed: () => Navigator.pop(context, 1),
child: const Text('ACTIVATE THIS PROFILE'),
),
],
);
}).then((value) {
if (value == 1) {
setState(() {
_active = true;
});
}
});
}
}
void handleAddNewBolus() async {
TimeOfDay? suggestedStartTime;
TimeOfDay? suggestedEndTime;
_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) &&
(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;
if (bolus.startTime.isAfter(lastEndTime)) {
suggestedStartTime = TimeOfDay.fromDateTime(lastEndTime);
suggestedEndTime = TimeOfDay.fromDateTime(bolus.startTime);
}
}
}
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return BolusDetailScreen(
bolusProfileId: widget.id,
suggestedStartTime: suggestedStartTime,
suggestedEndTime: suggestedEndTime,
);
},
),
).then((result) => reload(message: result?[0]));
}
void handleSaveAction() async {
setState(() {
bottomNav = detailBottomRowWhileSaving;
});
if (_bolusProfileForm.currentState!.validate()) {
await checkActiveProfiles();
BolusProfile bolusProfile = BolusProfile(
id: widget.id,
name: _nameController.text,
active: _active,
notes: _notesController.text,
);
BolusProfile.put(bolusProfile);
Navigator.pop(context,
['${_isNew ? 'New' : ''} Bolus Profile saved', bolusProfile]);
}
setState(() {
bottomNav = detailBottomRow;
});
}
void handleCancelAction() {
if (Settings.get().showConfirmationDialogOnCancel &&
(_isNew &&
(_active != widget.active ||
_nameController.text != '' ||
_notesController.text != '')) ||
(!_isNew &&
(_bolusProfile!.active != _active ||
_bolusProfile!.name != _nameController.text ||
(_bolusProfile!.notes ?? '') != _notesController.text))) {
Dialogs.showCancelConfirmationDialog(
context: context,
isNew: _isNew,
onSave: handleSaveAction,
);
} else {
Navigator.pop(context);
}
}
void renderTabButtons(index) {
if (_bolusProfile != null) {
setState(() {
switch (index) {
case 1:
actionButton = addBolusButton;
appBarActions = [refreshButton, closeButton];
bottomNav = null;
break;
default:
actionButton = null;
appBarActions = [closeButton];
bottomNav = detailBottomRow;
}
});
}
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: _isNew ? 1 : 2,
child: Builder(builder: (BuildContext context) {
final TabController tabController = DefaultTabController.of(context)!;
tabController.addListener(() {
renderTabButtons(tabController.index);
});
List<Widget> tabs = [
Scrollbar(
controller: _scrollController,
child: SingleChildScrollView(
controller: _scrollController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
FormWrapper(
formState: _bolusProfileForm,
fields: [
TextFormField(
controller: _nameController,
decoration: const InputDecoration(
labelText: 'Name',
),
validator: (value) {
if (value!.trim().isEmpty) {
return 'Empty title';
}
return null;
},
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Notes',
),
controller: _notesController,
keyboardType: TextInputType.multiline,
minLines: 2,
maxLines: 5,
),
BooleanFormField(
value: _active,
onChanged: (value) {
setState(() {
_active = value;
});
},
label: 'active',
),
],
),
],
),
),
),
];
if (!_isNew) {
tabs.add(BolusListScreen(
bolusProfile: _bolusProfile!,
bolusRates: _bolusRates,
reload: reload));
}
return Scaffold(
appBar: AppBar(
title: Text(_isNew ? 'New Bolus Profile' : _bolusProfile!.name),
bottom: _isNew
? PreferredSize(child: Container(), preferredSize: Size.zero)
: const TabBar(
tabs: [
Tab(text: 'PROFILE'),
Tab(text: 'RATES'),
],
),
actions: appBarActions,
),
drawer: const Navigation(
currentLocation: BolusProfileDetailScreen.routeName),
body: TabBarView(
children: tabs,
),
bottomNavigationBar: bottomNav,
floatingActionButton: actionButton,
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
);
}),
);
}
}