]> gitweb.hamatoma.de Git - exhibition.git/commitdiff
Module benchmarks to implement all widget types.
authorHamatoma <author.hamatoma.de>
Sat, 16 Oct 2021 18:17:00 +0000 (20:17 +0200)
committerHamatoma <author.hamatoma.de>
Sat, 16 Oct 2021 18:17:00 +0000 (20:17 +0200)
* helper:
* new: fromString()
* fully tested by unit tests

* Generator:
** implements now the data types bool, date, datetime, float, currency
** correction in generating xxx_data.dart
** sql-generation: the SQL statements remember the newlines inside ('|' instead of "")

52 files changed:
lib/base/helper.dart
lib/meta/benchmarks_meta.dart [new file with mode: 0644]
lib/meta/modules.dart
lib/page/benchmarks/benchmark_data.dart [new file with mode: 0644]
lib/page/benchmarks/create_benchmark_custom.dart [new file with mode: 0644]
lib/page/benchmarks/create_benchmark_page.dart [new file with mode: 0644]
lib/page/benchmarks/delete_benchmark_custom.dart [new file with mode: 0644]
lib/page/benchmarks/delete_benchmark_page.dart [new file with mode: 0644]
lib/page/benchmarks/edit_benchmark_custom.dart [new file with mode: 0644]
lib/page/benchmarks/edit_benchmark_page.dart [new file with mode: 0644]
lib/page/benchmarks/list_benchmark_custom.dart [new file with mode: 0644]
lib/page/benchmarks/list_benchmark_page.dart [new file with mode: 0644]
lib/page/page_manager.dart
lib/page/roles/create_role_custom.dart
lib/page/roles/create_role_page.dart
lib/page/roles/edit_role_custom.dart
lib/page/roles/edit_role_page.dart
lib/page/roles/list_role_custom.dart
lib/page/roles/list_role_page.dart
lib/page/roles/role_data.dart
lib/page/structures/create_structure_custom.dart
lib/page/structures/create_structure_page.dart
lib/page/structures/delete_structure_custom.dart
lib/page/structures/delete_structure_page.dart
lib/page/structures/edit_structure_custom.dart
lib/page/structures/edit_structure_page.dart
lib/page/structures/list_structure_custom.dart
lib/page/structures/list_structure_page.dart
lib/page/structures/structure_data.dart [new file with mode: 0644]
lib/page/users/create_user_custom.dart
lib/page/users/create_user_page.dart
lib/page/users/delete_user_custom.dart
lib/page/users/delete_user_page.dart
lib/page/users/edit_user_custom.dart
lib/page/users/edit_user_page.dart
lib/page/users/list_user_custom.dart
lib/page/users/list_user_page.dart
lib/page/users/user_data.dart
lib/services/global_widget.dart
metatool/bin/generator.dart
metatool/bin/generator_base.dart
metatool/bin/page_generator.dart
metatool/bin/sql_generator.dart
metatool/local.properties [new file with mode: 0644]
metatool/pubspec.yaml
metatool/test/helper_test.dart [new file with mode: 0644]
rest_server/data/sql/benchmarks.sql.yaml [new file with mode: 0644]
rest_server/data/sql/roles.sql.yaml
rest_server/data/sql/structures.sql.yaml
rest_server/data/sql/users.sql.yaml
test/helper_test.dart [new file with mode: 0644]
tools/InitProject

index 03aec4a393bcd5793f3caf4a43006ba94d2676c1..8658397628268790081c961e619599d5418a4db9 100644 (file)
@@ -1,5 +1,28 @@
+import 'package:intl/intl.dart';
+import 'package:sprintf/sprintf.dart';
+
 import 'defines.dart';
+import 'i18n.dart';
+
+final dbDateFormat = DateFormat('yyyy-MM-dd HH:mm:ss');
+final dbDateOnlyFormat = DateFormat('yyyy-MM-dd');
+
+final i18n = I18N();
+
+final regExprDateSortable = RegExp(r'(\d{4})[-.](\d\d?)[.-](\d\d?)');
+final regExprDateStandard = RegExp(r'(\d\d?)[-.](\d\d?)[.-](\d{4})');
+final regExprDateTimeSortable =
+    RegExp(r'(\d{4})[-.](\d\d?)[.-](\d\d?)?(\D(\d\d?):(\d\d?)(:(\d\d?))?)?');
+final regExprDateTimeStandard =
+    // ......1.....1....2.....2....3.....34..5.....5.6.....67.8.....87.4
+    RegExp(r'(\d\d?)[-.](\d\d?)[.-](\d{4})(\D(\d\d?):(\d\d?)(:(\d\d?))?)?');
+final standardDateFormat = DateFormat('dd.MM.yyyy');
 
+final standardDateTimeFormat = DateFormat('dd.MM.yyyy HH:mm');
+
+final standardDateTimeFormatSeconds = DateFormat('dd.MM.yyyy HH:mm:ss');
+
+// ..................................1.....1....2.....2....3....3.4.5.....5.6.....67.....7.4
 /// Handles the [input] as a pattern in a filter list:
 ///
 /// Appends '*' if input does not end with a '*'.
@@ -7,43 +30,137 @@ import 'defines.dart';
 ///
 /// Returns a SQL pattern string.
 String asPattern(String input) {
-  final rc = input.isEmpty || input.endsWith('*') ? input : input + '*';
+  final rc = input.endsWith('*') ? input : input + '*';
   return rc.replaceAll('*', '%').replaceAll('?', '_');
 }
 
-/// Converts a [name] to a camel case string.
+/// Converts an [object] into a string depending on the data type.
 ///
