Commit 27bed8c

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2023-12-16 07:25:35
add export column editor dialoge
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 5cdab11
Changed files (6)
lib/components/dialoges/add_export_column_dialoge.dart
@@ -0,0 +1,147 @@
+import 'package:blood_pressure_app/components/measurement_list/measurement_list_entry.dart';
+import 'package:blood_pressure_app/model/blood_pressure.dart';
+import 'package:blood_pressure_app/model/export_import/column.dart';
+import 'package:blood_pressure_app/screens/subsettings/export_import/export_field_format_documentation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+class AddExportColumnDialoge extends StatefulWidget {
+
+  const AddExportColumnDialoge({super.key, this.initialColumn});
+
+  final ExportColumn? initialColumn;
+
+  @override
+  State<AddExportColumnDialoge> createState() => _AddExportColumnDialogeState();
+}
+
+class _AddExportColumnDialogeState extends State<AddExportColumnDialoge> {
+  final formKey = GlobalKey<FormState>();
+
+  /// Csv column title used to compute remaining titles.
+  late String csvTitle;
+
+  /// Pattern to
+  late String formatPattern;
+
+
+  @override
+  void initState() {
+    super.initState();
+    csvTitle = widget.initialColumn?.csvTitle ?? '';
+    formatPattern = widget.initialColumn?.formatPattern ?? '';
+  }
+
+
+  @override
+  void dispose() {
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final localizations = AppLocalizations.of(context)!;
+    return Scaffold(
+      appBar: AppBar(
+        forceMaterialTransparency: true,
+        leading: IconButton(
+            onPressed: () => Navigator.of(context).pop(null),
+            icon: const Icon(Icons.close)
+        ),
+        actions: [
+          TextButton(
+            onPressed: () {
+              if (formKey.currentState?.validate() ?? false) {
+                formKey.currentState!.save();
+                final column = UserColumn(formatPattern, csvTitle, formatPattern);
+                // TODO: validate internalIdentifier doesn't exist and find append index ?
+                Navigator.pop(context, column);
+              }
+            },
+            child: Text(localizations.btnSave)
+          )
+        ],
+      ),
+      body: Form(
+        key: formKey,
+        child: ListView(
+          children: [
+            TextFormField(
+              initialValue: csvTitle,
+              decoration: getInputDecoration(localizations.csvTitle),
+              validator: (value) => (value != null && value.isNotEmpty) ? null : localizations.errNoValue,
+              onSaved: (value) => setState(() {csvTitle = value!;}),
+            ),
+            const SizedBox(height: 8,),
+            TextFormField(
+              initialValue: formatPattern,
+              onChanged: (value) => setState(() {
+                formatPattern = value;
+              }),
+              decoration: getInputDecoration(localizations.fieldFormat).copyWith(
+                suffixIcon: IconButton(
+                    onPressed: () {
+                      Navigator.of(context).push(MaterialPageRoute(
+                          builder: (context) => InformationScreen(text: localizations.exportFieldFormatDocumentation)));
+                    },
+                    icon: const Icon(Icons.info_outline)
+                ),
+              ),
+              validator: (value) => (value != null && value.isNotEmpty) ? null : localizations.errNoValue,
+              onSaved: (value) => setState(() {formatPattern = value!;}),
+            ),
+            const SizedBox(height: 8,),
+            Container(
+              padding: const EdgeInsets.all(24),
+              decoration: BoxDecoration(
+                color: Theme.of(context).colorScheme.surface,
+                borderRadius: BorderRadius.circular(20)
+              ),
+              child: (){
+                  final record = BloodPressureRecord(DateTime.now(), 123, 78, 65, 'test note');
+                  final column = UserColumn('', '', formatPattern);
+                  String? text = column.encode(record);
+                  final decoded = column.decode(text);
+                  if (text.isEmpty) text = null;
+                  return Column(
+                    children: [
+                      MeasurementListRow(record: record,),
+                      const SizedBox(height: 8,),
+                      const Icon(Icons.arrow_downward),
+                      const SizedBox(height: 8,),
+                      (text != null) ? Text(text) :
+                        Text(localizations.errNoValue, style: const TextStyle(fontStyle: FontStyle.italic),),
+                      const SizedBox(height: 8,),
+                      const Icon(Icons.arrow_downward),
+                      const SizedBox(height: 8,),
+                      Text(decoded.toString())
+                    ],
+                  );
+                }()
+              ),
+          ],
+        ),
+
+      ),
+    );
+  }
+
+  InputDecoration getInputDecoration(String? labelText) {
+    final border = OutlineInputBorder(
+        borderSide: BorderSide(
+          width: 3,
+          color: Theme.of(context).primaryColor,
+        ),
+        borderRadius: BorderRadius.circular(20)
+    );
+    return InputDecoration(
+      hintText: labelText,
+      labelText: labelText,
+      errorMaxLines: 5,
+      border: border,
+      enabledBorder: border,
+    );
+  }
+}
+
+// TODO: showdialoge function and use in manager
\ No newline at end of file
lib/l10n/app_en.arb
@@ -478,5 +478,7 @@
   "manageExportColumns": "Manage export columns",
   "@manageExportColumns": {},
   "buildIn": "Build-in",
