Commit 4686fd9

derdilla <82763757+derdilla@users.noreply.github.com>
2026-01-16 17:19:10
Allow editing medications (#620)
* Implement medication editing * Add test for initial value prefilling
1 parent 39dde2f
Changed files (3)
app/lib/features/settings/add_medication_dialoge.dart
@@ -10,7 +10,10 @@ import 'package:provider/provider.dart';
 /// Dialoge to enter values for a [Medicine].
 class AddMedicationDialoge extends StatefulWidget {
   /// Create a dialoge to enter values for a [Medicine].
-  const AddMedicationDialoge({super.key});
+  const AddMedicationDialoge({super.key, this.initialValue});
+
+  /// Medicine to use to prefill input fields.
+  final Medicine? initialValue;
 
   @override
   State<AddMedicationDialoge> createState() => _AddMedicationDialogeState();
@@ -21,13 +24,20 @@ class _AddMedicationDialogeState extends State<AddMedicationDialoge> {
   final nameFocusNode = FocusNode();
 
   Color _color = Colors.transparent;
+
   String? _designation;
-  double? _defaultDosis;
 
+  /// Selected default dosis in mg.
+  double? _defaultDosis;
 
   @override
   void initState() {
     super.initState();
+    if (widget.initialValue != null) {
+      _color = Color(widget.initialValue!.color ?? 0);
+      _designation = widget.initialValue!.designation;
+      _defaultDosis = widget.initialValue!.dosis?.mg;
+    }
     nameFocusNode.requestFocus();
   }
 
@@ -53,6 +63,7 @@ class _AddMedicationDialogeState extends State<AddMedicationDialoge> {
             TextFormField(
               focusNode: nameFocusNode,
               decoration: _getInputDecoration(context, localizations.name),
+              initialValue: _designation,
               onSaved: (value) => _designation = value,
             ),
             const SizedBox(height: 8,),
@@ -69,6 +80,7 @@ class _AddMedicationDialogeState extends State<AddMedicationDialoge> {
               keyboardType: TextInputType.number,
               decoration: _getInputDecoration(context, localizations.defaultDosis),
               inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'([0-9]+(\.([0-9]*))?)')),],
+              initialValue: _defaultDosis?.toString(),
               onSaved: (value) => _defaultDosis = double.tryParse(value ?? '')
                   ?? int.tryParse(value ?? '')?.toDouble(),
             ),
@@ -98,7 +110,9 @@ class _AddMedicationDialogeState extends State<AddMedicationDialoge> {
 /// Shows a full screen dialoge to input a medicine.
 ///
 /// The created medicine gets an index that was never in settings.
-Future<Medicine?> showAddMedicineDialoge(BuildContext context) =>
+Future<Medicine?> showAddMedicineDialoge(BuildContext context, {
+  Medicine? initialValue,
+}) =>
   showDialog<Medicine?>(context: context,
-    builder: (context) => AddMedicationDialoge(),
+    builder: (context) => AddMedicationDialoge(initialValue: initialValue),
   );
app/lib/features/settings/medicine_manager_screen.dart
@@ -31,13 +31,34 @@ class MedicineManagerScreen extends StatelessWidget {
     subtitle: med.dosis == null ? null
         : Text('${AppLocalizations.of(context)!.defaultDosis}: '
         '${med.dosis!.mg} mg'),
-    trailing: IconButton(
-      icon: const Icon(Icons.delete),
-      onPressed: () async {
-        if (await showConfirmDeletionDialoge(context) && context.mounted) {
-          await RepositoryProvider.of<MedicineRepository>(context).remove(med);
-        }
-      },
+    trailing: Row(
+      mainAxisSize: MainAxisSize.min,
+      children: [
+        IconButton(
+          icon: const Icon(Icons.edit),
+          onPressed: () async {
+            final medRepo = RepositoryProvider.of<MedicineRepository>(context);
+            final newMed = await showAddMedicineDialoge(context,
+                initialValue: med);
+            if (newMed != null) {
+              // We can not edit the med directly since this could skew old
+              // entries. Marking a medicine as removed just hides it from the
+              // selection list, while editing it would alter old the default
+              // dosis of old records.
+              await medRepo.remove(med);
+              await medRepo.add(newMed);
+            }
+          },
+        ),
+        IconButton(
+          icon: const Icon(Icons.delete),
+          onPressed: () async {
+            if (await showConfirmDeletionDialoge(context) && context.mounted) {
+              await RepositoryProvider.of<MedicineRepository>(context).remove(med);
+            }
+          },
+        ),
+      ],
     ),
   );
 
app/test/features/settings/add_medication_dialoge_test.dart
@@ -0,0 +1,19 @@
+import 'package:blood_pressure_app/features/settings/add_medication_dialoge.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:health_data_store/health_data_store.dart';
+
+import '../../util.dart';
+
+void main() {
+  testWidgets('should prefill initialValue', (tester) async {
+    await tester.pumpWidget(materialApp(AddMedicationDialoge(
+      initialValue: Medicine(
+        designation: 'testmed 1',
+        color: Colors.red.toARGB32(),
+        dosis: Weight.mg(12.34),
+      ),)));
+    expect(find.text('testmed 1'), findsOneWidget);
+    expect(find.text('12.34'), findsOneWidget);
+  });
+}