-/// A camelCase string starts with a uppercase character.
-String toCamelCase(String name) {
-  final rc = name.isEmpty ? '' : (name[0].toUpperCase() + name.substring(1));
+/// [dbFormat]: true: the result is stored in the database.
+///
+/// [dateOnly]: true: only the date is part of the result, not the time.
+/// Only relevant for DateTime objects.
+///
+/// [withSeconds]: true: the result contains the seconds of the DateTime instance.
+/// Only relevant for DateTime objects.
+String asString(dynamic object,
+    {bool dbFormat = false, bool dateOnly = false, bool withSeconds = false}) {
+  String rc;
+  if (object is String) {
+    rc = object;
+  } else if (object is int) {
+    rc = object.toString();
+  } else if (object is bool) {
+    if (dbFormat) {
+      rc = object ? 'T' : 'F';
+    } else {
+      rc = object ? i18n.tr('Yes') : i18n.tr('No');
+    }
+  } else if (object is DateTime) {
+    if (dbFormat) {
+      if (dateOnly) {
+        rc = dbDateOnlyFormat.format(object);
+      } else {
+        rc = dbDateFormat.format(object);
+      }
+    } else if (dateOnly) {
+      rc = standardDateFormat.format(object);
+    } else if (withSeconds) {
+      rc = standardDateTimeFormatSeconds.format(object);
+    } else {
+      rc = standardDateTimeFormat.format(object);
+    }
+  } else if (object is double) {
+    rc = sprintf('%.2f', [object]);
+  } else {
+    rc = object.toString();
+  }
   return rc;
 }
 
-/// Returns the [dataType] specific value of [data].
-dynamic valueOf(DataType dataType, String data) {
+/// Converts a string [value] into a [dataType] specific object.
+///
+/// If conversion is not possible (wrong input), the [defaultValue] is returned
+dynamic fromString(String value,
+    {required DataType dataType, dynamic defaultValue}) {
   dynamic rc;
+  RegExpMatch? match;
   switch (dataType) {
+    case DataType.undefined:
+      rc = defaultValue;
+      break;
+    case DataType.string:
+      rc = value;
+      break;
     case DataType.bool:
-      rc = data == 'true';
+      if (value == 'T' || value == i18n.tr('Yes')) {
+        rc = true;
+      } else if (value == 'F' || value == i18n.tr('No')) {
+        rc = false;
+      } else {
+        rc = defaultValue;
+      }
       break;
     case DataType.currency:
     case DataType.float:
-      rc = double.tryParse(data);
+      rc = double.tryParse(value) ?? defaultValue;
       break;
     case DataType.date:
+      if ((match = regExprDateSortable.firstMatch(value)) != null) {
+        rc = DateTime(int.parse(match!.group(1)!), int.parse(match.group(2)!),
+            int.parse(match.group(3)!));
+      } else if ((match = regExprDateStandard.firstMatch(value)) != null) {
+        rc = DateTime(int.parse(match!.group(3)!), int.parse(match.group(2)!),
+            int.parse(match.group(1)!));
+      } else {
+        rc = defaultValue;
+      }
+      break;
     case DataType.datetime:
-      rc = DateTime.parse(data);
+      if ((match = regExprDateTimeSortable.firstMatch(value)) != null) {
+        rc = DateTime(
+          int.parse(match!.group(1)!),
+          int.parse(match.group(2)!),
+          int.parse(match.group(3)!),
+          match.groupCount < 6 ? 0 : int.parse(match.group(5) ?? '0'),
+          match.groupCount < 6 ? 0 : int.parse(match.group(6) ?? '0'),
+          match.groupCount < 8 ? 0 : int.parse(match.group(8) ?? '0'),
+        );
+      } else if ((match = regExprDateTimeStandard.firstMatch(value)) != null) {
+        rc = DateTime(
+          int.parse(match!.group(3)!),
+          int.parse(match.group(2)!),
+          int.parse(match.group(1)!),
+          match.groupCount < 6 ? 0 : int.parse(match.group(5) ?? '0'),
+          match.groupCount < 6 ? 0 : int.parse(match.group(6) ?? '0'),
+          match.groupCount < 8 ? 0 : int.parse(match.group(8) ?? '0'),
+        );
+      } else {
+        rc = defaultValue;
+      }
       break;
     case DataType.int:
     case DataType.nat:
     case DataType.reference:
-      rc = int.tryParse(data);
-      break;
-    case DataType.string:
-      rc = data;
+      rc = int.tryParse(value) ?? defaultValue;
+      if (dataType == DataType.nat && rc < 0) {
+        rc = defaultValue;
+      }
       break;
-    case DataType.undefined:
-      throw FormatException('valueOf(): data type is undefined');
   }
   return rc;
 }
+
+/// This function is only used to avoid compiler warning "unused import"
+/// for generated code.
+void helperDummyUsage() {
+  // nothing to do
+}
+
+/// Converts a [name] to a camel case string.
+///
+/// A camelCase string starts with a uppercase character.
+String toCamelCase(String name) {
+  final rc = name.isEmpty ? '' : (name[0].toUpperCase() + name.substring(1));
+  return rc;
+}
diff --git a/lib/meta/benchmarks_meta.dart b/lib/meta/benchmarks_meta.dart
new file mode 100644 (file)
index 0000000..7956efd
--- /dev/null
@@ -0,0 +1,78 @@
+import '../base/defines.dart';
+import '../base/i18n.dart';
+import 'module_meta_data.dart';
+
+final i18n = I18N();
+final M = i18n.module("Benchmarks");
+
+class BenchmarkMeta extends ModuleMetaData {
+  static BenchmarkMeta instance = BenchmarkMeta.internal();
+  factory BenchmarkMeta() {
+    return instance;
+  }
+  BenchmarkMeta.internal()
+      : super('Benchmarks', [
+          PropertyMetaData('id', i18n.tr('Id'), DataType.reference, ':primary:',
+              displayType: DisplayType.combobox),
+          PropertyMetaData(
+              'lastName', i18n.tr('Last Name'), DataType.string, ':notnull:',
+              size: 64),
+          PropertyMetaData('firstName', i18n.tr('First Name', M),
+              DataType.string, ':unique:notnull:',
+              size: 32),
+          PropertyMetaData(
+              'email', i18n.tr('EMail', M), DataType.string, ':unique:notnull:',
+              size: 255, validators: ['isEmail(input)']),
+          PropertyMetaData(
+              'birthday', i18n.tr('Birthday'), DataType.date, ':notnull:'),
+          PropertyMetaData(
+              'active', i18n.tr('Active'), DataType.bool, ':notnull:'),
+          PropertyMetaData(
+              'weight', i18n.tr('Weight'), DataType.float, ''),
+          PropertyMetaData(
+              'income', i18n.tr('Income'), DataType.currency, ''),
+          PropertyMetaData(
+              'created', i18n.tr('Created'), DataType.datetime, ':hidden:'),
+          PropertyMetaData(
+              'createdBy', i18n.tr('Created by'), DataType.string, ':hidden:',
+              size: 32),
+          PropertyMetaData(
+              'changed', i18n.tr('Changed'), DataType.datetime, ':hidden:'),
+          PropertyMetaData(
+              'changedBy', i18n.tr('Changed by'), DataType.string, ':hidden:',
+              size: 32),
+        ], [
+          PageMetaData(
+            'New Benchmark',
+            PageType.create,
+            fields: [CopyDbFields('filters')],
+          ),
+          PageMetaData(
+            'Change Benchmark',
+            PageType.edit,
+            fields: [CopyDbFields('filters')],
+          ),
+          PageMetaData(
+            'Delete Benchmark',
+            PageType.delete,
+            fields: [CopyDbFields('filters')],
+          ),
+          ListPageMetaData(
+            'Benchmarks Overview',
+            fields: [
+              PropertyMetaData(
+                  'text', i18n.tr('Text'), DataType.string, ':pattern:',
+                  size: 64),
+            ],
+            tableColumns: 'benchmark_id;benchmark_lastname;benchmark_firstname;benchmark_birthday',
+            tableHeaders: i18n.tr(';Id;Last Name;First Name;Birthday'),
+            whereCondition: '''(:text='' OR benchmark_lastname like :text
+  OR benchmark_firstname like :text)''',
+            orderBy: 'benchmark_id',
+          ),
+        ]);
+  @override
+  void onInitialized() {
+    super.onInitialized();
+  }
+}
index 2ff718cbe1e7dd5b623c7dfe4e2c30058e8dda99..484f1799eb656320084f09a29a5b6d3ac48ce7b8 100644 (file)
@@ -1,14 +1,17 @@
 // DO NOT CHANGE. This file is created by the meta_tool
 import 'module_meta_data.dart';
+import 'benchmarks_meta.dart';
 import 'roles_meta.dart';
 import 'structures_meta.dart';
 import 'users_meta.dart';
-
 /// Returns the meta data of the module given by [name].
 /// Returns null if not found.
 ModuleMetaData? moduleByName(String name) {
   ModuleMetaData? rc;
   switch (name) {
+    case 'Benchmarks':
+      rc = BenchmarkMeta();
+      break;
     case 'Roles':
       rc = RoleMeta();
       break;
@@ -23,10 +26,10 @@ ModuleMetaData? moduleByName(String name) {
   }
   return rc;
 }
-
 /// Returns the module names as string list.
-List<String> moduleNames() {
+List<String> moduleNames(){
   return [
+    'Benchmarks',
     'Roles',
     'Structures',
     'Users',
diff --git a/lib/page/benchmarks/benchmark_data.dart b/lib/page/benchmarks/benchmark_data.dart
new file mode 100644 (file)
index 0000000..929cce3
--- /dev/null
@@ -0,0 +1,110 @@
+// DO NOT CHANGE. This file is created by the meta_tool
+import '../../base/defines.dart';
+import '../../base/helper.dart';
+import '../../persistence/data_record.dart';
+class BenchmarkData extends DataRecord<int>{
+  int? id;
+  String? lastName;
+  String? firstName;
+  String? email;
+  DateTime? birthday;
+  bool? active;
+  double? weight;
+  int? income;
+  DateTime? created;
+  String? createdBy;
+  DateTime? changed;
+  String? changedBy;
+  BenchmarkData({
+ this.id, this.lastName, this.firstName, this.email, this.birthday, this.active, this.weight, this.income, this.created, this.createdBy, this.changed, this.changedBy});
+  BenchmarkData.createFromMap(DataMap map) {
+    fromMap(map);
+  }
+  @override
+  void fromMap(DataMap map) {
+    id = map.containsKey('benchmark_id') ? fromString(map['benchmark_id'], dataType: DataType.reference) : null;
+    lastName = map.containsKey('benchmark_lastname') ? fromString(map['benchmark_lastname'], dataType: DataType.string) : null;
+    firstName = map.containsKey('benchmark_firstname') ? fromString(map['benchmark_firstname'], dataType: DataType.string) : null;
+    email = map.containsKey('benchmark_email') ? fromString(map['benchmark_email'], dataType: DataType.string) : null;
+    birthday = map.containsKey('benchmark_birthday') ? fromString(map['benchmark_birthday'], dataType: DataType.date) : null;
+    active = map.containsKey('benchmark_active') ? fromString(map['benchmark_active'], dataType: DataType.bool) : null;
+    weight = map.containsKey('benchmark_weight') ? fromString(map['benchmark_weight'], dataType: DataType.float) : null;
+    income = map.containsKey('benchmark_income') ? fromString(map['benchmark_income'], dataType: DataType.currency) : null;
+    created = map.containsKey('benchmark_created') ? fromString(map['benchmark_created'], dataType: DataType.datetime) : null;
+    createdBy = map.containsKey('benchmark_createdby') ? fromString(map['benchmark_createdby'], dataType: DataType.string) : null;
+    changed = map.containsKey('benchmark_changed') ? fromString(map['benchmark_changed'], dataType: DataType.datetime) : null;
+    changedBy = map.containsKey('benchmark_changedby') ? fromString(map['benchmark_changedby'], dataType: DataType.string) : null;
+  }
+  @override
+  int keyOf() {
+    return id ?? 0;
+  }
+  @override
+  String nameOfKey(){
+    return 'benchmark_id';
+  }
+  static DataType? dataTypeOf(String name) {
+    DataType? rc;
+    switch(name){
+    case 'id':
+      rc = DataType.reference;
+      break;
+    case 'lastName':
+      rc = DataType.string;
+      break;
+    case 'firstName':
+      rc = DataType.string;
+      break;
+    case 'email':
+      rc = DataType.string;
+      break;
+    case 'birthday':
+      rc = DataType.date;
+      break;
+    case 'active':
+      rc = DataType.bool;
+      break;
+    case 'weight':
+      rc = DataType.float;
+      break;
+    case 'income':
+      rc = DataType.currency;
+      break;
+    case 'created':
+      rc = DataType.datetime;
+      break;
+    case 'createdBy':
+      rc = DataType.string;
+      break;
+    case 'changed':
+      rc = DataType.datetime;
+      break;
+    case 'changedBy':
+      rc = DataType.string;
+      break;
+    default:
+      break;
+    }
+    return rc;
+  }
+  @override
+  DataMap toMap({DataMap? map, bool clear = true}) {
+    map ??= DataMap();
+    if (clear) {
+      map.clear();
+    }
+    map['benchmark_id'] = id;
+    map['benchmark_lastname'] = lastName;
+    map['benchmark_firstname'] = firstName;
+    map['benchmark_email'] = email;
+    map['benchmark_birthday'] = birthday;
+    map['benchmark_active'] = active;
+    map['benchmark_weight'] = weight;
+    map['benchmark_income'] = income;
+    map['benchmark_created'] = created;
+    map['benchmark_createdby'] = createdBy;
+    map['benchmark_changed'] = changed;
+    map['benchmark_changedby'] = changedBy;
+    return map;
+  }
+}
diff --git a/lib/page/benchmarks/create_benchmark_custom.dart b/lib/page/benchmarks/create_benchmark_custom.dart
new file mode 100644 (file)
index 0000000..b09328e
--- /dev/null
@@ -0,0 +1,200 @@
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+
+import '../../base/defines.dart';
+import '../../base/helper.dart';
+import '../../base/i18n.dart';
+import '../../base/validators.dart';
+import '../../services/global_widget.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/message_line.dart';
+import '../../widget/widget_form.dart';
+import 'create_benchmark_page.dart';
+
+final i18n = I18N();
+
+class CreateBenchmarkCustom extends State<CreateBenchmarkPage> with MessageLine {
+  final globalData = GlobalData();
+  AttendedPage? attendedPage;
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'CreateBenchmark');
+  final lastNameController = TextEditingController();
+  final firstNameController = TextEditingController();
+  final emailController = TextEditingController();
+  final birthdayController = TextEditingController();
+  final activeController = TextEditingController();
+  final weightController = TextEditingController();
+  final incomeController = TextEditingController();
+  CreateBenchmarkCustom();
+  @override
+  Widget build(BuildContext context) {
+    final padding = GlobalThemeData.padding;
+    lastNameController.text = _fieldData.lastName;
+    firstNameController.text = _fieldData.firstName;
+    emailController.text = _fieldData.email;
+    birthdayController.text = asString(_fieldData.birthday);
+    activeController.text = asString(_fieldData.active);
+    weightController.text = asString(_fieldData.weight);
+    incomeController.text = asString(_fieldData.income);
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: lastNameController,
+            decoration: InputDecoration(labelText: i18n.tr('Last Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.lastName = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: firstNameController,
+            decoration: InputDecoration(labelText: i18n.tr('First Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.firstName = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: emailController,
+            decoration: InputDecoration(labelText: i18n.tr('EMail')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.email = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: birthdayController,
+            decoration: InputDecoration(labelText: i18n.tr('Birthday')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.birthday = fromString(value ?? '', dataType: DataType.date)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: activeController,
+            decoration: InputDecoration(labelText: i18n.tr('Active')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.active = fromString(value ?? '', dataType: DataType.bool)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: weightController,
+            decoration: InputDecoration(labelText: i18n.tr('Weight')),
+            onSaved: (value) => _fieldData.weight = fromString(value ?? '', dataType: DataType.float)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: incomeController,
+            decoration: InputDecoration(labelText: i18n.tr('Income')),
+            onSaved: (value) => _fieldData.income = fromString(value ?? '', dataType: DataType.currency)
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => verifyAndStore(),
+              child: Text(i18n.tr('Save'))),
+          weight: 8,
+          gapAbove: 2 * padding),
+      FormItem(
+          ElevatedButton(
+            onPressed: () {
+              attendedPage!.pageStates.dbDataState.clear();
+              globalData.navigate(context, '/Benchmarks/list');
+            },
+            child: Text(i18n.tr('Cancel')),
+          ),
+          weight: 4)
+    ];
+    final rc = Scaffold(
+        appBar: globalData.appBarBuilder(i18n.tr('New Benchmark')),
+        drawer: globalData.drawerBuilder(context),
+        body: SafeArea(
+            child: Form(
+                key: _formKey,
+                child: Card(
+                    margin: EdgeInsets.symmetric(
+                        vertical: padding, horizontal: padding),
+                    child: Padding(
+                        padding: EdgeInsets.symmetric(
+                            vertical: padding, horizontal: padding),
+                        child: WidgetForm.flexibleGrid(
+                          formItems,
+                          screenWidth: attendedPage!.pageStates.screenWidth,
+                          padding: padding,
+                        ))))));
+    return rc;
+  }
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  void store() {
+    final parameters = <String, dynamic>{
+      'module': 'Benchmarks',
+      'sql': 'insert',
+    };
+    _fieldData.toMap(parameters);
+    globalData.restPersistence!
+        .store(what: 'store', map: parameters)
+        .then((answer) {
+      if (answer.startsWith('id:')) {
+        final id = int.tryParse(answer.substring(3));
+        if (id == null || id == 0) {
+          setError(i18n.tr('Saving data failed: $answer'));
+          setState(() => 1);
+        } else {
+          attendedPage!.pageStates.dbDataState.clear();
+          globalData.navigate(context, '/Benchmarks/edit;$id');
+        }
+      }
+    });
+  }
+
+  void verifyAndStore() {
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      store();
+    }
+  }
+
+  @override
+  void dispose() {
+    lastNameController.dispose();
+    firstNameController.dispose();
+    emailController.dispose();
+    birthdayController.dispose();
+    activeController.dispose();
+    weightController.dispose();
+    incomeController.dispose();
+    super.dispose();
+  }
+}
+
+class _FieldData {
+  String lastName = '';
+  String firstName = '';
+  String email = '';
+  DateTime? birthday;
+  bool active = false;
+  double weight = 0;
+  double income = 0;
+
+
+  void toMap(Map<String, dynamic> map) {
+    map[':lastName'] = lastName;
+    map[':firstName'] = firstName;
+    map[':email'] = email;
+    map[':birthday'] = asString(birthday);
+    map[':active'] = asString(active);
+    map[':weight'] = asString(weight);
+    map[':income'] = asString(income);
+    map[':createdBy'] = GlobalData.loginUserName;
+  }
+}
diff --git a/lib/page/benchmarks/create_benchmark_page.dart b/lib/page/benchmarks/create_benchmark_page.dart
new file mode 100644 (file)
index 0000000..fa02c71
--- /dev/null
@@ -0,0 +1,31 @@
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+
+import '../../meta/benchmarks_meta.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import 'create_benchmark_custom.dart';
+
+class CreateBenchmarkPage extends StatefulWidget {
+  final PageStates pageStates = PageStates();
+  CreateBenchmarkPage() : super();
+  @override
+  _CreateBenchmarkPageState createState() {
+    final rc = _CreateBenchmarkPageState();
+    rc.attendedPage =
+        AttendedPage(this, rc, GlobalData(), BenchmarkMeta.instance, pageStates);
+    pageStates.attendedPage = rc.attendedPage;
+    return rc;
+  }
+}
+
+class _CreateBenchmarkPageState extends CreateBenchmarkCustom {
+  _CreateBenchmarkPageState(): super();
+  @override
+  void didChangeDependencies() {
+    final size = MediaQuery.of(context).size;
+    attendedPage!.pageStates.screenWidth = size.width;
+    attendedPage!.pageStates.screenHeight = size.height;
+    super.didChangeDependencies();
+  }
+}
diff --git a/lib/page/benchmarks/delete_benchmark_custom.dart b/lib/page/benchmarks/delete_benchmark_custom.dart
new file mode 100644 (file)
index 0000000..812cfb8
--- /dev/null
@@ -0,0 +1,195 @@
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+
+import '../../base/defines.dart';
+import '../../base/helper.dart';
+import '../../base/i18n.dart';
+import '../../base/validators.dart';
+import '../../services/global_widget.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/message_line.dart';
+import '../../widget/widget_form.dart';
+import 'delete_benchmark_page.dart';
+
+final i18n = I18N();
+
+class DeleteBenchmarkCustom extends State<DeleteBenchmarkPage> with MessageLine {
+  final int primaryKey;
+  final globalData = GlobalData();
+  AttendedPage? attendedPage;
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'DeleteBenchmark');
+  final lastNameController = TextEditingController();
+  final firstNameController = TextEditingController();
+  final emailController = TextEditingController();
+  final birthdayController = TextEditingController();
+  final activeController = TextEditingController();
+  final weightController = TextEditingController();
+  final incomeController = TextEditingController();
+  DeleteBenchmarkCustom(this.primaryKey);
+  @override
+  Widget build(BuildContext context) {
+    final padding = GlobalThemeData.padding;
+    attendedPage?.loadRecord(
+        name: 'record',
+        reload: () => setState(() => 1),
+        onDone: (record) => _fieldData.fromMap(record),
+        parameters: {'module': 'Benchmarks', 'sql': 'byId', ':id': primaryKey});
+    lastNameController.text = _fieldData.lastName;
+    firstNameController.text = _fieldData.firstName;
+    emailController.text = _fieldData.email;
+    birthdayController.text = asString(_fieldData.birthday);
+    activeController.text = asString(_fieldData.active);
+    weightController.text = asString(_fieldData.weight);
+    incomeController.text = asString(_fieldData.income);
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: lastNameController,
+            decoration: InputDecoration(labelText: i18n.tr('Last Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.lastName = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: firstNameController,
+            decoration: InputDecoration(labelText: i18n.tr('First Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.firstName = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: emailController,
+            decoration: InputDecoration(labelText: i18n.tr('EMail')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.email = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: birthdayController,
+            decoration: InputDecoration(labelText: i18n.tr('Birthday')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.birthday = fromString(value ?? '', dataType: DataType.date)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: activeController,
+            decoration: InputDecoration(labelText: i18n.tr('Active')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.active = fromString(value ?? '', dataType: DataType.bool)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: weightController,
+            decoration: InputDecoration(labelText: i18n.tr('Weight')),
+            onSaved: (value) => _fieldData.weight = fromString(value ?? '', dataType: DataType.float)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: incomeController,
+            decoration: InputDecoration(labelText: i18n.tr('Income')),
+            onSaved: (value) => _fieldData.income = fromString(value ?? '', dataType: DataType.currency)
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => verifyAndDelete(),
+              child: Text(i18n.tr('Delete'))),
+          weight: 8,
+          gapAbove: 2 * padding),
+      FormItem(
+          ElevatedButton(
+            onPressed: () {
+              attendedPage!.pageStates.dbDataState.clear();
+              globalData.navigate(context, '/Benchmarks/list');
+            },
+            child: Text(i18n.tr('Cancel')),
+          ),
+          weight: 4)
+    ];
+    final rc = Scaffold(
+        appBar: globalData.appBarBuilder(i18n.tr('Delete Benchmark')),
+        drawer: globalData.drawerBuilder(context),
+        body: SafeArea(
+            child: Form(
+                key: _formKey,
+                child: Card(
+                    margin: EdgeInsets.symmetric(
+                        vertical: padding, horizontal: padding),
+                    child: Padding(
+                        padding: EdgeInsets.symmetric(
+                            vertical: padding, horizontal: padding),
+                        child: WidgetForm.flexibleGrid(
+                          formItems,
+                          screenWidth: attendedPage!.pageStates.screenWidth,
+                          padding: padding,
+                        ))))));
+    return rc;
+  }
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  void delete() {
+    final parameters = <String, dynamic>{
+      'module': 'Benchmarks',
+      'sql': 'delete',
+    };
+    parameters[':id'] = primaryKey;
+    globalData.restPersistence!
+        .store(what: 'store', map: parameters)
+        .then((answer) {
+      globalData.navigate(context, '/Benchmarks/list');
+    });
+  }
+
+  void verifyAndDelete() {
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      delete();
+    }
+  }
+
+  @override
+  void dispose() {
+    lastNameController.dispose();
+    firstNameController.dispose();
+    emailController.dispose();
+    birthdayController.dispose();
+    activeController.dispose();
+    weightController.dispose();
+    incomeController.dispose();
+    super.dispose();
+  }
+}
+
+class _FieldData {
+  String lastName = '';
+  String firstName = '';
+  String email = '';
+  DateTime? birthday;
+  bool active = false;
+  double weight = 0;
+  double income = 0;
+
+  void fromMap(Map<String, dynamic> map) {
+    lastName = map['benchmark_lastname'];
+    firstName = map['benchmark_firstname'];
+    email = map['benchmark_email'];
+    birthday = map['benchmark_birthday'];
+    active = map['benchmark_active'];
+    weight = map['benchmark_weight'];
+    income = map['benchmark_income'];
+  }
+}
diff --git a/lib/page/benchmarks/delete_benchmark_page.dart b/lib/page/benchmarks/delete_benchmark_page.dart
new file mode 100644 (file)
index 0000000..0955fbf
--- /dev/null
@@ -0,0 +1,32 @@
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+
+import '../../meta/benchmarks_meta.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import 'delete_benchmark_custom.dart';
+
+class DeleteBenchmarkPage extends StatefulWidget {
+  final int primaryKey;
+  final PageStates pageStates = PageStates();
+  DeleteBenchmarkPage(this.primaryKey) : super();
+  @override
+  _DeleteBenchmarkPageState createState() {
+    final rc = _DeleteBenchmarkPageState(this.primaryKey);
+    rc.attendedPage =
+        AttendedPage(this, rc, GlobalData(), BenchmarkMeta.instance, pageStates);
+    pageStates.attendedPage = rc.attendedPage;
+    return rc;
+  }
+}
+
+class _DeleteBenchmarkPageState extends DeleteBenchmarkCustom {
+  _DeleteBenchmarkPageState(int primaryKey): super(primaryKey);
+  @override
+  void didChangeDependencies() {
+    final size = MediaQuery.of(context).size;
+    attendedPage!.pageStates.screenWidth = size.width;
+    attendedPage!.pageStates.screenHeight = size.height;
+    super.didChangeDependencies();
+  }
+}
diff --git a/lib/page/benchmarks/edit_benchmark_custom.dart b/lib/page/benchmarks/edit_benchmark_custom.dart
new file mode 100644 (file)
index 0000000..0b151a1
--- /dev/null
@@ -0,0 +1,206 @@
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+
+import '../../base/defines.dart';
+import '../../base/helper.dart';
+import '../../base/i18n.dart';
+import '../../base/validators.dart';
+import '../../services/global_widget.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/message_line.dart';
+import '../../widget/widget_form.dart';
+import 'edit_benchmark_page.dart';
+
+final i18n = I18N();
+
+class EditBenchmarkCustom extends State<EditBenchmarkPage> with MessageLine {
+  final int primaryKey;
+  final globalData = GlobalData();
+  AttendedPage? attendedPage;
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'EditBenchmark');
+  final lastNameController = TextEditingController();
+  final firstNameController = TextEditingController();
+  final emailController = TextEditingController();
+  final birthdayController = TextEditingController();
+  final activeController = TextEditingController();
+  final weightController = TextEditingController();
+  final incomeController = TextEditingController();
+  EditBenchmarkCustom(this.primaryKey);
+  @override
+  Widget build(BuildContext context) {
+    final padding = GlobalThemeData.padding;
+    attendedPage?.loadRecord(
+        name: 'record',
+        reload: () => setState(() => 1),
+        onDone: (record) => _fieldData.fromMap(record),
+        parameters: {'module': 'Benchmarks', 'sql': 'byId', ':id': primaryKey});
+    lastNameController.text = _fieldData.lastName;
+    firstNameController.text = _fieldData.firstName;
+    emailController.text = _fieldData.email;
+    birthdayController.text = asString(_fieldData.birthday);
+    activeController.text = asString(_fieldData.active);
+    weightController.text = asString(_fieldData.weight);
+    incomeController.text = asString(_fieldData.income);
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: lastNameController,
+            decoration: InputDecoration(labelText: i18n.tr('Last Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.lastName = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: firstNameController,
+            decoration: InputDecoration(labelText: i18n.tr('First Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.firstName = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: emailController,
+            decoration: InputDecoration(labelText: i18n.tr('EMail')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.email = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: birthdayController,
+            decoration: InputDecoration(labelText: i18n.tr('Birthday')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.birthday = fromString(value ?? '', dataType: DataType.date)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: activeController,
+            decoration: InputDecoration(labelText: i18n.tr('Active')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.active = fromString(value ?? '', dataType: DataType.bool)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: weightController,
+            decoration: InputDecoration(labelText: i18n.tr('Weight')),
+            onSaved: (value) => _fieldData.weight = fromString(value ?? '', dataType: DataType.float)
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: incomeController,
+            decoration: InputDecoration(labelText: i18n.tr('Income')),
+            onSaved: (value) => _fieldData.income = fromString(value ?? '', dataType: DataType.currency)
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => verifyAndStore(),
+              child: Text(i18n.tr('Save'))),
+          weight: 8,
+          gapAbove: 2 * padding),
+      FormItem(
+          ElevatedButton(
+            onPressed: () {
+              attendedPage!.pageStates.dbDataState.clear();
+              globalData.navigate(context, '/Benchmarks/list');
+            },
+            child: Text(i18n.tr('Cancel')),
+          ),
+          weight: 4)
+    ];
+    final rc = Scaffold(
+        appBar: globalData.appBarBuilder(i18n.tr('Change Benchmark')),
+        drawer: globalData.drawerBuilder(context),
+        body: SafeArea(
+            child: Form(
+                key: _formKey,
+                child: Card(
+                    margin: EdgeInsets.symmetric(
+                        vertical: padding, horizontal: padding),
+                    child: Padding(
+                        padding: EdgeInsets.symmetric(
+                            vertical: padding, horizontal: padding),
+                        child: WidgetForm.flexibleGrid(
+                          formItems,
+                          screenWidth: attendedPage!.pageStates.screenWidth,
+                          padding: padding,
+                        ))))));
+    return rc;
+  }
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  void store() {
+    final parameters = <String, dynamic>{
+      'module': 'Benchmarks',
+      'sql': 'update',
+    };
+    parameters[':id'] = primaryKey;
+    _fieldData.toMap(parameters);
+    globalData.restPersistence!
+        .store(what: 'store', map: parameters)
+        .then((answer) {});
+  }
+
+  void verifyAndStore() {
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      store();
+    }
+  }
+
+  @override
+  void dispose() {
+    lastNameController.dispose();
+    firstNameController.dispose();
+    emailController.dispose();
+    birthdayController.dispose();
+    activeController.dispose();
+    weightController.dispose();
+    incomeController.dispose();
+    super.dispose();
+  }
+}
+
+class _FieldData {
+  String lastName = '';
+  String firstName = '';
+  String email = '';
+  DateTime? birthday;
+  bool active = false;
+  double weight = 0;
+  double income = 0;
+
+  void fromMap(Map<String, dynamic> map) {
+    lastName = map['benchmark_lastname'];
+    firstName = map['benchmark_firstname'];
+    email = map['benchmark_email'];
+    birthday = map['benchmark_birthday'];
+    active = map['benchmark_active'];
+    weight = map['benchmark_weight'];
+    income = map['benchmark_income'];
+  }
+
+  void toMap(Map<String, dynamic> map) {
+    // please set outside: map[':id'] = primaryKey;
+    map[':lastName'] = lastName;
+    map[':firstName'] = firstName;
+    map[':email'] = email;
+    map[':birthday'] = asString(birthday);
+    map[':active'] = asString(active);
+    map[':weight'] = asString(weight);
+    map[':income'] = asString(income);
+    map[':changedBy'] = GlobalData.loginUserName;
+  }
+}
diff --git a/lib/page/benchmarks/edit_benchmark_page.dart b/lib/page/benchmarks/edit_benchmark_page.dart
new file mode 100644 (file)
index 0000000..32f631a
--- /dev/null
@@ -0,0 +1,32 @@
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+
+import '../../meta/benchmarks_meta.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import 'edit_benchmark_custom.dart';
+
+class EditBenchmarkPage extends StatefulWidget {
+  final int primaryKey;
+  final PageStates pageStates = PageStates();
+  EditBenchmarkPage(this.primaryKey) : super();
+  @override
+  _EditBenchmarkPageState createState() {
+    final rc = _EditBenchmarkPageState(this.primaryKey);
+    rc.attendedPage =
+        AttendedPage(this, rc, GlobalData(), BenchmarkMeta.instance, pageStates);
+    pageStates.attendedPage = rc.attendedPage;
+    return rc;
+  }
+}
+
+class _EditBenchmarkPageState extends EditBenchmarkCustom {
+  _EditBenchmarkPageState(int primaryKey): super(primaryKey);
+  @override
+  void didChangeDependencies() {
+    final size = MediaQuery.of(context).size;
+    attendedPage!.pageStates.screenWidth = size.width;
+    attendedPage!.pageStates.screenHeight = size.height;
+    super.didChangeDependencies();
+  }
+}
diff --git a/lib/page/benchmarks/list_benchmark_custom.dart b/lib/page/benchmarks/list_benchmark_custom.dart
new file mode 100644 (file)
index 0000000..c1701f0
--- /dev/null
@@ -0,0 +1,126 @@
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+
+import '../../base/helper.dart';
+import '../../base/i18n.dart';
+import '../../services/global_widget.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/widget_form.dart';
+import 'list_benchmark_page.dart';
+
+final i18n = I18N();
+
+class ListBenchmarkCustom extends State<ListBenchmarkPage> {
+  final globalData = GlobalData();
+  AttendedPage? attendedPage;
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'CreateBenchmark');
+  final textController = TextEditingController();
+  ListBenchmarkCustom();
+  @override
+  Widget build(BuildContext context) {
+    final padding = GlobalThemeData.padding;
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: textController,
+            decoration: InputDecoration(labelText: i18n.tr('Text')),
+            onSaved: (value) => _fieldData.text = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => search(), child: Text(i18n.tr('Search'))),
+          weight: 12,
+          gapAbove: padding),
+    ];
+    final form = Form(
+        key: _formKey,
+        child: Card(
+            color: GlobalThemeData.formBackgroundColor,
+            elevation: GlobalThemeData.formElevation,
+            margin:
+                EdgeInsets.symmetric(vertical: padding, horizontal: padding),
+            child: Padding(
+                padding: EdgeInsets.symmetric(
+                    vertical: padding, horizontal: padding),
+                child: WidgetForm.flexibleGrid(formItems,
+                    screenWidth: attendedPage!.pageStates.screenWidth,
+                    padding: padding))));
+    final rows = attendedPage!.getRows(
+        columnList: 'benchmark_id;benchmark_lastname;benchmark_firstname;benchmark_birthday',
+        what: 'query',
+        parameters: {
+          'module': 'Benchmarks',
+          'sql': 'list',
+          'offset': '0',
+          'size': '10',
+          ':text': asPattern(_fieldData.text),
+        },
+        onDone: () => setState(() => 1),
+        routeEdit: '/Benchmarks/edit',
+        context: context);
+    final table = DataTable(
+      columns: <DataColumn>[
+        DataColumn(
+          label: Text(i18n.tr('Id')),
+        ),
+        DataColumn(
+          label: Text(i18n.tr('Last Name')),
+        ),
+        DataColumn(
+          label: Text(i18n.tr('First Name')),
+        ),
+        DataColumn(
+          label: Text(i18n.tr('Birthday')),
+        ),
+      ],
+      rows: rows,
+    );
+    final frameWidget = Column(children: [
+      form,
+      SizedBox(height: padding),
+      SizedBox(width: double.infinity, child: table),
+    ]);
+    final rc = Scaffold(
+        appBar: globalData.appBarBuilder(i18n.tr('Overview benchmarks')),
+        drawer: globalData.drawerBuilder(context),
+        floatingActionButton: FloatingActionButton(
+          onPressed: () {
+            globalData.navigate(context, '/Benchmarks/create');
+          },
+          child: const Icon(Icons.add),
+          //backgroundColor: Colors.green,
+        ),
+        body: SafeArea(child: frameWidget));
+    return rc;
+  }
+
+  @override
+  void dispose() {
+    helperDummyUsage();
+    globalWidgetDummyUsage();
+    textController.dispose();
+    super.dispose();
+  }
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  void search() {
+    attendedPage!.pageStates.dbDataState.clear();
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      setState(() => 1);
+    }
+  }
+}
+
+class _FieldData {
+  String text = '';
+}
diff --git a/lib/page/benchmarks/list_benchmark_page.dart b/lib/page/benchmarks/list_benchmark_page.dart
new file mode 100644 (file)
index 0000000..d65dcc5
--- /dev/null
@@ -0,0 +1,31 @@
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+
+import '../../meta/benchmarks_meta.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import 'list_benchmark_custom.dart';
+
+class ListBenchmarkPage extends StatefulWidget {
+  final PageStates pageStates = PageStates();
+  ListBenchmarkPage() : super();
+  @override
+  _ListBenchmarkPageState createState() {
+    final rc = _ListBenchmarkPageState();
+    rc.attendedPage =
+        AttendedPage(this, rc, GlobalData(), BenchmarkMeta.instance, pageStates);
+    pageStates.attendedPage = rc.attendedPage;
+    return rc;
+  }
+}
+
+class _ListBenchmarkPageState extends ListBenchmarkCustom {
+  _ListBenchmarkPageState(): super();
+  @override
+  void didChangeDependencies() {
+    final size = MediaQuery.of(context).size;
+    attendedPage!.pageStates.screenWidth = size.width;
+    attendedPage!.pageStates.screenHeight = size.height;
+    super.didChangeDependencies();
+  }
+}
index 77d41685013a1a0a03b7b397137283deafdec36c..cea3c7319ae429f4b4832da5892c65b653951998 100644 (file)
@@ -2,6 +2,10 @@
 import 'package:flutter/material.dart';
 import 'page_manager_custom.dart';
 
+import 'benchmarks/create_benchmark_page.dart';
+import 'benchmarks/edit_benchmark_page.dart';
+import 'benchmarks/delete_benchmark_page.dart';
+import 'benchmarks/list_benchmark_page.dart';
 import 'roles/create_role_page.dart';
 import 'roles/edit_role_page.dart';
 import 'roles/list_role_page.dart';
@@ -30,6 +34,18 @@ class PageManager {
     final parts = route.split(';');
     final arg1 = parts.length < 2 ? 0 : int.parse(parts[1]);
     switch (parts[0]) {
+      case '/Benchmarks/create':
+        rc = CreateBenchmarkPage();
+        break;
+      case '/Benchmarks/edit':
+        rc = EditBenchmarkPage(arg1);
+        break;
+      case '/Benchmarks/delete':
+        rc = DeleteBenchmarkPage(arg1);
+        break;
+      case '/Benchmarks/list':
+        rc = ListBenchmarkPage();
+        break;
       case '/Roles/create':
         rc = CreateRolePage();
         break;
index 15a4f82f48302786cba57bc46d67aa8908170628..3a38b4182d19ee8db5f293f8facc0247e62ed3a5 100644 (file)
@@ -2,30 +2,73 @@
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
+import '../../base/validators.dart';
+import '../../services/global_widget.dart';
 import '../../setting/global_data.dart';
 import '../../widget/attended_page.dart';
+import '../../widget/message_line.dart';
 import '../../widget/widget_form.dart';
 import 'create_role_page.dart';
 
 final i18n = I18N();
 
-class CreateRoleCustom extends State<CreateRolePage> {
+class CreateRoleCustom extends State<CreateRolePage> with MessageLine {
   final globalData = GlobalData();
   AttendedPage? attendedPage;
-
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'CreateRole');
+  final nameController = TextEditingController();
   CreateRoleCustom();
   @override
   Widget build(BuildContext context) {
     final padding = GlobalThemeData.padding;
+    nameController.text = _fieldData.name;
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: nameController,
+            decoration: InputDecoration(labelText: i18n.tr('Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.name = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => verifyAndStore(),
+              child: Text(i18n.tr('Save'))),
+          weight: 8,
+          gapAbove: 2 * padding),
+      FormItem(
+          ElevatedButton(
+            onPressed: () {
+              attendedPage!.pageStates.dbDataState.clear();
+              globalData.navigate(context, '/Roles/list');
+            },
+            child: Text(i18n.tr('Cancel')),
+          ),
+          weight: 4)
+    ];
     final rc = Scaffold(
-        appBar: globalData.appBarBuilder(i18n.tr('Change Role data')),
+        appBar: globalData.appBarBuilder(i18n.tr('New Role')),
         drawer: globalData.drawerBuilder(context),
         body: SafeArea(
-            child: WidgetForm.flexibleGridAttended(
-                attendedPage!.attendedWidgets(),
-                screenWidth: attendedPage!.pageStates.screenWidth,
-                padding: padding)));
+            child: Form(
+                key: _formKey,
+                child: Card(
+                    margin: EdgeInsets.symmetric(
+                        vertical: padding, horizontal: padding),
+                    child: Padding(
+                        padding: EdgeInsets.symmetric(
+                            vertical: padding, horizontal: padding),
+                        child: WidgetForm.flexibleGrid(
+                          formItems,
+                          screenWidth: attendedPage!.pageStates.screenWidth,
+                          padding: padding,
+                        ))))));
     return rc;
   }
 
@@ -33,4 +76,49 @@ class CreateRoleCustom extends State<CreateRolePage> {
   void initState() {
     super.initState();
   }
+
+  void store() {
+    final parameters = <String, dynamic>{
+      'module': 'Roles',
+      'sql': 'insert',
+    };
+    _fieldData.toMap(parameters);
+    globalData.restPersistence!
+        .store(what: 'store', map: parameters)
+        .then((answer) {
+      if (answer.startsWith('id:')) {
+        final id = int.tryParse(answer.substring(3));
+        if (id == null || id == 0) {
+          setError(i18n.tr('Saving data failed: $answer'));
+          setState(() => 1);
+        } else {
+          attendedPage!.pageStates.dbDataState.clear();
+          globalData.navigate(context, '/Roles/edit;$id');
+        }
+      }
+    });
+  }
+
+  void verifyAndStore() {
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      store();
+    }
+  }
+
+  @override
+  void dispose() {
+    nameController.dispose();
+    super.dispose();
+  }
+}
+
+class _FieldData {
+  String name = '';
+
+
+  void toMap(Map<String, dynamic> map) {
+    map[':name'] = name;
+    map[':createdBy'] = GlobalData.loginUserName;
+  }
 }
index 2cd8530ff6ee1cb07d75cb0e9c8dbfc5e5abf649..4ec6c88d247f4f8f2e59f42a4159ecb4d1dbb6e0 100644 (file)
@@ -20,7 +20,7 @@ class CreateRolePage extends StatefulWidget {
 }
 
 class _CreateRolePageState extends CreateRoleCustom {
-  _CreateRolePageState() : super();
+  _CreateRolePageState(): super();
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index e5326de29d56e2e0a27d8b1ce272a0260a779449..fe67f51cc253ba7a07c74074262fecd67ceeefb6 100644 (file)
@@ -2,31 +2,79 @@
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
+import '../../base/validators.dart';
+import '../../services/global_widget.dart';
 import '../../setting/global_data.dart';
 import '../../widget/attended_page.dart';
+import '../../widget/message_line.dart';
 import '../../widget/widget_form.dart';
 import 'edit_role_page.dart';
 
 final i18n = I18N();
 
-class EditRoleCustom extends State<EditRolePage> {
+class EditRoleCustom extends State<EditRolePage> with MessageLine {
   final int primaryKey;
   final globalData = GlobalData();
   AttendedPage? attendedPage;
-
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'EditRole');
+  final nameController = TextEditingController();
   EditRoleCustom(this.primaryKey);
   @override
   Widget build(BuildContext context) {
     final padding = GlobalThemeData.padding;
+    attendedPage?.loadRecord(
+        name: 'record',
+        reload: () => setState(() => 1),
+        onDone: (record) => _fieldData.fromMap(record),
+        parameters: {'module': 'Roles', 'sql': 'byId', ':id': primaryKey});
+    nameController.text = _fieldData.name;
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: nameController,
+            decoration: InputDecoration(labelText: i18n.tr('Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.name = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => verifyAndStore(),
+              child: Text(i18n.tr('Save'))),
+          weight: 8,
+          gapAbove: 2 * padding),
+      FormItem(
+          ElevatedButton(
+            onPressed: () {
+              attendedPage!.pageStates.dbDataState.clear();
+              globalData.navigate(context, '/Roles/list');
+            },
+            child: Text(i18n.tr('Cancel')),
+          ),
+          weight: 4)
+    ];
     final rc = Scaffold(
-        appBar: globalData.appBarBuilder(i18n.tr('Change Role data')),
+        appBar: globalData.appBarBuilder(i18n.tr('Change Role')),
         drawer: globalData.drawerBuilder(context),
         body: SafeArea(
-            child: WidgetForm.flexibleGridAttended(
-                attendedPage!.attendedWidgets(),
-                screenWidth: attendedPage!.pageStates.screenWidth,
-                padding: padding)));
+            child: Form(
+                key: _formKey,
+                child: Card(
+                    margin: EdgeInsets.symmetric(
+                        vertical: padding, horizontal: padding),
+                    child: Padding(
+                        padding: EdgeInsets.symmetric(
+                            vertical: padding, horizontal: padding),
+                        child: WidgetForm.flexibleGrid(
+                          formItems,
+                          screenWidth: attendedPage!.pageStates.screenWidth,
+                          padding: padding,
+                        ))))));
     return rc;
   }
 
@@ -34,4 +82,43 @@ class EditRoleCustom extends State<EditRolePage> {
   void initState() {
     super.initState();
   }
+
+  void store() {
+    final parameters = <String, dynamic>{
+      'module': 'Roles',
+      'sql': 'update',
+    };
+    parameters[':id'] = primaryKey;
+    _fieldData.toMap(parameters);
+    globalData.restPersistence!
+        .store(what: 'store', map: parameters)
+        .then((answer) {});
+  }
+
+  void verifyAndStore() {
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      store();
+    }
+  }
+
+  @override
+  void dispose() {
+    nameController.dispose();
+    super.dispose();
+  }
+}
+
+class _FieldData {
+  String name = '';
+
+  void fromMap(Map<String, dynamic> map) {
+    name = map['role_name'];
+  }
+
+  void toMap(Map<String, dynamic> map) {
+    // please set outside: map[':id'] = primaryKey;
+    map[':name'] = name;
+    map[':changedBy'] = GlobalData.loginUserName;
+  }
 }
index 6c32f014345b856ae772492995f4f13872267312..ef15ac45d8661adb74e1558911f0d05741b1b6b9 100644 (file)
@@ -21,7 +21,7 @@ class EditRolePage extends StatefulWidget {
 }
 
 class _EditRolePageState extends EditRoleCustom {
-  _EditRolePageState(int primaryKey) : super(primaryKey);
+  _EditRolePageState(int primaryKey): super(primaryKey);
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index b73090e8598c351f822ff4b6868d6c1f5d9c3e7a..32e6ed81b15bfccbea06682ef5746a09ffc7c222 100644 (file)
@@ -2,7 +2,9 @@
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
+import '../../services/global_widget.dart';
 import '../../setting/global_data.dart';
 import '../../widget/attended_page.dart';
 import '../../widget/widget_form.dart';
@@ -13,24 +15,103 @@ final i18n = I18N();
 class ListRoleCustom extends State<ListRolePage> {
   final globalData = GlobalData();
   AttendedPage? attendedPage;
-
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'CreateRole');
+  final textController = TextEditingController();
   ListRoleCustom();
   @override
   Widget build(BuildContext context) {
     final padding = GlobalThemeData.padding;
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: textController,
+            decoration: InputDecoration(labelText: i18n.tr('Text')),
+            onSaved: (value) => _fieldData.text = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => search(), child: Text(i18n.tr('Search'))),
+          weight: 12,
+          gapAbove: padding),
+    ];
+    final form = Form(
+        key: _formKey,
+        child: Card(
+            color: GlobalThemeData.formBackgroundColor,
+            elevation: GlobalThemeData.formElevation,
+            margin:
+                EdgeInsets.symmetric(vertical: padding, horizontal: padding),
+            child: Padding(
+                padding: EdgeInsets.symmetric(
+                    vertical: padding, horizontal: padding),
+                child: WidgetForm.flexibleGrid(formItems,
+                    screenWidth: attendedPage!.pageStates.screenWidth,
+                    padding: padding))));
+    final rows = attendedPage!.getRows(
+        columnList: 'role_id;role_name',
+        what: 'query',
+        parameters: {
+          'module': 'Roles',
+          'sql': 'list',
+          'offset': '0',
+          'size': '10',
+          ':text': _fieldData.text,
+        },
+        onDone: () => setState(() => 1),
+        routeEdit: '/Roles/edit',
+        context: context);
+    final table = DataTable(
+      columns: <DataColumn>[
+        DataColumn(
+          label: Text(i18n.tr('d;Name')),
+        ),
+      ],
+      rows: rows,
+    );
+    final frameWidget = Column(children: [
+      form,
+      SizedBox(height: padding),
+      SizedBox(width: double.infinity, child: table),
+    ]);
     final rc = Scaffold(
-        appBar: globalData.appBarBuilder(i18n.tr('Change Role data')),
+        appBar: globalData.appBarBuilder(i18n.tr('Overview roles')),
         drawer: globalData.drawerBuilder(context),
-        body: SafeArea(
-            child: WidgetForm.flexibleGridAttended(
-                attendedPage!.attendedWidgets(),
-                screenWidth: attendedPage!.pageStates.screenWidth,
-                padding: padding)));
+        floatingActionButton: FloatingActionButton(
+          onPressed: () {
+            globalData.navigate(context, '/Roles/create');
+          },
+          child: const Icon(Icons.add),
+          //backgroundColor: Colors.green,
+        ),
+        body: SafeArea(child: frameWidget));
     return rc;
   }
 
+  @override
+  void dispose() {
+    helperDummyUsage();
+    globalWidgetDummyUsage();
+    textController.dispose();
+    super.dispose();
+  }
+
   @override
   void initState() {
     super.initState();
   }
+
+  void search() {
+    attendedPage!.pageStates.dbDataState.clear();
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      setState(() => 1);
+    }
+  }
+}
+
+class _FieldData {
+  String text = '';
 }
