Commit f768bf8
Changed files (2)
lib
components
dialoges
test
ui
components
lib/components/dialoges/add_measurement_dialoge.dart
@@ -29,6 +29,7 @@ class AddEntryDialoge extends StatefulWidget {
///
/// When this is null the timestamp is [DateTime.now] and the other fields
/// will be empty.
+ ///
/// When an initial record is set medicine input is not possible because it is
/// saved separately.
final BloodPressureRecord? initialRecord;
@@ -64,7 +65,7 @@ class _AddEntryDialogeState extends State<AddEntryDialoge> {
/// Last [FormState.save]d note.
String? notes;
- /// Index of the medicine intake that can me entered here.
+ /// Index of the selected medicine in `widget.settings.medications`.
int? medicineId;
/// Whether to show the medication dosis input
@@ -112,7 +113,7 @@ class _AddEntryDialogeState extends State<AddEntryDialoge> {
ListTile(
title: Text(DateFormat(widget.settings.dateFormatString).format(time)),
trailing: const Icon(Icons.edit),
- shape: buildListTileBorder(),
+ shape: buildShapeBorder(),
onTap: () async {
final messenger = ScaffoldMessenger.of(context);
var selectedTime = await showDateTimePicker(
@@ -200,7 +201,8 @@ class _AddEntryDialogeState extends State<AddEntryDialoge> {
);
}
- RoundedRectangleBorder buildListTileBorder([Color? color]) => RoundedRectangleBorder(
+ /// Build the border all fields have.
+ RoundedRectangleBorder buildShapeBorder([Color? color]) => RoundedRectangleBorder(
side: BorderSide(
width: 2,
color: color ?? Theme.of(context).primaryColor
@@ -224,8 +226,8 @@ class _AddEntryDialogeState extends State<AddEntryDialoge> {
);
}
BloodPressureRecord? record;
- if (systolic != null && diastolic != null && pulse != null
- && notes != null && needlePin != null) {
+ if (systolic != null || diastolic != null || pulse != null
+ || notes != null || needlePin != null) {
record = BloodPressureRecord(time, systolic, diastolic, pulse, notes ?? '', needlePin: needlePin);
}
@@ -293,7 +295,7 @@ class _AddEntryDialogeState extends State<AddEntryDialoge> {
});
},
initialColor: needlePin?.color ?? Colors.transparent,
- shape: buildListTileBorder(needlePin?.color)
+ shape: buildShapeBorder(needlePin?.color)
),
if (widget.settings.medications.isNotEmpty && widget.initialRecord == null)
Padding(
@@ -301,41 +303,35 @@ class _AddEntryDialogeState extends State<AddEntryDialoge> {
child: Row(
children: [
Expanded(
- child: Ink(
- padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4),
- decoration: ShapeDecoration(
- shape: buildListTileBorder()
- ),
- child: DropdownButton(
- isExpanded: true,
- value: widget.settings.medications
- .where((e) => e.id == medicineId).firstOrNull,
- underline: const SizedBox.shrink(),
- items: [
- for (final e in widget.settings.medications)
- DropdownMenuItem(
- value: e,
- child: Text(e.designation),
- ),
+ child: DropdownButtonFormField(
+ isExpanded: true,
+ value: widget.settings.medications
+ .where((e) => e.id == medicineId).firstOrNull,
+ decoration: getInputDecoration(null),
+ items: [
+ for (final e in widget.settings.medications)
DropdownMenuItem(
- value: null,
- child: Text(localizations.noMedication),
- )
- ],
- onChanged: (v) {
- setState(() {
- if (v != null) {
- _showMedicineDosisInput = true;
- medicineId = v.id;
- medicineDosis = v.defaultDosis;
- } else {
- _showMedicineDosisInput = false;
- medicineId = null;
- }
- Material.of(context).markNeedsPaint();
- });
- }
- ),
+ value: e,
+ child: Text(e.designation),
+ ),
+ DropdownMenuItem(
+ value: null,
+ child: Text(localizations.noMedication),
+ )
+ ],
+ onChanged: (v) {
+ setState(() {
+ if (v != null) {
+ _showMedicineDosisInput = true;
+ medicineId = v.id;
+ medicineDosis = v.defaultDosis;
+ } else {
+ _showMedicineDosisInput = false;
+ medicineId = null;
+ }
+ Material.of(context).markNeedsPaint();
+ });
+ }
),
),
if (_showMedicineDosisInput)
test/ui/components/add_measurement_dialoge_test.dart
@@ -127,7 +127,7 @@ void main() {
});
group('showAddEntryDialoge', () {
testWidgets('should return null on cancel', (widgetTester) async {
- dynamic result = 'not null';
+ dynamic result = 'result before save';
await loadDialoge(widgetTester, (context) async
=> result = await showAddEntryDialoge(context, Settings(),
mockRecord(sys: 123, dia: 56, pul: 43, note: 'Test note', pin: Colors.teal)));
@@ -141,7 +141,7 @@ void main() {
expect(result, null);
});
testWidgets('should return values on edit cancel', (widgetTester) async {
- dynamic result = 'not null';
+ dynamic result = 'result before save';
final record = mockRecord(sys: 123, dia: 56, pul: 43, note: 'Test note', pin: Colors.teal);
await loadDialoge(widgetTester, (context) async
=> result = await showAddEntryDialoge(context, Settings(), record));
@@ -159,7 +159,7 @@ void main() {
(record.creationTime, record.systolic, record.diastolic, record.pulse, record.notes, record.needlePin!.color)));
});
testWidgets('should be able to input records', (WidgetTester widgetTester) async {
- dynamic result = 'not null';
+ dynamic result = 'result before save';
await loadDialoge(widgetTester, (context) async
=> result = await showAddEntryDialoge(context, Settings()));
expect(find.byType(DropdownButton<Medicine?>), findsNothing, reason: 'No medication in settings.');
@@ -187,10 +187,63 @@ void main() {
.having((p0) => p0.needlePin?.color, 'needlePin', Colors.red)
);
});
+ testWidgets('should allow value only', (WidgetTester widgetTester) async {
+ dynamic result = 'result before save';
+ await loadDialoge(widgetTester, (context) async
+ => result = await showAddEntryDialoge(context, Settings()));
+ expect(find.byType(DropdownButton<Medicine?>), findsNothing, reason: 'No medication in settings.');
+ final localizations = await AppLocalizations.delegate.load(const Locale('en'));
+
+ await widgetTester.enterText(find.ancestor(of: find.text(localizations.sysLong).first,
+ matching: find.byType(TextFormField)), '123');
+ await widgetTester.enterText(find.ancestor(of: find.text(localizations.diaLong).first,
+ matching: find.byType(TextFormField)), '67');
+ await widgetTester.enterText(find.ancestor(of: find.text(localizations.pulLong).first,
+ matching: find.byType(TextFormField)), '89');
+
+ expect(find.text(localizations.btnSave), findsOneWidget);
+ await widgetTester.tap(find.text(localizations.btnSave));
+ await widgetTester.pumpAndSettle();
+
+ expect(result?.$2, isNull);
+ expect(result?.$1, isA<BloodPressureRecord>()
+ .having((p0) => p0.systolic, 'systolic', 123)
+ .having((p0) => p0.diastolic, 'diastolic', 67)
+ .having((p0) => p0.pulse, 'pulse', 89)
+ .having((p0) => p0.notes, 'notes', '')
+ .having((p0) => p0.needlePin?.color, 'needlePin', null)
+ );
+ });
+ testWidgets('should allow note only', (WidgetTester widgetTester) async {
+ dynamic result = 'result before save';
+ await loadDialoge(widgetTester, (context) async
+ => result = await showAddEntryDialoge(context, Settings(
+ allowMissingValues: true,
+ validateInputs: false
+ )));
+ expect(find.byType(DropdownButton<Medicine?>), findsNothing, reason: 'No medication in settings.');
+
+ final localizations = await AppLocalizations.delegate.load(const Locale('en'));
+ await widgetTester.enterText(find.ancestor(of: find.text(localizations.addNote).first,
+ matching: find.byType(TextFormField)), 'test note');
+
+ expect(find.text(localizations.btnSave), findsOneWidget);
+ await widgetTester.tap(find.text(localizations.btnSave));
+ await widgetTester.pumpAndSettle();
+
+ expect(result?.$2, isNull);
+ expect(result?.$1, isA<BloodPressureRecord>()
+ .having((p0) => p0.systolic, 'systolic', null)
+ .having((p0) => p0.diastolic, 'diastolic', null)
+ .having((p0) => p0.pulse, 'pulse', null)
+ .having((p0) => p0.notes, 'notes', 'test note')
+ .having((p0) => p0.needlePin?.color, 'needlePin', null)
+ );
+ });
testWidgets('should be able to input medicines', (WidgetTester widgetTester) async {
final med2 = mockMedicine(designation: 'medication2', defaultDosis: 31.415);
- dynamic result = 'not null';
+ dynamic result = 'result before save';
await loadDialoge(widgetTester, (context) async
=> result = await showAddEntryDialoge(context, Settings(
medications: [
@@ -426,6 +479,5 @@ void main() {
expect(fourthFocusedTextFormField, findsOneWidget);
expect(find.descendant(of: fourthFocusedTextFormField, matching: find.text('Systolic')), findsWidgets);
});
- // TODO: test medicine_intake
});
}
\ No newline at end of file