-  "@buildIn": {}
+  "@buildIn": {},
+  "csvTitle": "CSV-title",
+  "@csvTitle": {}
 }
lib/model/export_import/column.dart
@@ -217,17 +217,21 @@ class BuildInColumn extends ExportColumn {
 
 // TODO: add class for formattedTimestamp
 
-/// Class for storing export behavior of columns.
-///
-/// In most cases using the sealed
+/// Class for storing data of user added columns.
 class UserColumn extends ExportColumn {
   /// Create a object that handles export behavior for data in a column.
   ///
-  /// [formatter] will be created according to [formatString].
-  UserColumn(this.internalIdentifier, this.csvTitle, String formatString):
-        formatter = ScriptedFormatter(formatString);
+  /// [formatter] will be created according to [formatPattern].
+  ///
+  /// [internalIdentifier] is automatically prefixed with 'userColumn.' during object creation.
+  UserColumn(String internalIdentifier, this.csvTitle, String formatPattern):
+        formatter = ScriptedFormatter(formatPattern),
+        internalIdentifier = 'userColumn.$internalIdentifier';
 
   @override
+  /// Unique identifier of userColumn.
+  ///
+  /// Is automatically be prefixed with `userColumn.` to avoid name collisions with build-ins.
   final String internalIdentifier;
 
   @override
lib/screens/subsettings/export_import/export_column_data.dart
@@ -1,197 +0,0 @@
-/* TODO: rewrite
-
-import 'package:blood_pressure_app/components/consistent_future_builder.dart';
-import 'package:blood_pressure_app/model/blood_pressure.dart';
-import 'package:blood_pressure_app/model/export_import/import_field_type.dart';
-import 'package:blood_pressure_app/model/export_options.dart';
-import 'package:blood_pressure_app/screens/subsettings/export_import/export_field_format_documentation.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-
-class EditExportColumnPage extends StatefulWidget {
-  final String? initialInternalName;
-  final String? initialDisplayName;
-  final String? initialFormatPattern;
-  final bool editable;
-  
-  const EditExportColumnPage({super.key, this.initialDisplayName, this.initialInternalName, 
-    this.initialFormatPattern, this.editable = true});
-
-  @override
-  State<EditExportColumnPage> createState() => _EditExportColumnPageState();
-}
-
-class _EditExportColumnPageState extends State<EditExportColumnPage> {
-  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
-  String? _internalName;
-  String? _displayName;
-  String? _formatPattern;
-  bool _editedInternalName = false;
-  var _internalNameKeyNr = 0;
-
-
-  @override
-  void initState() {
-    super.initState();
-    _internalName = widget.initialInternalName;
-    _displayName = widget.initialDisplayName;
-    _formatPattern= widget.initialFormatPattern;
-  }
-
-  _EditExportColumnPageState();
-  
-  @override
-  Widget build(BuildContext context) {
-    final localizations = AppLocalizations.of(context)!;
-    return ConsistentFutureBuilder(
-      future: ExportConfigurationModel.get(localizations),
-      lastChildWhileWaiting: true,
-      onData: (BuildContext context, ExportConfigurationModel exportConfigurationModel) => Scaffold(
-        body: Center(
-          child: Padding(
-            padding: const EdgeInsets.all(60.0),
-            child: Form(
-              key: _formKey,
-              child: SingleChildScrollView(
-                child: Column(
-                  mainAxisSize: MainAxisSize.min,
-                  children: [
-                    if (!widget.editable)
-                      Text(localizations.errCantEditThis),
-                    Opacity(
-                      opacity: widget.editable ? 1 : 0.7,
-                      child: IgnorePointer(
-                        ignoring: !widget.editable,
-                        child: Column(
-                          mainAxisSize: MainAxisSize.min,
-                          children: [
-                            TextFormField(
-                              key: const Key('displayName'),
-                              initialValue: _displayName,
-                              decoration: InputDecoration(label: Text(localizations.displayTitle)),
-                              onChanged: (String? value) {
-                                if (value != null && value.isNotEmpty) {
-                                  setState(() {
-                                    _displayName = value;
-                                  });
-                                  if (_editedInternalName || (widget.initialInternalName != null)) return;
-                                  final asciiName = value.replaceAll(RegExp(r'[^A-Za-z0-9 ]'), '');
-                                  final internalName = asciiName.replaceAllMapped(RegExp(r' (.)'), (match) {
-                                    return match.group(1)!.toUpperCase();
-                                  }).replaceAll(' ', '');
-                                  setState(() {
-                                    _internalNameKeyNr++;
-                                    _internalName = internalName;
-                                  });
-                                }
-                              },
-                            ),
-                            TextFormField(
-                              key: Key('internalName$_internalNameKeyNr'), // it should update when display name is changed without unfocussing on edit
-                              initialValue: _internalName,
-                              decoration: InputDecoration(label: Text(localizations.internalName)),
-                              enabled: (widget.initialInternalName == null),
-                              validator: (String? value) {
-                                if (value == null || value.isEmpty || RegExp(r'[^A-Za-z0-9]').hasMatch(value)) {
-                                  return localizations.errOnlyLatinCharactersAndArabicNumbers;
-                                }
-                                if (exportConfigurationModel.availableFormatsMap.keys.contains(value)) {
-                                  return localizations.errExportColumnWithThisNameAlreadyExists;
-                                }
-                                return null;
-                              },
-                              onChanged: (String? value) {
-                                if (value != null && value.isNotEmpty && !RegExp(r'[^A-Za-z0-9]').hasMatch(value)) {
-                                  setState(() {
-                                    _internalName = value;
-                                    _editedInternalName = true;
-                                  });
-                                }
-                              },
-                            ),
-                            TextFormField(
-                              key: const Key('formatPattern'),
-                              initialValue: _formatPattern,
-                              decoration: InputDecoration(
-                                label: Text(localizations.fieldFormat),
-                                suffixIcon: IconButton(
-                                    onPressed: () {
-                                      Navigator.of(context).push(MaterialPageRoute(
-                                          builder: (context) => InformationScreen(text: localizations.exportFieldFormatDocumentation)));
-                                    },
-                                    icon: const Icon(Icons.info_outline)
-                                ),
-                              ),
-                              maxLines: 6,
-                              minLines: 1,
-                              validator: (String? value) {
-                                if (value == null || value.isEmpty) {
-                                  return localizations.errNoValue;
-                                } else if (_internalName != null && _displayName != null) {
-                                  try {
-                                    final column = LegacyExportColumn(internalName: _internalName!, columnTitle: _displayName!, formatPattern: value);
-                                    column.formatRecord(BloodPressureRecord(DateTime.now(), 100, 80, 60, ''));
-                                    _formatPattern = value;
-                                  } catch (e) {
-                                    _formatPattern = null;
-                                    return e.toString();
-                                  }
-                                }
-                                return null;
-                              },
-                              onChanged: (value) => setState(() {_formatPattern = value;}),
-                            ),
-                            const SizedBox(height: 12,),
-                            Text(localizations.result),
-                            Text(((){try {
-                              final column = LegacyExportColumn(internalName: _internalName!, columnTitle: _displayName!, formatPattern: _formatPattern!);
-                              return column.formatRecord(BloodPressureRecord(DateTime.now(), 100, 80, 60, 'test'));
-                            } catch (e) {
-                              return '-';
-                            }})()),
-                            const SizedBox(height: 24,),
-                          ],
-                        ),
-                      ),
-                    ),
-                    Row(
-                      children: [
-                        TextButton(
-                            key: const Key('btnCancel'),
-                            onPressed: () {
-                              Navigator.of(context).pop();
-                            },
-
-                            child: Text(localizations.btnCancel)
-                        ),
-                        const Spacer(),
-                        FilledButton.icon(
-                          key: const Key('btnSave'),
-                          icon: const Icon(Icons.save),
-                          label: Text(localizations.btnSave),
-                          onPressed: (widget.editable) ? (() async {
-                            if (_formKey.currentState?.validate() ?? false) {
-                              final navigator = Navigator.of(context);
-                              exportConfigurationModel.addOrUpdate(LegacyExportColumn(
-                                  internalName: _internalName!,
-                                  columnTitle: _displayName!,
-                                  formatPattern: _formatPattern!
-                              ));
-                              navigator.pop();
-                            }
-                          }) : null,
-                        )
-                      ],
-                    )
-                  ],
-                ),
-              ),
-            ),
-          ),
-        )
-      ),
-    );
-  }
-}
-
- */
\ No newline at end of file
lib/screens/subsettings/export_import/export_column_management_screen.dart
@@ -1,3 +1,4 @@
+import 'package:blood_pressure_app/components/dialoges/add_export_column_dialoge.dart';
 import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -46,6 +47,7 @@ class ExportColumnsManagementScreen extends StatelessWidget {
                   leading: const Icon(Icons.add),
                   title: Text(localizations.addExportformat),
                   onTap: () {
+                    Navigator.push(context, MaterialPageRoute(builder: (context) => AddExportColumnDialoge()));
                     // TODO: reimplement tile adding
                   },
                 )
lib/screens/subsettings/export_import/export_field_format_documentation.dart
@@ -14,7 +14,7 @@ class InformationScreen extends StatelessWidget {
   Widget build(BuildContext context) {
     return Scaffold(
         appBar: AppBar(
-          backgroundColor: Theme.of(context).primaryColor,
+          forceMaterialTransparency: true,
         ),
         body: Container(
           padding: const EdgeInsets.all(10),