index 0915e10602594259aefa4ae513f0e1c5d86433d2..b42f052403af7c5e5350e744c837b61cbd7126b8 100644 (file)
@@ -20,7 +20,7 @@ class ListRolePage extends StatefulWidget {
 }
 
 class _ListRolePageState extends ListRoleCustom {
-  _ListRolePageState() : super();
+  _ListRolePageState(): super();
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index 3a0da8bc366ba8b102d41553145b1cf7ec3de35f..74cd990221e674676d25a22ea1f9b71a7176ed77 100644 (file)
@@ -2,83 +2,61 @@
 import '../../base/defines.dart';
 import '../../base/helper.dart';
 import '../../persistence/data_record.dart';
-
-class RoleData extends DataRecord<int> {
+class RoleData extends DataRecord<int>{
   int? id;
   String? name;
   DateTime? created;
   String? createdBy;
   DateTime? changed;
   String? changedBy;
-  RoleData(
-      {this.id,
-      this.name,
-      this.created,
-      this.createdBy,
-      this.changed,
-      this.changedBy});
+  RoleData({
+ this.id, this.name, this.created, this.createdBy, this.changed, this.changedBy});
   RoleData.createFromMap(DataMap map) {
     fromMap(map);
   }
   @override
   void fromMap(DataMap map) {
-    id = map.containsKey('role_id')
-        ? valueOf(DataType.reference, map['role_id'])
-        : null;
-    name = map.containsKey('role_name')
-        ? valueOf(DataType.string, map['role_name'])
-        : null;
-    created = map.containsKey('role_created')
-        ? valueOf(DataType.datetime, map['role_created'])
-        : null;
-    createdBy = map.containsKey('role_createdby')
-        ? valueOf(DataType.string, map['role_createdby'])
-        : null;
-    changed = map.containsKey('role_changed')
-        ? valueOf(DataType.datetime, map['role_changed'])
-        : null;
-    changedBy = map.containsKey('role_changedby')
-        ? valueOf(DataType.string, map['role_changedby'])
-        : null;
+    id = map.containsKey('role_id') ? fromString(map['role_id'], dataType: DataType.reference) : null;
+    name = map.containsKey('role_name') ? fromString(map['role_name'], dataType: DataType.string) : null;
+    created = map.containsKey('role_created') ? fromString(map['role_created'], dataType: DataType.datetime) : null;
+    createdBy = map.containsKey('role_createdby') ? fromString(map['role_createdby'], dataType: DataType.string) : null;
+    changed = map.containsKey('role_changed') ? fromString(map['role_changed'], dataType: DataType.datetime) : null;
+    changedBy = map.containsKey('role_changedby') ? fromString(map['role_changedby'], dataType: DataType.string) : null;
   }
-
   @override
   int keyOf() {
     return id ?? 0;
   }
-
   @override
-  String nameOfKey() {
+  String nameOfKey(){
     return 'role_id';
   }
-
   static DataType? dataTypeOf(String name) {
     DataType? rc;
-    switch (name) {
-      case 'id':
-        rc = DataType.reference;
-        break;
-      case 'name':
-        rc = DataType.string;
-        break;
-      case 'created':
-        rc = DataType.datetime;
-        break;
-      case 'createdBy':
-        rc = DataType.string;
-        break;
-      case 'changed':
-        rc = DataType.datetime;
-        break;
-      case 'changedBy':
-        rc = DataType.string;
-        break;
-      default:
-        break;
+    switch(name){
+    case 'id':
+      rc = DataType.reference;
+      break;
+    case 'name':
+      rc = DataType.string;
+      break;
+    case 'created':
+      rc = DataType.datetime;
+      break;
+    case 'createdBy':
+      rc = DataType.string;
+      break;
+    case 'changed':
+      rc = DataType.datetime;
+      break;
+    case 'changedBy':
+      rc = DataType.string;
+      break;
+    default:
+      break;
     }
     return rc;
   }
-
   @override
   DataMap toMap({DataMap? map, bool clear = true}) {
     map ??= DataMap();
index 113246374523097f2ec692613ed0fdbe0b5690e8..c86d7afb1d875c6011a5d5d428bd9d98f69e25a9 100644 (file)
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
+import '../../base/validators.dart';
+import '../../services/global_widget.dart';
 import '../../setting/global_data.dart';
 import '../../widget/attended_page.dart';
+import '../../widget/message_line.dart';
 import '../../widget/widget_form.dart';
 import 'create_structure_page.dart';
 
 final i18n = I18N();
 
-class CreateStructureCustom extends State<CreateStructurePage> {
+class CreateStructureCustom extends State<CreateStructurePage> with MessageLine {
   final globalData = GlobalData();
   AttendedPage? attendedPage;
-
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'CreateStructure');
+  final scopeController = TextEditingController();
+  final nameController = TextEditingController();
+  final valueController = TextEditingController();
+  final positionController = TextEditingController();
   CreateStructureCustom();
   @override
   Widget build(BuildContext context) {
     final padding = GlobalThemeData.padding;
+    scopeController.text = _fieldData.scope;
+    nameController.text = _fieldData.name;
+    valueController.text = _fieldData.value;
+    positionController.text = asString(_fieldData.position);
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: scopeController,
+            decoration: InputDecoration(labelText: i18n.tr('Scope')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.scope = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: nameController,
+            decoration: InputDecoration(labelText: i18n.tr('Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.name = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: valueController,
+            decoration: InputDecoration(labelText: i18n.tr('Value')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.value = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: positionController,
+            decoration: InputDecoration(labelText: i18n.tr('Position')),
+            onSaved: (value) => _fieldData.position = fromString(value ?? '', dataType: DataType.int)
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => verifyAndStore(),
+              child: Text(i18n.tr('Save'))),
+          weight: 8,
+          gapAbove: 2 * padding),
+      FormItem(
+          ElevatedButton(
+            onPressed: () {
+              attendedPage!.pageStates.dbDataState.clear();
+              globalData.navigate(context, '/Structures/list');
+            },
+            child: Text(i18n.tr('Cancel')),
+          ),
+          weight: 4)
+    ];
     final rc = Scaffold(
-        appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')),
+        appBar: globalData.appBarBuilder(i18n.tr('New Structure')),
         drawer: globalData.drawerBuilder(context),
         body: SafeArea(
-            child: WidgetForm.flexibleGridAttended(
-                attendedPage!.attendedWidgets(),
-                screenWidth: attendedPage!.pageStates.screenWidth,
-                padding: padding)));
+            child: Form(
+                key: _formKey,
+                child: Card(
+                    margin: EdgeInsets.symmetric(
+                        vertical: padding, horizontal: padding),
+                    child: Padding(
+                        padding: EdgeInsets.symmetric(
+                            vertical: padding, horizontal: padding),
+                        child: WidgetForm.flexibleGrid(
+                          formItems,
+                          screenWidth: attendedPage!.pageStates.screenWidth,
+                          padding: padding,
+                        ))))));
     return rc;
   }
 
@@ -33,4 +105,58 @@ class CreateStructureCustom extends State<CreateStructurePage> {
   void initState() {
     super.initState();
   }
+
+  void store() {
+    final parameters = <String, dynamic>{
+      'module': 'Structures',
+      'sql': 'insert',
+    };
+    _fieldData.toMap(parameters);
+    globalData.restPersistence!
+        .store(what: 'store', map: parameters)
+        .then((answer) {
+      if (answer.startsWith('id:')) {
+        final id = int.tryParse(answer.substring(3));
+        if (id == null || id == 0) {
+          setError(i18n.tr('Saving data failed: $answer'));
+          setState(() => 1);
+        } else {
+          attendedPage!.pageStates.dbDataState.clear();
+          globalData.navigate(context, '/Structures/edit;$id');
+        }
+      }
+    });
+  }
+
+  void verifyAndStore() {
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      store();
+    }
+  }
+
+  @override
+  void dispose() {
+    scopeController.dispose();
+    nameController.dispose();
+    valueController.dispose();
+    positionController.dispose();
+    super.dispose();
+  }
+}
+
+class _FieldData {
+  String scope = '';
+  String name = '';
+  String value = '';
+  int position = 0;
+
+
+  void toMap(Map<String, dynamic> map) {
+    map[':scope'] = scope;
+    map[':name'] = name;
+    map[':value'] = value;
+    map[':position'] = asString(position);
+    map[':createdBy'] = GlobalData.loginUserName;
+  }
 }
index e27c01ef4d389921765ffa79c6ec298b77d72a38..88aa0fbe5e25be84fab24c4989cfcb8ab4c49d92 100644 (file)
@@ -12,15 +12,15 @@ class CreateStructurePage extends StatefulWidget {
   @override
   _CreateStructurePageState createState() {
     final rc = _CreateStructurePageState();
-    rc.attendedPage = AttendedPage(
-        this, rc, GlobalData(), StructureMeta.instance, pageStates);
+    rc.attendedPage =
+        AttendedPage(this, rc, GlobalData(), StructureMeta.instance, pageStates);
     pageStates.attendedPage = rc.attendedPage;
     return rc;
   }
 }
 
 class _CreateStructurePageState extends CreateStructureCustom {
-  _CreateStructurePageState() : super();
+  _CreateStructurePageState(): super();
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index d1dcfb223cb694bea1e76388745609a3b9969e41..fc775c3d52ace5f134d8cb6d22a3367e37704fd9 100644 (file)
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
+import '../../base/validators.dart';
+import '../../services/global_widget.dart';
 import '../../setting/global_data.dart';
 import '../../widget/attended_page.dart';
+import '../../widget/message_line.dart';
 import '../../widget/widget_form.dart';
 import 'delete_structure_page.dart';
 
 final i18n = I18N();
 
-class DeleteStructureCustom extends State<DeleteStructurePage> {
+class DeleteStructureCustom extends State<DeleteStructurePage> with MessageLine {
   final int primaryKey;
   final globalData = GlobalData();
   AttendedPage? attendedPage;
-
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'DeleteStructure');
+  final scopeController = TextEditingController();
+  final nameController = TextEditingController();
+  final valueController = TextEditingController();
+  final positionController = TextEditingController();
   DeleteStructureCustom(this.primaryKey);
   @override
   Widget build(BuildContext context) {
     final padding = GlobalThemeData.padding;
+    attendedPage?.loadRecord(
+        name: 'record',
+        reload: () => setState(() => 1),
+        onDone: (record) => _fieldData.fromMap(record),
+        parameters: {'module': 'Structures', 'sql': 'byId', ':id': primaryKey});
+    scopeController.text = _fieldData.scope;
+    nameController.text = _fieldData.name;
+    valueController.text = _fieldData.value;
+    positionController.text = asString(_fieldData.position);
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: scopeController,
+            decoration: InputDecoration(labelText: i18n.tr('Scope')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.scope = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: nameController,
+            decoration: InputDecoration(labelText: i18n.tr('Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.name = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: valueController,
+            decoration: InputDecoration(labelText: i18n.tr('Value')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.value = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: positionController,
+            decoration: InputDecoration(labelText: i18n.tr('Position')),
+            onSaved: (value) => _fieldData.position = fromString(value ?? '', dataType: DataType.int)
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => verifyAndDelete(),
+              child: Text(i18n.tr('Delete'))),
+          weight: 8,
+          gapAbove: 2 * padding),
+      FormItem(
+          ElevatedButton(
+            onPressed: () {
+              attendedPage!.pageStates.dbDataState.clear();
+              globalData.navigate(context, '/Structures/list');
+            },
+            child: Text(i18n.tr('Cancel')),
+          ),
+          weight: 4)
+    ];
     final rc = Scaffold(
-        appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')),
+        appBar: globalData.appBarBuilder(i18n.tr('Delete Structure')),
         drawer: globalData.drawerBuilder(context),
         body: SafeArea(
-            child: WidgetForm.flexibleGridAttended(
-                attendedPage!.attendedWidgets(),
-                screenWidth: attendedPage!.pageStates.screenWidth,
-                padding: padding)));
+            child: Form(
+                key: _formKey,
+                child: Card(
+                    margin: EdgeInsets.symmetric(
+                        vertical: padding, horizontal: padding),
+                    child: Padding(
+                        padding: EdgeInsets.symmetric(
+                            vertical: padding, horizontal: padding),
+                        child: WidgetForm.flexibleGrid(
+                          formItems,
+                          screenWidth: attendedPage!.pageStates.screenWidth,
+                          padding: padding,
+                        ))))));
     return rc;
   }
 
@@ -34,4 +111,47 @@ class DeleteStructureCustom extends State<DeleteStructurePage> {
   void initState() {
     super.initState();
   }
+
+  void delete() {
+    final parameters = <String, dynamic>{
+      'module': 'Structures',
+      'sql': 'delete',
+    };
+    parameters[':id'] = primaryKey;
+    globalData.restPersistence!
+        .store(what: 'store', map: parameters)
+        .then((answer) {
+      globalData.navigate(context, '/Structures/list');
+    });
+  }
+
+  void verifyAndDelete() {
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      delete();
+    }
+  }
+
+  @override
+  void dispose() {
+    scopeController.dispose();
+    nameController.dispose();
+    valueController.dispose();
+    positionController.dispose();
+    super.dispose();
+  }
+}
+
+class _FieldData {
+  String scope = '';
+  String name = '';
+  String value = '';
+  int position = 0;
+
+  void fromMap(Map<String, dynamic> map) {
+    scope = map['structure_scope'];
+    name = map['structure_name'];
+    value = map['structure_value'];
+    position = map['structure_position'];
+  }
 }
index cc888a8d54a22aeed3b844d899b1fcdfd35390d2..2bdedf31d7acb9ce08674906ee7eb17e63100090 100644 (file)
@@ -13,15 +13,15 @@ class DeleteStructurePage extends StatefulWidget {
   @override
   _DeleteStructurePageState createState() {
     final rc = _DeleteStructurePageState(this.primaryKey);
-    rc.attendedPage = AttendedPage(
-        this, rc, GlobalData(), StructureMeta.instance, pageStates);
+    rc.attendedPage =
+        AttendedPage(this, rc, GlobalData(), StructureMeta.instance, pageStates);
     pageStates.attendedPage = rc.attendedPage;
     return rc;
   }
 }
 
 class _DeleteStructurePageState extends DeleteStructureCustom {
-  _DeleteStructurePageState(int primaryKey) : super(primaryKey);
+  _DeleteStructurePageState(int primaryKey): super(primaryKey);
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index b3310837b3221695873b5dbbffb3b96a30e21018..58fe2a8fabd1eddd51320b7322443b9df0801166 100644 (file)
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
+import '../../base/validators.dart';
+import '../../services/global_widget.dart';
 import '../../setting/global_data.dart';
 import '../../widget/attended_page.dart';
+import '../../widget/message_line.dart';
 import '../../widget/widget_form.dart';
 import 'edit_structure_page.dart';
 
 final i18n = I18N();
 
-class EditStructureCustom extends State<EditStructurePage> {
+class EditStructureCustom extends State<EditStructurePage> with MessageLine {
   final int primaryKey;
   final globalData = GlobalData();
   AttendedPage? attendedPage;
-
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'EditStructure');
+  final scopeController = TextEditingController();
+  final nameController = TextEditingController();
+  final valueController = TextEditingController();
+  final positionController = TextEditingController();
   EditStructureCustom(this.primaryKey);
   @override
   Widget build(BuildContext context) {
     final padding = GlobalThemeData.padding;
+    attendedPage?.loadRecord(
+        name: 'record',
+        reload: () => setState(() => 1),
+        onDone: (record) => _fieldData.fromMap(record),
+        parameters: {'module': 'Structures', 'sql': 'byId', ':id': primaryKey});
+    scopeController.text = _fieldData.scope;
+    nameController.text = _fieldData.name;
+    valueController.text = _fieldData.value;
+    positionController.text = asString(_fieldData.position);
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: scopeController,
+            decoration: InputDecoration(labelText: i18n.tr('Scope')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.scope = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: nameController,
+            decoration: InputDecoration(labelText: i18n.tr('Name')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.name = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: valueController,
+            decoration: InputDecoration(labelText: i18n.tr('Value')),
+            validator: (input) => notEmpty(input),
+            onSaved: (value) => _fieldData.value = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          TextFormField(
+            controller: positionController,
+            decoration: InputDecoration(labelText: i18n.tr('Position')),
+            onSaved: (value) => _fieldData.position = fromString(value ?? '', dataType: DataType.int)
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => verifyAndStore(),
+              child: Text(i18n.tr('Save'))),
+          weight: 8,
+          gapAbove: 2 * padding),
+      FormItem(
+          ElevatedButton(
+            onPressed: () {
+              attendedPage!.pageStates.dbDataState.clear();
+              globalData.navigate(context, '/Structures/list');
+            },
+            child: Text(i18n.tr('Cancel')),
+          ),
+          weight: 4)
+    ];
     final rc = Scaffold(
-        appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')),
+        appBar: globalData.appBarBuilder(i18n.tr('Change Structure')),
         drawer: globalData.drawerBuilder(context),
         body: SafeArea(
-            child: WidgetForm.flexibleGridAttended(
-                attendedPage!.attendedWidgets(),
-                screenWidth: attendedPage!.pageStates.screenWidth,
-                padding: padding)));
+            child: Form(
+                key: _formKey,
+                child: Card(
+                    margin: EdgeInsets.symmetric(
+                        vertical: padding, horizontal: padding),
+                    child: Padding(
+                        padding: EdgeInsets.symmetric(
+                            vertical: padding, horizontal: padding),
+                        child: WidgetForm.flexibleGrid(
+                          formItems,
+                          screenWidth: attendedPage!.pageStates.screenWidth,
+                          padding: padding,
+                        ))))));
     return rc;
   }
 
@@ -34,4 +111,55 @@ class EditStructureCustom extends State<EditStructurePage> {
   void initState() {
     super.initState();
   }
+
+  void store() {
+    final parameters = <String, dynamic>{
+      'module': 'Structures',
+      'sql': 'update',
+    };
+    parameters[':id'] = primaryKey;
+    _fieldData.toMap(parameters);
+    globalData.restPersistence!
+        .store(what: 'store', map: parameters)
+        .then((answer) {});
+  }
+
+  void verifyAndStore() {
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      store();
+    }
+  }
+
+  @override
+  void dispose() {
+    scopeController.dispose();
+    nameController.dispose();
+    valueController.dispose();
+    positionController.dispose();
+    super.dispose();
+  }
+}
+
+class _FieldData {
+  String scope = '';
+  String name = '';
+  String value = '';
+  int position = 0;
+
+  void fromMap(Map<String, dynamic> map) {
+    scope = map['structure_scope'];
+    name = map['structure_name'];
+    value = map['structure_value'];
+    position = map['structure_position'];
+  }
+
+  void toMap(Map<String, dynamic> map) {
+    // please set outside: map[':id'] = primaryKey;
+    map[':scope'] = scope;
+    map[':name'] = name;
+    map[':value'] = value;
+    map[':position'] = asString(position);
+    map[':changedBy'] = GlobalData.loginUserName;
+  }
 }
index a689d34c69fec6ed85983cb17934339c8cad2bd2..c151f661d5bdbd2569f26da42d8f1c67298cc1af 100644 (file)
@@ -13,15 +13,15 @@ class EditStructurePage extends StatefulWidget {
   @override
   _EditStructurePageState createState() {
     final rc = _EditStructurePageState(this.primaryKey);
-    rc.attendedPage = AttendedPage(
-        this, rc, GlobalData(), StructureMeta.instance, pageStates);
+    rc.attendedPage =
+        AttendedPage(this, rc, GlobalData(), StructureMeta.instance, pageStates);
     pageStates.attendedPage = rc.attendedPage;
     return rc;
   }
 }
 
 class _EditStructurePageState extends EditStructureCustom {
-  _EditStructurePageState(int primaryKey) : super(primaryKey);
+  _EditStructurePageState(int primaryKey): super(primaryKey);
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index eb54b7d0b0e6ff1bcee6add70108e0a3d0ff2cb5..28c0a643473a502681c6e197402302003b15f325 100644 (file)
@@ -2,7 +2,9 @@
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
+import '../../services/global_widget.dart';
 import '../../setting/global_data.dart';
 import '../../widget/attended_page.dart';
 import '../../widget/widget_form.dart';
@@ -13,24 +15,103 @@ final i18n = I18N();
 class ListStructureCustom extends State<ListStructurePage> {
   final globalData = GlobalData();
   AttendedPage? attendedPage;
-
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'CreateStructure');
+  final textController = TextEditingController();
   ListStructureCustom();
   @override
   Widget build(BuildContext context) {
     final padding = GlobalThemeData.padding;
+    final formItems = <FormItem>[
+      FormItem(
+          TextFormField(
+            controller: textController,
+            decoration: InputDecoration(labelText: i18n.tr('Text')),
+            onSaved: (value) => _fieldData.text = value ?? ''
+          ),
+          weight: 6),
+      FormItem(
+          ElevatedButton(
+              onPressed: () => search(), child: Text(i18n.tr('Search'))),
+          weight: 12,
+          gapAbove: padding),
+    ];
+    final form = Form(
+        key: _formKey,
+        child: Card(
+            color: GlobalThemeData.formBackgroundColor,
+            elevation: GlobalThemeData.formElevation,
+            margin:
+                EdgeInsets.symmetric(vertical: padding, horizontal: padding),
+            child: Padding(
+                padding: EdgeInsets.symmetric(
+                    vertical: padding, horizontal: padding),
+                child: WidgetForm.flexibleGrid(formItems,
+                    screenWidth: attendedPage!.pageStates.screenWidth,
+                    padding: padding))));
+    final rows = attendedPage!.getRows(
+        columnList: 'structure_id;structure_scope;structure_name;structure_value;structure_position',
+        what: 'query',
+        parameters: {
+          'module': 'Structures',
+          'sql': 'list',
+          'offset': '0',
+          'size': '10',
+          ':text': _fieldData.text,
+        },
+        onDone: () => setState(() => 1),
+        routeEdit: '/Structures/edit',
+        context: context);
+    final table = DataTable(
+      columns: <DataColumn>[
+        DataColumn(
+          label: Text(i18n.tr('d;Scope;Name;Value;Position')),
+        ),
+      ],
+      rows: rows,
+    );
+    final frameWidget = Column(children: [
+      form,
+      SizedBox(height: padding),
+      SizedBox(width: double.infinity, child: table),
+    ]);
     final rc = Scaffold(
-        appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')),
+        appBar: globalData.appBarBuilder(i18n.tr('Overview structures')),
         drawer: globalData.drawerBuilder(context),
-        body: SafeArea(
-            child: WidgetForm.flexibleGridAttended(
-                attendedPage!.attendedWidgets(),
-                screenWidth: attendedPage!.pageStates.screenWidth,
-                padding: padding)));
+        floatingActionButton: FloatingActionButton(
+          onPressed: () {
+            globalData.navigate(context, '/Structures/create');
+          },
+          child: const Icon(Icons.add),
+          //backgroundColor: Colors.green,
+        ),
+        body: SafeArea(child: frameWidget));
     return rc;
   }
 
+  @override
+  void dispose() {
+    helperDummyUsage();
+    globalWidgetDummyUsage();
+    textController.dispose();
+    super.dispose();
+  }
+
   @override
   void initState() {
     super.initState();
   }
+
+  void search() {
+    attendedPage!.pageStates.dbDataState.clear();
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      setState(() => 1);
+    }
+  }
+}
+
+class _FieldData {
+  String text = '';
 }
index 55c901c8bcbfdd9dcea86dd63d0b80206cc58b03..e286fbc4ae0f50a1a783ec73762412bb8bc7e659 100644 (file)
@@ -12,15 +12,15 @@ class ListStructurePage extends StatefulWidget {
   @override
   _ListStructurePageState createState() {
     final rc = _ListStructurePageState();
-    rc.attendedPage = AttendedPage(
-        this, rc, GlobalData(), StructureMeta.instance, pageStates);
+    rc.attendedPage =
+        AttendedPage(this, rc, GlobalData(), StructureMeta.instance, pageStates);
     pageStates.attendedPage = rc.attendedPage;
     return rc;
   }
 }
 
 class _ListStructurePageState extends ListStructureCustom {
-  _ListStructurePageState() : super();
+  _ListStructurePageState(): super();
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
diff --git a/lib/page/structures/structure_data.dart b/lib/page/structures/structure_data.dart
new file mode 100644 (file)
index 0000000..85285ec
--- /dev/null
@@ -0,0 +1,92 @@
+// DO NOT CHANGE. This file is created by the meta_tool
+import '../../base/defines.dart';
+import '../../base/helper.dart';
+import '../../persistence/data_record.dart';
+class StructureData extends DataRecord<int>{
+  int? id;
+  String? scope;
+  String? name;
+  String? value;
+  int? position;
+  DateTime? created;
+  String? createdBy;
+  DateTime? changed;
+  String? changedBy;
+  StructureData({
+ this.id, this.scope, this.name, this.value, this.position, this.created, this.createdBy, this.changed, this.changedBy});
+  StructureData.createFromMap(DataMap map) {
+    fromMap(map);
+  }
+  @override
+  void fromMap(DataMap map) {
+    id = map.containsKey('structure_id') ? fromString(map['structure_id'], dataType: DataType.reference) : null;
+    scope = map.containsKey('structure_scope') ? fromString(map['structure_scope'], dataType: DataType.string) : null;
+    name = map.containsKey('structure_name') ? fromString(map['structure_name'], dataType: DataType.string) : null;
+    value = map.containsKey('structure_value') ? fromString(map['structure_value'], dataType: DataType.string) : null;
+    position = map.containsKey('structure_position') ? fromString(map['structure_position'], dataType: DataType.int) : null;
+    created = map.containsKey('structure_created') ? fromString(map['structure_created'], dataType: DataType.datetime) : null;
+    createdBy = map.containsKey('structure_createdby') ? fromString(map['structure_createdby'], dataType: DataType.string) : null;
+    changed = map.containsKey('structure_changed') ? fromString(map['structure_changed'], dataType: DataType.datetime) : null;
+    changedBy = map.containsKey('structure_changedby') ? fromString(map['structure_changedby'], dataType: DataType.string) : null;
+  }
+  @override
+  int keyOf() {
+    return id ?? 0;
+  }
+  @override
+  String nameOfKey(){
+    return 'structure_id';
+  }
+  static DataType? dataTypeOf(String name) {
+    DataType? rc;
+    switch(name){
+    case 'id':
+      rc = DataType.reference;
+      break;
+    case 'scope':
+      rc = DataType.string;
+      break;
+    case 'name':
+      rc = DataType.string;
+      break;
+    case 'value':
+      rc = DataType.string;
+      break;
+    case 'position':
+      rc = DataType.int;
+      break;
+    case 'created':
+      rc = DataType.datetime;
+      break;
+    case 'createdBy':
+      rc = DataType.string;
+      break;
+    case 'changed':
+      rc = DataType.datetime;
+      break;
+    case 'changedBy':
+      rc = DataType.string;
+      break;
+    default:
+      break;
+    }
+    return rc;
+  }
+  @override
+  DataMap toMap({DataMap? map, bool clear = true}) {
+    map ??= DataMap();
+    if (clear) {
+      map.clear();
+    }
+    map['structure_id'] = id;
+    map['structure_scope'] = scope;
+    map['structure_name'] = name;
+    map['structure_value'] = value;
+    map['structure_position'] = position;
+    map['structure_created'] = created;
+    map['structure_createdby'] = createdBy;
+    map['structure_changed'] = changed;
+    map['structure_changedby'] = changedBy;
+    return map;
+  }
+}
index c0da66b7d760bb1a967bdc5b8f791d5f58c18b4e..615970d4b70e1a9fd0d0ddaf5379ed3f3811e9fe 100644 (file)
@@ -2,6 +2,8 @@
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
 import '../../base/validators.dart';
 import '../../services/global_widget.dart';
@@ -39,7 +41,7 @@ class CreateUserCustom extends State<CreateUserPage> with MessageLine {
             controller: nameController,
             decoration: InputDecoration(labelText: i18n.tr('Name')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.name = value ?? '',
+            onSaved: (value) => _fieldData.name = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -47,7 +49,7 @@ class CreateUserCustom extends State<CreateUserPage> with MessageLine {
             controller: displayNameController,
             decoration: InputDecoration(labelText: i18n.tr('Display name')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.displayName = value ?? '',
+            onSaved: (value) => _fieldData.displayName = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -55,7 +57,7 @@ class CreateUserCustom extends State<CreateUserPage> with MessageLine {
             controller: emailController,
             decoration: InputDecoration(labelText: i18n.tr('EMail')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.email = value ?? '',
+            onSaved: (value) => _fieldData.email = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -69,7 +71,8 @@ class CreateUserCustom extends State<CreateUserPage> with MessageLine {
           weight: 6),
       FormItem(
           ElevatedButton(
-              onPressed: () => verifyAndStore(), child: Text(i18n.tr('Save'))),
+              onPressed: () => verifyAndStore(),
+              child: Text(i18n.tr('Save'))),
           weight: 8,
           gapAbove: 2 * padding),
       FormItem(
@@ -151,11 +154,12 @@ class _FieldData {
   String email = '';
   int role = 0;
 
+
   void toMap(Map<String, dynamic> map) {
     map[':name'] = name;
     map[':displayName'] = displayName;
     map[':email'] = email;
-    map[':role'] = role;
+    map[':role'] = asString(role);
     map[':createdBy'] = GlobalData.loginUserName;
   }
 }
index 71a2c05f8e2aab205a665c480213d491711ed3e2..14e69e258185a24630f5a76f39e934f03133ccc6 100644 (file)
@@ -20,7 +20,7 @@ class CreateUserPage extends StatefulWidget {
 }
 
 class _CreateUserPageState extends CreateUserCustom {
-  _CreateUserPageState() : super();
+  _CreateUserPageState(): super();
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index 65cfc7a7020cdb1a19bfb682e6ac84aa5b903056..64f531d726c149031218783da0f460584cf217ab 100644 (file)
@@ -2,6 +2,8 @@
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
 import '../../base/validators.dart';
 import '../../services/global_widget.dart';
@@ -45,7 +47,7 @@ class DeleteUserCustom extends State<DeleteUserPage> with MessageLine {
             controller: nameController,
             decoration: InputDecoration(labelText: i18n.tr('Name')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.name = value ?? '',
+            onSaved: (value) => _fieldData.name = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -53,7 +55,7 @@ class DeleteUserCustom extends State<DeleteUserPage> with MessageLine {
             controller: displayNameController,
             decoration: InputDecoration(labelText: i18n.tr('Display name')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.displayName = value ?? '',
+            onSaved: (value) => _fieldData.displayName = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -61,7 +63,7 @@ class DeleteUserCustom extends State<DeleteUserPage> with MessageLine {
             controller: emailController,
             decoration: InputDecoration(labelText: i18n.tr('EMail')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.email = value ?? '',
+            onSaved: (value) => _fieldData.email = value ?? ''
           ),
           weight: 6),
       FormItem(
index 8bbef4c01f9cafe001d2b38d6e01af670ac93a85..85cbfc907ceebe2c637ac1bc32c7ee0433342d34 100644 (file)
@@ -21,7 +21,7 @@ class DeleteUserPage extends StatefulWidget {
 }
 
 class _DeleteUserPageState extends DeleteUserCustom {
-  _DeleteUserPageState(int primaryKey) : super(primaryKey);
+  _DeleteUserPageState(int primaryKey): super(primaryKey);
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index 81685c3e059f23e9f65f651d14d5f3680c877bf9..70a9f5078d8a361f54c03846b0480fe86f846c90 100644 (file)
@@ -2,6 +2,8 @@
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
 import '../../base/validators.dart';
 import '../../services/global_widget.dart';
@@ -45,7 +47,7 @@ class EditUserCustom extends State<EditUserPage> with MessageLine {
             controller: nameController,
             decoration: InputDecoration(labelText: i18n.tr('Name')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.name = value ?? '',
+            onSaved: (value) => _fieldData.name = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -53,7 +55,7 @@ class EditUserCustom extends State<EditUserPage> with MessageLine {
             controller: displayNameController,
             decoration: InputDecoration(labelText: i18n.tr('Display name')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.displayName = value ?? '',
+            onSaved: (value) => _fieldData.displayName = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -61,7 +63,7 @@ class EditUserCustom extends State<EditUserPage> with MessageLine {
             controller: emailController,
             decoration: InputDecoration(labelText: i18n.tr('EMail')),
             validator: (input) => notEmpty(input),
-            onSaved: (value) => _fieldData.email = value ?? '',
+            onSaved: (value) => _fieldData.email = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -75,7 +77,8 @@ class EditUserCustom extends State<EditUserPage> with MessageLine {
           weight: 6),
       FormItem(
           ElevatedButton(
-              onPressed: () => verifyAndStore(), child: Text(i18n.tr('Save'))),
+              onPressed: () => verifyAndStore(),
+              child: Text(i18n.tr('Save'))),
           weight: 8,
           gapAbove: 2 * padding),
       FormItem(
@@ -159,7 +162,7 @@ class _FieldData {
     map[':name'] = name;
     map[':displayName'] = displayName;
     map[':email'] = email;
-    map[':role'] = role;
+    map[':role'] = asString(role);
     map[':changedBy'] = GlobalData.loginUserName;
   }
 }
index 4b2e75f96c40371887a1ff257b12738ea63d3dad..11796632306f7b6a0d8a5c1b26bd2b9bd80e6d06 100644 (file)
@@ -21,7 +21,7 @@ class EditUserPage extends StatefulWidget {
 }
 
 class _EditUserPageState extends EditUserCustom {
-  _EditUserPageState(int primaryKey) : super(primaryKey);
+  _EditUserPageState(int primaryKey): super(primaryKey);
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index 4a62b31860afc2f49553c0413bda0c1a4cc7ba3e..b6b8727a5b290f1dc8389fbd2f0ed4161839b824 100644 (file)
@@ -32,7 +32,7 @@ class ListUserCustom extends State<ListUserPage> {
           TextFormField(
             controller: textController,
             decoration: InputDecoration(labelText: i18n.tr('Text')),
-            onSaved: (value) => _fieldData.text = value ?? '',
+            onSaved: (value) => _fieldData.text = value ?? ''
           ),
           weight: 6),
       FormItem(
@@ -118,6 +118,8 @@ class ListUserCustom extends State<ListUserPage> {
 
   @override
   void dispose() {
+    helperDummyUsage();
+    globalWidgetDummyUsage();
     textController.dispose();
     super.dispose();
   }
index 2723f48184f044e8e5216c00a0c1bfb8e4cbba5f..1938d3d9a841fa556eb29744f91b85a73d9fde16 100644 (file)
@@ -20,7 +20,7 @@ class ListUserPage extends StatefulWidget {
 }
 
 class _ListUserPageState extends ListUserCustom {
-  _ListUserPageState() : super();
+  _ListUserPageState(): super();
   @override
   void didChangeDependencies() {
     final size = MediaQuery.of(context).size;
index 5562cfdc9d07ff348da75ee594c11230ae1111a0..d27593e5643dcb2caefe9083e133bf5b52c412c2 100644 (file)
@@ -2,8 +2,7 @@
 import '../../base/defines.dart';
 import '../../base/helper.dart';
 import '../../persistence/data_record.dart';
-
-class UserData extends DataRecord<int> {
+class UserData extends DataRecord<int>{
   int? id;
   String? name;
   String? displayName;
@@ -13,96 +12,66 @@ class UserData extends DataRecord<int> {
   String? createdBy;
   DateTime? changed;
   String? changedBy;
-  UserData(
-      {this.id,
-      this.name,
-      this.displayName,
-      this.email,
-      this.role,
-      this.created,
-      this.createdBy,
-      this.changed,
-      this.changedBy});
+  UserData({
+ this.id, this.name, this.displayName, this.email, this.role, this.created, this.createdBy, this.changed, this.changedBy});
   UserData.createFromMap(DataMap map) {
     fromMap(map);
   }
   @override
   void fromMap(DataMap map) {
-    id = map.containsKey('user_id')
-        ? valueOf(DataType.reference, map['user_id'])
-        : null;
-    name = map.containsKey('user_name')
-        ? valueOf(DataType.string, map['user_name'])
-        : null;
-    displayName = map.containsKey('user_displayname')
-        ? valueOf(DataType.string, map['user_displayname'])
-        : null;
-    email = map.containsKey('user_email')
-        ? valueOf(DataType.string, map['user_email'])
-        : null;
-    role = map.containsKey('user_role')
-        ? valueOf(DataType.reference, map['user_role'])
-        : null;
-    created = map.containsKey('user_created')
-        ? valueOf(DataType.datetime, map['user_created'])
-        : null;
-    createdBy = map.containsKey('user_createdby')
-        ? valueOf(DataType.string, map['user_createdby'])
-        : null;
-    changed = map.containsKey('user_changed')
-        ? valueOf(DataType.datetime, map['user_changed'])
-        : null;
-    changedBy = map.containsKey('user_changedby')
-        ? valueOf(DataType.string, map['user_changedby'])
-        : null;
+    id = map.containsKey('user_id') ? fromString(map['user_id'], dataType: DataType.reference) : null;
+    name = map.containsKey('user_name') ? fromString(map['user_name'], dataType: DataType.string) : null;
+    displayName = map.containsKey('user_displayname') ? fromString(map['user_displayname'], dataType: DataType.string) : null;
+    email = map.containsKey('user_email') ? fromString(map['user_email'], dataType: DataType.string) : null;
+    role = map.containsKey('user_role') ? fromString(map['user_role'], dataType: DataType.reference) : null;
+    created = map.containsKey('user_created') ? fromString(map['user_created'], dataType: DataType.datetime) : null;
+    createdBy = map.containsKey('user_createdby') ? fromString(map['user_createdby'], dataType: DataType.string) : null;
+    changed = map.containsKey('user_changed') ? fromString(map['user_changed'], dataType: DataType.datetime) : null;
+    changedBy = map.containsKey('user_changedby') ? fromString(map['user_changedby'], dataType: DataType.string) : null;
   }
-
   @override
   int keyOf() {
     return id ?? 0;
   }
-
   @override
-  String nameOfKey() {
+  String nameOfKey(){
     return 'user_id';
   }
-
   static DataType? dataTypeOf(String name) {
     DataType? rc;
-    switch (name) {
-      case 'id':
-        rc = DataType.reference;
-        break;
-      case 'name':
-        rc = DataType.string;
-        break;
-      case 'displayName':
-        rc = DataType.string;
-        break;
-      case 'email':
-        rc = DataType.string;
-        break;
-      case 'role':
-        rc = DataType.reference;
-        break;
-      case 'created':
-        rc = DataType.datetime;
-        break;
-      case 'createdBy':
-        rc = DataType.string;
-        break;
-      case 'changed':
-        rc = DataType.datetime;
-        break;
-      case 'changedBy':
-        rc = DataType.string;
-        break;
-      default:
-        break;
+    switch(name){
+    case 'id':
+      rc = DataType.reference;
+      break;
+    case 'name':
+      rc = DataType.string;
+      break;
+    case 'displayName':
+      rc = DataType.string;
+      break;
+    case 'email':
+      rc = DataType.string;
+      break;
+    case 'role':
+      rc = DataType.reference;
+      break;
+    case 'created':
+      rc = DataType.datetime;
+      break;
+    case 'createdBy':
+      rc = DataType.string;
+      break;
+    case 'changed':
+      rc = DataType.datetime;
+      break;
+    case 'changedBy':
+      rc = DataType.string;
+      break;
+    default:
+      break;
     }
     return rc;
   }
-
   @override
   DataMap toMap({DataMap? map, bool clear = true}) {
     map ??= DataMap();
index c826b27205ada14a2f328bb5f931db5575af287f..b3261a3c744f2b5df1d9c8e4031fc12afae60514 100644 (file)
@@ -32,6 +32,12 @@ void comboRolesFromBackend(
       {'module': 'global', 'sql': 'comboRoles'}, onDone);
 }
 
+/// This function is only used to avoid compiler warning "unused import"
+/// for generated code.
+void globalWidgetDummyUsage() {
+  // nothing to do
+}
+
 List<DropdownMenuItem<int>>? _combo(String name, String columnValue,
     String columnText, String? textUndefined, AttendedPage attendedPage) {
   final records = attendedPage.pageStates.dbDataState.listResponse(name);
index fa0bb51d40a75c2e7fd68cd743d4bf97c244c006..4da9320bf8c940ac086c704a37ddbfe44806682f 100644 (file)
@@ -54,8 +54,8 @@ class Generator extends PageGenerator {
       final type = item.dataType.toString();
       //id = data.containsKey('id') ? int.tryParse(data['id']) : null;
       buffer.writeln(
-          "    ${item.name} = map.containsKey('$name') ? valueOf($type, "
-          "map['$name']) : null;");
+          "    ${item.name} = map.containsKey('$name') ? "
+          "fromString(map['$name'], dataType: $type) : null;");
     }
     buffer.writeln('  }');
     final name = primary == null ? 'id' : primary.name;
@@ -184,7 +184,7 @@ List<String> moduleNames(){
             GeneratorBase.classToFilename(module.moduleNameSingular) +
                 '_data.dart';
         final directory = name.toLowerCase();
-        writeFile('../../lib/page/$directory/$filename',
+        writeFile('../lib/page/$directory/$filename',
             generator.createModuleData(module));
       }
     }
index fc5fb42bf448245adbda222824158e6d4d177674..e829ed48977309f2053c6a0c0d57c6011d0930db 100644 (file)
@@ -36,11 +36,6 @@ class GeneratorBase {
     logger.log(line);
   }
 
-  String toCamelCase(String name) {
-    final rc = name.isEmpty ? '' : (name[0].toUpperCase() + name.substring(1));
-    return rc;
-  }
-
   /// Writes a given [contents] into a file named [filename];
   void writeFile(String filename, String contents) {
     logger.log('creating $filename ...');
index 79bc43e718b9e3e1bbac82116332668eb38dc232..d9ddf20eee4615d9a9a2771c2b8a603f69eadcef 100644 (file)
@@ -3,6 +3,7 @@ import 'dart:io';
 import 'package:dart_bones/dart_bones.dart';
 
 import '../lib/base/defines.dart';
+import '../lib/base/helper.dart';
 import '../lib/meta/module_meta_data.dart';
 import '../lib/meta/modules.dart';
 import 'generator.dart';
@@ -132,6 +133,8 @@ class ListUserCustom extends State<ListUserPage> {
 
   @override
   void dispose() {
+    helperDummyUsage();
+    globalWidgetDummyUsage();
 #DISPOSE_CONTROLLER    super.dispose();
   }
 
@@ -158,6 +161,8 @@ class _FieldData {
 // It will never overridden by the meta_tool.
 import 'package:flutter/material.dart';
 
+import '../../base/defines.dart';
+import '../../base/helper.dart';
 import '../../base/i18n.dart';
 import '../../base/validators.dart';
 import '../../services/global_widget.dart';
@@ -248,8 +253,7 @@ class _FieldData {
 #DEF_FIELD
 #FROM_MAP#TO_MAP}
 ''';
-  static final templateStorageDoneCreate =
-      '''
+  static final templateStorageDoneCreate = '''
 
       if (answer.startsWith('id:')) {
         final id = int.tryParse(answer.substring(3));
@@ -350,8 +354,11 @@ StatefulWidget? customPageByRoute(String route) {
     for (var field in page.fields) {
       if (field.widgetType == WidgetType.property &&
           (field as PropertyMetaData).displayType == DisplayType.text) {
-        buffer.writeln(
-            '    ${field.name}Controller.text = _fieldData.${field.name};');
+        var value = '_fieldData.${field.name}';
+        if (field.dataType != DataType.string) {
+          value = 'asString($value)';
+        }
+        buffer.writeln('    ${field.name}Controller.text = $value;');
       }
     }
     return buffer.toString();
@@ -415,12 +422,9 @@ StatefulWidget? customPageByRoute(String route) {
           value = '0';
           break;
         case DataType.date:
-          type = 'Date';
-          value = 'Date()';
-          break;
         case DataType.datetime:
-          type = 'DateTime';
-          value = 'DateTime()';
+          type = 'DateTime?';
+          value = 'null';
           break;
         case DataType.string:
           type = 'String';
@@ -432,7 +436,11 @@ StatefulWidget? customPageByRoute(String route) {
           break;
         // throw FormatException('buildDefinitionFields(): missing ${field2.dataType}');
       }
-      buffer.writeln("  $type $name = $value;");
+      if (value == 'null') {
+        buffer.writeln("  $type $name;");
+      } else {
+        buffer.writeln("  $type $name = $value;");
+      }
     }
     return buffer.toString();
   }
@@ -477,9 +485,14 @@ StatefulWidget? customPageByRoute(String route) {
           }
           validator += '            ]),\n';
         }
+        final value = field.dataType == DataType.string
+            ? "value ?? ''"
+            : (field.dataType == DataType.date
+                ? "fromString(value ?? '', dataType: DataType.date)"
+                : "fromString(value ?? '', dataType: ${field.dataType})");
         rc = '''^TextFormField(
 #CONTR^  decoration: InputDecoration(labelText: i18n.tr('${field.label}')),
-#VALIDATOR^  onSaved: (value) => _fieldData.$name = value ?? '',
+#VALIDATOR^  onSaved: (value) => _fieldData.$name = $value
 ^)'''
             .replaceFirst('#CONTR',
                 withController ? '^  controller: ${name}Controller,\n' : '')
@@ -597,7 +610,7 @@ StatefulWidget? customPageByRoute(String route) {
           ? '.toString()'
           : '';
       var value = '_fieldData.$name$suffix';
-      if (field is PropertyMetaData && field.hasOption(':pattern')){
+      if (field is PropertyMetaData && field.hasOption(':pattern')) {
         value = 'asPattern($value)';
       }
       buffer.writeln("          ':$name': $value,");
@@ -626,7 +639,8 @@ StatefulWidget? customPageByRoute(String route) {
   String buildToMap(PageMetaData page) {
     String? rc;
     if (page.pageType == PageType.edit || page.pageType == PageType.create) {
-      final buffer = StringBuffer('\n  void toMap(Map<String, dynamic> map) {\n');
+      final buffer =
+          StringBuffer('\n  void toMap(Map<String, dynamic> map) {\n');
       if (page.pageType == PageType.edit) {
         buffer.writeln("    // please set outside: map[':id'] = primaryKey;");
       }
@@ -635,7 +649,9 @@ StatefulWidget? customPageByRoute(String route) {
           continue;
         }
         final name = field.name;
-        buffer.writeln("    map[':$name'] = $name;");
+        final value =
+            field.dataType == DataType.string ? name : 'asString($name)';
+        buffer.writeln("    map[':$name'] = $value;");
       }
       buffer.writeln("    map[':#'] = GlobalData.loginUserName;".replaceFirst(
           '#', page.pageType == PageType.edit ? 'changedBy' : 'createdBy'));
index 208f2fc0d178663af1440949cc672e39cf2ab089..1eb09262a8d8f50e70b497f25472e7f0340f4cb0 100644 (file)
@@ -9,6 +9,8 @@ import 'generator_base.dart';
 
 /// Handles the SQL generation part of the generator.
 class SqlGenerator extends GeneratorBase {
+  static final regExprParameters = RegExp(r'(:\w+)');
+
   SqlGenerator(BaseLogger logger) : super(logger);
 
   /// Returns a DDL statement creating the database table of the [module].
@@ -49,8 +51,9 @@ class SqlGenerator extends GeneratorBase {
       for (var page in listPages) {
         if (page is ListPageMetaData) {
           var whereCondition = page.whereCondition;
-          if (whereCondition.endsWith('\n')){
-            whereCondition = whereCondition.substring(0, whereCondition.length - 1);
+          if (whereCondition.endsWith('\n')) {
+            whereCondition =
+                whereCondition.substring(0, whereCondition.length - 1);
           }
           String selectItems2 = '';
           var selectItems =
@@ -74,10 +77,15 @@ class SqlGenerator extends GeneratorBase {
           buffer.writeln('''  type: list
   parameters: [$parameters]
   order: "$order"
-  sql: "SELECT
-$selectItems    t0.*$selectItems2
-    FROM $tableName t0
-$joins$whereCondition    ;"''');
+  sql: |
+    SELECT''');
+          if (selectItems.isNotEmpty) {
+            addToBuffer(selectItems, maxLength: 80, buffer: buffer, indent: 6);
+          }
+          addToBuffer('    t0.*$selectItems2',
+              maxLength: 80, buffer: buffer, indent: 6);
+          buffer.writeln('    FROM $tableName t0');
+          buffer.write('$joins$whereCondition');
         }
       }
     }
@@ -111,9 +119,8 @@ update:
     buffer.write(sqlText);
     var items = module.standardColumns('changedBy');
     var parameters = addToBuffer('  parameters: [', maxLength: 80);
-    var assignments = addToBuffer('    ', maxLength: 80);
+    var assignments = StringBuffer();
     var firstParameter = true;
-    var firstAssignment = true;
     for (var item in items) {
       if (!item.hasOption('hidden')) {
         addToBuffer('":${item.name}"',
@@ -121,32 +128,32 @@ update:
             separator: firstParameter ? null : ',',
             indent: 4,
             buffer: parameters);
-        firstParameter = false;
         if (!item.hasOption('primary')) {
-          addToBuffer('${item.columnName}=:${item.name}',
-              maxLength: 80,
-              separator: firstAssignment ? null : ',',
-              indent: 4,
-              buffer: assignments);
-          firstAssignment = false;
+          assignments.writeln('      ${item.columnName}=:${item.name},');
         }
+        firstParameter = false;
       }
     }
     parameters.write(']');
     var item = module.properties['changed']!;
-    addToBuffer('${item.columnName}=NOW()',
-        maxLength: 80, separator: ',', indent: 4, buffer: assignments);
+    assignments.write('      ${item.columnName}=NOW()');
     // parameters: [":id", ":name", ":displayname", ":email", ":changedby"]
     buffer.writeln(parameters);
-    buffer.write('  sql: "UPDATE $tableName SET\n');
+    buffer.write('  sql: |\n');
+    buffer.write('    UPDATE $tableName SET\n');
     buffer.writeln(assignments);
     //user_name=:name, user_displayname=:displayname, user_email=:email, user_changed=NOW(), user_changedby=:changedby
-    buffer.write('    WHERE ${list[0].columnName}=:${list[0].name};"\n');
+    buffer.write('    WHERE ${list[0].columnName}=:${list[0].name};\n');
 
     items = module.standardColumns('createdBy');
     parameters = addToBuffer('  parameters: [', maxLength: 80);
-    final sql1 = addToBuffer('  sql: "INSERT INTO $tableName(', maxLength: 80);
-    final sql2 = addToBuffer('    VALUES(', maxLength: 80);
+    final sql1 = StringBuffer('  sql: |\n');
+    addToBuffer('    INSERT INTO $tableName(',
+        maxLength: 80, buffer: sql1, indent: 4);
+    final sql2 = addToBuffer(
+      '    VALUES(',
+      maxLength: 80,
+    );
     var first = true;
     for (var item in items) {
       if (!item.hasOption('primary')) {
@@ -172,7 +179,7 @@ update:
     item = module.properties['created']!;
     addToBuffer('${item.columnName})',
         maxLength: 80, separator: ',', indent: 4, buffer: sql1);
-    addToBuffer('NOW());"',
+    addToBuffer('NOW());',
         maxLength: 80, separator: ',', indent: 4, buffer: sql2);
     // parameters: [":name", ":displayname", ":email", ":changedby"]
     buffer.write('''insert:
@@ -183,13 +190,15 @@ update:
     buffer.writeln(sql2);
     return buffer.toString();
   }
-  static final regExprParameters = RegExp(r'(:\w+)');
+
   /// Searches the parameters in the [whereCondition] and checks it against
   /// the [fields].
   String findParameters(String whereCondition, List<WidgetMetaData> fields) {
-    final names = regExprParameters.allMatches(whereCondition)
+    final names = regExprParameters
+        .allMatches(whereCondition)
         .map((element) => element.group(1))
-        .toSet().toList();
+        .toSet()
+        .toList();
     return '"' + names.join('","') + '"';
   }
 
diff --git a/metatool/local.properties b/metatool/local.properties
new file mode 100644 (file)
index 0000000..77df14c
--- /dev/null
@@ -0,0 +1,8 @@
+## This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Sat Oct 16 12:51:13 CEST 2021
+sdk.dir=/opt/android
index 224883d847a9e7040c159c073ff2f096fd7ce37b..0d8234aaf4c8cd003b58f98a6c142b721b86c9d9 100644 (file)
@@ -1,16 +1,18 @@
-name: meta-tool
+name: meta_tool
 description: A generator of programming code for building Flutter apps.
 version: 1.0.0
 homepage: https://github.com/hamatoma/exhibition
 
 environment:
-  sdk: ">=2.12.0 <3.0.0"
+#  sdk: ">=2.15.0 <3.0.0"
+  sdk: ">=2.15.0-163.0.dev <3.0.0"
 
 dependencies:
   meta: ^1.7.0
   sprintf: ^6.0.0
   yaml: ^3.1.0
   path: ^1.8.0
+  dart_bones: ^1.2.2
 
 dev_dependencies:
   pedantic: ^1.11.1
diff --git a/metatool/test/helper_test.dart b/metatool/test/helper_test.dart
new file mode 100644 (file)
index 0000000..f01c0e8
--- /dev/null
@@ -0,0 +1,197 @@
+import 'package:dart_bones/dart_bones.dart';
+import 'package:test/test.dart';
+//import 'package:path/path.dart';
+
+import '../lib/base/defines.dart';
+import '../lib/base/helper.dart';
+import '../lib/base/i18n.dart';
+
+final i18n = I18N();
+
+void main() {
+  final logger = MemoryLogger(LEVEL_FINE);
+  I18N.internal(logger);
+  FileSync.initialize(logger);
+  //final fileSync = FileSync();
+  //final baseDir = init(logger);
+  //final targetDir = join(baseDir, nodeTarget);
+  //fileSync.ensureDirectory(targetDir);
+  group('fromString', () {
+    test('bool', () {
+      expect(fromString('T', dataType: DataType.bool, defaultValue: false), isTrue);
+      expect(fromString('F', dataType: DataType.bool, defaultValue: true), isFalse);
+      expect(fromString(i18n.tr('Yes'), dataType: DataType.bool, defaultValue: false), isTrue);
+      expect(fromString(i18n.tr('No'), dataType: DataType.bool, defaultValue: true), isFalse);
+      expect(fromString('', dataType: DataType.bool, defaultValue: false), isFalse);
+      expect(fromString('', dataType: DataType.bool, defaultValue: true), isTrue);
+    });
+    test('int', ()
+    {
+      expect(fromString('123', dataType: DataType.int, defaultValue: -1),
+          123);
+      expect(fromString('-1234', dataType: DataType.int, defaultValue: -1),
+          -1234);
+      expect(fromString('', dataType: DataType.int, defaultValue: -1),
+          -1);
+      expect(fromString('a15', dataType: DataType.int, defaultValue: -1),
+          -1);
+    });
+    test('nat', ()
+    {
+      expect(fromString('123', dataType: DataType.nat, defaultValue: -1),
+          123);
+      expect(fromString('-1234', dataType: DataType.nat, defaultValue: -1),
+          -1);
+      expect(fromString('', dataType: DataType.nat, defaultValue: -1),
+          -1);
+      expect(fromString('a15', dataType: DataType.nat, defaultValue: -1),
+          -1);
+    });
+    test('reference', ()
+    {
+      expect(fromString('123', dataType: DataType.reference, defaultValue: -1),
+          123);
+      expect(fromString('-1234', dataType: DataType.reference, defaultValue: -1),
+          -1234);
+      expect(fromString('', dataType: DataType.reference, defaultValue: -1),
+          -1);
+      expect(fromString('a15', dataType: DataType.reference, defaultValue: -1),
+          -1);
+    });
+    test('float', ()
+    {
+      expect(fromString('123.76', dataType: DataType.float, defaultValue: -1),
+          123.76);
+      expect(fromString('-4123.76', dataType: DataType.float, defaultValue: -1),
+          -4123.76);
+      expect(fromString('', dataType: DataType.float, defaultValue: -99999999),
+          -99999999);
+      expect(fromString('Nothing', dataType: DataType.float, defaultValue: -99999999),
+          -99999999);
+    });
+    test('currency', ()
+    {
+      expect(fromString('123.76', dataType: DataType.currency, defaultValue: -1),
+          123.76);
+      expect(fromString('-4123.76', dataType: DataType.currency, defaultValue: -1),
+          -4123.76);
+      expect(fromString('', dataType: DataType.currency, defaultValue: -99999999),
+          -99999999);
+      expect(fromString('Nothing', dataType: DataType.currency, defaultValue: -99999999),
+          -99999999);
+    });
+    test('date', ()
+    {
+      expect(fromString('7.3.1987', dataType: DataType.date),
+          DateTime(1987, 3, 7));
+      expect(fromString('17.12.2035', dataType: DataType.date),
+          DateTime(2035, 12, 17));
+      expect(fromString('2012.6.2', dataType: DataType.date),
+          DateTime(2012, 6, 2));
+      expect(fromString('1923.10.31', dataType: DataType.date),
+          DateTime(1923, 10, 31));
+      expect(fromString('17.12.21', dataType: DataType.date),
+          isNull);
+    });
+    test('datetime', ()
+    {
+      expect(fromString('17.12.2035', dataType: DataType.datetime),
+          DateTime(2035, 12, 17));
+      expect(fromString('7.3.1987', dataType: DataType.datetime),
+          DateTime(1987, 3, 7));
+      expect(fromString('2012.6.2', dataType: DataType.datetime),
+          DateTime(2012, 6, 2));
+      expect(fromString('1923.10.31', dataType: DataType.datetime),
+          DateTime(1923, 10, 31));
+      expect(fromString('17.12.21', dataType: DataType.datetime),
+          isNull);
+      expect(fromString('7.3.1987T2:44', dataType: DataType.datetime),
+          DateTime(1987, 3, 7, 2, 44));
+      expect(fromString('17.12.2035 13:59:22', dataType: DataType.datetime),
+          DateTime(2035, 12, 17, 13, 59, 22));
+      expect(fromString('2012.6.2/23:59:59', dataType: DataType.datetime),
+          DateTime(2012, 6, 2, 23, 59, 59));
+      expect(fromString('1923.10.31-3:4', dataType: DataType.datetime),
+          DateTime(1923, 10, 31, 3, 4));
+    });
+  });
+  group('asPattern', () {
+    test('unchanged', () {
+      expect(asPattern('A test!123'), 'A test!123%');
+    });
+    test('with *', () {
+      expect(asPattern('*Wu*ff'), '%Wu%ff%');
+    });
+    test('empty', () {
+      expect(asPattern(''), '%');
+    });
+    test('with ?', () {
+      expect(asPattern('M??r'), 'M__r%');
+    });
+    test('mixed', () {
+      expect(asPattern('*M?i*r'), '%M_i%r%');
+    });
+  });
+  group('asString', () {
+    test('bool', () {
+      expect(asString(true), i18n.tr('Yes'));
+      expect(asString(false), i18n.tr('No'));
+      expect(asString(true, dbFormat: true), 'T');
+      expect(asString(false, dbFormat: true), 'F');
+    });
+    test('int', () {
+      expect(asString(12345), '12345');
+      expect(asString(-33), '-33');
+      expect(asString(-33, dbFormat: true), '-33');
+      expect(asString(884433, dbFormat: true), '884433');
+    });
+    test('double', () {
+      expect(asString(7733.0), '7733.00');
+      expect(asString(-123.77), '-123.77');
+      expect(asString(1E-99), '.00');
+      expect(asString(7733.0, dbFormat: true), '7733.00');
+      expect(asString(-123.77, dbFormat: true), '-123.77');
+    });
+    test('Date', () {
+      expect(asString(DateTime(2021, 10, 3), dateOnly: true), '03.10.2021');
+      expect(
+          asString(DateTime(2021, 10, 3, 9, 33), dateOnly: true), '03.10.2021');
+      expect(asString(DateTime(2021, 10, 3, 9, 33), dateOnly: false),
+          '03.10.2021 09:33');
+      expect(asString(DateTime(2021, 10, 3, 9, 33, 14), dateOnly: false),
+          '03.10.2021 09:33');
+      expect(
+          asString(DateTime(2021, 10, 3, 9, 33, 14),
+              dateOnly: false, withSeconds: true),
+          '03.10.2021 09:33:14');
+      expect(asString(DateTime(2021, 7, 3), dbFormat: true, dateOnly: true),
+          '2021-07-03');
+      expect(
+          asString(DateTime(2021, 10, 3, 9, 33),
+              dbFormat: true, dateOnly: true),
+          '2021-10-03');
+      expect(
+          asString(DateTime(2021, 7, 3, 9, 33),
+              dbFormat: true, dateOnly: false),
+          '2021-07-03 09:33:00');
+      expect(
+          asString(DateTime(2021, 10, 3, 9, 33, 14),
+              dbFormat: true, dateOnly: false),
+          '2021-10-03 09:33:14');
+      expect(
+          asString(DateTime(2021, 10, 3, 9, 33, 14),
+              dbFormat: true, dateOnly: false, withSeconds: true),
+          '2021-10-03 09:33:14');
+    });
+    test('string', () {
+      expect(asString('A test!123'), 'A test!123');
+      expect(asString('A test!123', dbFormat: true), 'A test!123');
+    });
+    test('string', () {
+      expect(asString('A test!123'), 'A test!123');
+    });
+    test('string', () {
+      expect(asString('A test!123'), 'A test!123');
+    });
+  });
+}
diff --git a/rest_server/data/sql/benchmarks.sql.yaml b/rest_server/data/sql/benchmarks.sql.yaml
new file mode 100644 (file)
index 0000000..1214dba
--- /dev/null
@@ -0,0 +1,48 @@
+---
+# DO NOT CHANGE. This file is created by the meta_tool
+# SQL statements of the module "Benchmarks":
+
+module: Benchmarks
+list:
+  type: list
+  parameters: [":text"]
+  order: "benchmark_id"
+  sql: |
+    SELECT
+    t0.*    FROM benchmarks t0
+    WHERE
+    (:text='' OR benchmark_lastname like :text
+      OR benchmark_firstname like :text)
+byId:
+  type: record
+  parameters: [ ":id" ]
+  sql: "SELECT * FROM benchmarks WHERE benchmark_id=:id;"
+delete:
+  type: delete
+  parameters: [ ":id" ]
+  sql: "DELETE * FROM benchmarks WHERE benchmark_id=:id;"
+update:
+  type: update
+  parameters: [":id",":lastName",":firstName",":email",":birthday",":active",
+    ":weight",":income"]
+  sql: |
+    UPDATE benchmarks SET
+      benchmark_lastname=:lastName,
+      benchmark_firstname=:firstName,
+      benchmark_email=:email,
+      benchmark_birthday=:birthday,
+      benchmark_active=:active,
+      benchmark_weight=:weight,
+      benchmark_income=:income,
+      benchmark_changed=NOW()
+    WHERE benchmark_id=:id;
+insert:
+  type: insert
+  parameters: [":lastName",":firstName",":email",":birthday",":active",":weight",
+    ":income",":createdBy"]
+  sql: |
+    INSERT INTO benchmarks(benchmark_lastname,benchmark_firstname,
+      benchmark_email,benchmark_birthday,benchmark_active,benchmark_weight,
+      benchmark_income,benchmark_createdby,benchmark_created)
+    VALUES(:lastName,:firstName,:email,:birthday,:active,:weight,:income,
+      :createdBy,NOW());
index 1eded90f69a8c5fd0840754bdfb7b48b676a1dd2..901ab649172f2b082469bbde9fba655a625c01bf 100644 (file)
@@ -7,10 +7,9 @@ list:
   type: list
   parameters: []
   order: "role_id"
-  sql: "SELECT
-    t0.*
-    FROM roles t0
-    ;"
+  sql: |
+    SELECT
+    t0.*    FROM roles t0
 byId:
   type: record
   parameters: [ ":id" ]
@@ -22,11 +21,14 @@ delete:
 update:
   type: update
   parameters: [":id",":name"]
-  sql: "UPDATE roles SET
-    role_name=:name,role_changed=NOW()
-    WHERE role_id=:id;"
+  sql: |
+    UPDATE roles SET
+      role_name=:name,
+      role_changed=NOW()
+    WHERE role_id=:id;
 insert:
   type: insert
   parameters: [":name",":createdBy"]
-  sql: "INSERT INTO roles(role_name,role_createdby,role_created)
-    VALUES(:name,:createdBy,NOW());"
+  sql: |
+    INSERT INTO roles(role_name,role_createdby,role_created)
+    VALUES(:name,:createdBy,NOW());
index 9595e1d8a4fb05d59e751255f4879cfd6f95c251..eb68f178aee44d54485ebdfe4b7e98b87570a196 100644 (file)
@@ -7,10 +7,9 @@ list:
   type: list
   parameters: []
   order: "structure_id"
-  sql: "SELECT
-    t0.*
-    FROM structures t0
-    ;"
+  sql: |
+    SELECT
+    t0.*    FROM structures t0
 byId:
   type: record
   parameters: [ ":id" ]
@@ -22,13 +21,18 @@ delete:
 update:
   type: update
   parameters: [":id",":scope",":name",":value",":position"]
-  sql: "UPDATE structures SET
-    structure_scope=:scope,structure_name=:name,structure_value=:value,
-    structure_position=:position,structure_changed=NOW()
-    WHERE structure_id=:id;"
+  sql: |
+    UPDATE structures SET
+      structure_scope=:scope,
+      structure_name=:name,
+      structure_value=:value,
+      structure_position=:position,
+      structure_changed=NOW()
+    WHERE structure_id=:id;
 insert:
   type: insert
   parameters: [":scope",":name",":value",":position",":createdBy"]
-  sql: "INSERT INTO structures(structure_scope,structure_name,structure_value,
+  sql: |
+    INSERT INTO structures(structure_scope,structure_name,structure_value,
       structure_position,structure_createdby,structure_created)
-    VALUES(:scope,:name,:value,:position,:createdBy,NOW());"
+    VALUES(:scope,:name,:value,:position,:createdBy,NOW());
index 5102dfe611233d621185abbfed9de0f81436cf33..00a4637ee4780a60dd194a529d595403bb158590 100644 (file)
@@ -7,15 +7,14 @@ list:
   type: list
   parameters: [":text",":role"]
   order: "user_id"
-  sql: "SELECT
-    t0.*,t1.role_name AS role
-    FROM users t0
+  sql: |
+    SELECT
+    t0.*,t1.role_name AS role    FROM users t0
     JOIN roles t1 ON t1.role_id=t0.user_role
     WHERE
     (:text='' OR user_name like :text
       OR user_displayname like :text OR user_email like :text)
       AND (:role=0 OR :role=user_role)
-    ;"
 byId:
   type: record
   parameters: [ ":id" ]
@@ -27,13 +26,18 @@ delete:
 update:
   type: update
   parameters: [":id",":name",":displayName",":email",":role"]
-  sql: "UPDATE users SET
-    user_name=:name,user_displayname=:displayName,user_email=:email,
-    user_role=:role,user_changed=NOW()
-    WHERE user_id=:id;"
+  sql: |
+    UPDATE users SET
+      user_name=:name,
+      user_displayname=:displayName,
+      user_email=:email,
+      user_role=:role,
+      user_changed=NOW()
+    WHERE user_id=:id;
 insert:
   type: insert
   parameters: [":name",":displayName",":email",":role",":createdBy"]
-  sql: "INSERT INTO users(user_name,user_displayname,user_email,user_role,
+  sql: |
+    INSERT INTO users(user_name,user_displayname,user_email,user_role,
       user_createdby,user_created)
-    VALUES(:name,:displayName,:email,:role,:createdBy,NOW());"
+    VALUES(:name,:displayName,:email,:role,:createdBy,NOW());
diff --git a/test/helper_test.dart b/test/helper_test.dart
new file mode 100644 (file)
index 0000000..7d41733
--- /dev/null
@@ -0,0 +1,3 @@
+/// The flutter test environment is not usable for helper.dart
+/// See metadata/test/helper.dart for tests (with dart test environment)
+
index 0786b560352c77818a7fece8a62c857a95d4d36b..4ff2bfa375530c94bcdfe4bad532a645c9b7ade2 100755 (executable)
@@ -141,7 +141,7 @@ function Flutter(){
   flutter config linux
 }
 function Finish(){
-  pub upgrade
+  dart pub upgrade
 }
 if [ -z "$APP" ]; then
   Usage "missing PROJECT"