]> gitweb.hamatoma.de Git - exhibition.git/commitdiff
Refactoring, new module rolestarter
authorHamatoma <author.hamatoma.de>
Sat, 23 Oct 2021 20:47:07 +0000 (22:47 +0200)
committerHamatoma <author.hamatoma.de>
Sat, 23 Oct 2021 20:47:07 +0000 (22:47 +0200)
* Refactoring:
** usage of the dart feature "late": dummy constructors removed

* new module rolestarter:
** new: PageType.mapping
** new: MappingPageMetaData
** new: ReferenceProperty

lib/meta/module_meta_data.dart
lib/meta/modules.dart
lib/meta/rolestarter_meta.dart [new file with mode: 0644]
lib/page/page_manager.dart
lib/setting/global_data.dart
metatool/bin/page_generator.dart

index 659d4888c470d050780eb5f1bea8053a6219f9a4..2634f5298373c050c2b8753cf26c5237378e0c6f 100644 (file)
@@ -34,10 +34,6 @@ enum DisplayType {
   text,
 }
 
-class DummyModule extends ModuleMetaData {
-  DummyModule() : super('', [], []);
-}
-
 /// Describes a field of the page.
 class FieldMetaData extends WidgetMetaData {
   DataType dataType;
@@ -48,6 +44,8 @@ class FieldMetaData extends WidgetMetaData {
       : super(name, WidgetType.field);
 }
 
+/// Describes the list page, that displays an overview over all records of the
+/// related table.
 class ListPageMetaData extends PageMetaData {
   final String tableHeaders;
   final String tableColumns;
@@ -105,6 +103,38 @@ class ListPageMetaData extends PageMetaData {
             name: name, fields: fields, globalComboBoxes: globalComboBoxes);
 }
 
+/// Describes a mapping page, that allows assignments of many table entries
+/// of the member table to one entry of a common table.
+///
+/// Example: Common table is roles, member table is starters. Than the page
+/// allows to assign some starters (menu items) to a role.
+class MappingPageMetaData extends PageMetaData {
+  ModuleMetaData? commonModule;
+  ModuleMetaData? memberModule;
+  PropertyMetaData? commonProperty;
+  PropertyMetaData? memberProperty;
+
+  /// Constructor.
+  ///
+  /// [name] is the page name. It must be unique over all pages in the module.
+  /// Default is a name derived from the page type.
+  ///
+  /// [commonModuleName]: the name of the module containing the common entries
+  /// of the relation.
+  ///
+  /// [memberModuleName]: the name of the module containing the member entries
+  ///  that belongs to exactly one entry in the common module.
+  ///
+  /// [commonPropertyName]: the name of the property representing the common module.
+  ///
+  /// [memberPropertyName]: the name of the property representing the member module.
+  ///
+  /// Don't forget to initialize the [commonModule], [memberModule],
+  /// [commonProperty] and [memberProperty] in the overridden method [onInitialized].
+  MappingPageMetaData(String label, {String name = ''})
+      : super(label, PageType.mapping, name: name, fields: []);
+}
+
 class MetaException extends FormatException {}
 
 /// Stores the meta data of a module.
@@ -290,13 +320,6 @@ class ModuleMetaData {
     return rc;
   }
 
-  /// Returns the meta data of a property given by its [name] or null if missing.
-  PropertyMetaData? propertyByName(String name) {
-    final rc = propertyList.singleWhere((element) => element.name == name,
-        orElse: null);
-    return rc;
-  }
-
   /// Returns a property given by the [columnName].
   PropertyMetaData? propertyByColumnName(String columnName) {
     PropertyMetaData? rc;
@@ -309,6 +332,13 @@ class ModuleMetaData {
     return rc;
   }
 
+  /// Returns the meta data of a property given by its [name] or null if missing.
+  PropertyMetaData? propertyByName(String name) {
+    final rc = propertyList.singleWhere((element) => element.name == name,
+        orElse: null);
+    return rc;
+  }
+
   /// Returns the properties that are not in [metaColumns].
   /// : if the name of the property is [included] the property is always part of
   /// the result.
@@ -323,7 +353,7 @@ class PageMetaData {
   String name = '';
   final String label;
   final PageType pageType;
-  ModuleMetaData module = DummyModule();
+  late ModuleMetaData module;
   final List<WidgetMetaData> fields;
   final String globalComboBoxes;
   PageMetaData(this.label, this.pageType,
@@ -369,11 +399,11 @@ class PageMetaData {
   }
 }
 
-enum PageType { create, custom, delete, edit, list }
+enum PageType { create, custom, delete, edit, list, mapping }
 
 /// Stores the meta data of a module property stored as column in a database.
 class PropertyMetaData extends WidgetMetaData {
-  ModuleMetaData module = DummyModule();
+  late ModuleMetaData module;
   final String label;
 
   /// Relative width of the field in a 12 column form: 1 <= width <= 12
@@ -414,6 +444,14 @@ class PropertyMetaData extends WidgetMetaData {
   }
 }
 
+class ReferenceProperty extends WidgetMetaData {
+  /// This attribute gets is real value after the construcctor of the module.
+  PropertyMetaData child = PropertyMetaData('dummy', '', DataType.bool, '');
+  final String nameChild;
+  ReferenceProperty({required this.nameChild})
+      : super(nameChild + 'Ref', WidgetType.referenceProperty);
+}
+
 /// Describes a widget used in the page.
 /// Base class of all other widgets.
 class WidgetMetaData {
@@ -422,4 +460,4 @@ class WidgetMetaData {
   WidgetMetaData(this.name, this.widgetType);
 }
 
-enum WidgetType { button, field, dbField, property }
+enum WidgetType { button, field, dbField, property, referenceProperty }
index 13cd8da81f1851f9499b4653d73197e070b8036c..9334a33b663bfbaab3c711df5060928293fa1b11 100644 (file)
@@ -2,6 +2,7 @@
 import 'module_meta_data.dart';
 import 'benchmarks_meta.dart';
 import 'roles_meta.dart';
+import 'rolestarter_meta.dart';
 import 'starters_meta.dart';
 import 'structures_meta.dart';
 import 'users_meta.dart';
@@ -17,6 +18,9 @@ ModuleMetaData? moduleByName(String name) {
     case 'Roles':
       rc = RolesMeta();
       break;
+    case 'Rolestarter':
+      rc = RoleStarterMeta();
+      break;
     case 'Starters':
       rc = StartersMeta();
       break;
@@ -37,6 +41,7 @@ List<String> moduleNames() {
   return [
     'Benchmarks',
     'Roles',
+    'Rolestarter',
     'Starters',
     'Structures',
     'Users',
diff --git a/lib/meta/rolestarter_meta.dart b/lib/meta/rolestarter_meta.dart
new file mode 100644 (file)
index 0000000..35c7144
--- /dev/null
@@ -0,0 +1,51 @@
+import '../base/defines.dart';
+import '../base/i18n.dart';
+import 'module_meta_data.dart';
+import 'roles_meta.dart';
+import 'starters_meta.dart';
+
+final i18n = I18N();
+final M = i18n.module("RoleStarter");
+
+class RoleStarterMeta extends ModuleMetaData {
+  static RoleStarterMeta instance = RoleStarterMeta.internal();
+  factory RoleStarterMeta() {
+    return instance;
+  }
+  RoleStarterMeta.internal()
+      : super('RoleStarter', [
+          PropertyMetaData('id', i18n.tr('Id'), DataType.reference, ':primary:',
+              displayType: DisplayType.combobox),
+          PropertyMetaData(
+              'role', i18n.tr('Role'), DataType.reference, ':notnull:',
+              displayType: DisplayType.combobox,
+              foreignKey: 'roles.role_id;role_name;role'),
+          PropertyMetaData(
+              'starter', i18n.tr('Starter'), DataType.reference, ':notnull:',
+              displayType: DisplayType.combobox,
+              foreignKey: 'starters.starter_id;starter_name;starter'),
+          PropertyMetaData('createdAt', i18n.tr('Created at'),
+              DataType.datetime, ':hidden:'),
+          PropertyMetaData(
+              'createdBy', i18n.tr('Created by'), DataType.string, ':hidden:',
+              size: 32),
+          PropertyMetaData('changedAt', i18n.tr('Changed at'),
+              DataType.datetime, ':hidden:'),
+          PropertyMetaData(
+              'changedBy', i18n.tr('Changed by'), DataType.string, ':hidden:',
+              size: 32),
+        ], [
+          MappingPageMetaData(
+            i18n.tr('Role-Starter Assignment'),
+          ),
+        ]);
+  @override
+  void onInitialized() {
+    super.onInitialized();
+    final page = pageByName('mapping') as MappingPageMetaData;
+    page.commonModule = RolesMeta();
+    page.memberModule = StartersMeta();
+    page.commonProperty = propertyByName('role');
+    page.memberProperty = propertyByName('starter');
+  }
+}
index 7eb726613b43fdf7ccc032ecb0701dbd84e04ee6..581a5e4818a260b9e1943f98bdfd9901895cc596 100644 (file)
@@ -9,6 +9,7 @@ import 'benchmarks/list_benchmark_page.dart';
 import 'roles/create_role_page.dart';
 import 'roles/edit_role_page.dart';
 import 'roles/list_role_page.dart';
+import 'rolestarter/mapping_rolestarter_page.dart';
 import 'starters/create_starter_page.dart';
 import 'starters/edit_starter_page.dart';
 import 'starters/delete_starter_page.dart';
@@ -59,6 +60,9 @@ class PageManager {
       case '/Roles/list':
         rc = ListRolePage();
         break;
+      case '/RoleStarter/mapping':
+        rc = MappingRoleStarterPage();
+        break;
       case '/Starters/create':
         rc = CreateStarterPage();
         break;
index 618cfef5dd5c8660cd7aad3d4ad9b20c30ea647b..9c1215cb00fad413fd95bbc729653c3f943844be 100644 (file)
@@ -17,16 +17,6 @@ typedef DrawerBuilder = Function(dynamic);
 
 typedef FooterBuilder = FooterInterface? Function();
 
-class DummyFooter implements FooterInterface {
-  @override
-  Widget widget(PageControllerExhibition controller) {
-    return const Text('');
-  }
-
-  /// Returns a method creating a footer.
-  static DummyFooter? builder() => DummyFooter();
-}
-
 abstract class FooterInterface {
   Widget widget(PageControllerExhibition controller);
 }
@@ -47,15 +37,11 @@ class GlobalData {
   final FooterBuilder footerBuilder;
   final BaseConfiguration configuration;
   final RestPersistence? restPersistence;
-  HomeDirectories homeDirectories = HomeDirectories.dummy();
+  late HomeDirectories homeDirectories;
 
   final navigatorStack = NavigatorStack();
   factory GlobalData() => _instance ?? GlobalData();
 
-  GlobalData.dummy()
-      : this.internal(BaseConfiguration({}, globalLogger), (input) => '',
-            (input) => '', DummyFooter.builder, null, globalLogger);
-
   /// [configuration]: general settings.
   /// [appBarBuilder]: a factory to create the Hamburger menu.
   /// [footerBuilder]: a factory to create a footer area.
@@ -115,7 +101,6 @@ class HomeDirectories {
       throw FormatException('HomeDirectory.getHomePath(): unknown platform');
     }
   }
-  HomeDirectories.dummy();
 }
 
 /// Manages the call stack of the navigator.
index 80e4a377be50c295fc3fdbbc181d6e96545ad9b4..37af3dc0a5256779ea22cf4c025b3461c7465e33 100644 (file)
@@ -247,6 +247,160 @@ class ListUserCustom extends State<ListUserPage> {
   }
 }
 
+class _FieldData {
+  int thePageSize = 10;
+  int theOffset = 0;
+#DEF_FIELDS}
+''';
+
+  static final templateMappingCustom =
+      '''// 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 '../../services/global_widget.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/widget_form.dart';
+import '../../persistence/persistence.dart';
+import 'list_user_page.dart';
+
+final i18n = I18N();
+
+class MappingUserCustom extends State<MappingUserPage> {
+  final globalData = GlobalData();
+  late Future<DbData> _futureDbData;
+  AttendedPage? attendedPage;
+  final _fieldData = _FieldData();
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'CreateUser');
+#DEF_CONTROLLERS  MappingUserCustom();
+  @override
+  Widget build(BuildContext context) {
+    final rc = Scaffold(
+      appBar: globalData.appBarBuilder(i18n.tr('Overview users')),
+      drawer: globalData.drawerBuilder(context),
+      floatingActionButton: FloatingActionButton(
+        onPressed: () {
+          globalData.navigate(context, '/Users/create');
+        },
+        child: const Icon(Icons.add),
+        tooltip: #TIP_ADD
+      ),
+      body: SafeArea(
+          child: FutureBuilder<DbData>(
+        future: _futureDbData,
+        builder: (context, snapshot) {
+          Widget rc;
+          if (snapshot.connectionState != ConnectionState.done) {
+            rc = const CircularProgressIndicator();
+          } else {
+            if (snapshot.hasData) {
+              final rows = attendedPage!.getRows(dbData: snapshot.data!,
+                  columnList: '#ROW_COLUMNS',
+                  onDone: () => setState(() => 1),
+                  route#EDIT1: '/Users/#EDIT2',
+                  context: context);
+              rc = buildFrame(totalCount: snapshot.data?.count ?? rows.length,
+                rows: rows);
+            } else if (snapshot.hasError) {
+              rc = Text('Backend problem: \${snapshot.error}');
+            } else {
+              rc = const CircularProgressIndicator();
+            }
+          }
+          return rc;
+        },
+      )),
+    );
+    return rc;
+  }
+
+  Widget buildFrame({required JsonList rows, required int totalCount}){
+    final padding = GlobalThemeData.padding;
+#INIT_COMBOS    final formItems = <FormItem>[
+#FORM_ITEMS      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 table = DataTable(
+      columns: <DataColumn>[
+#TABLE_HEADER      ],
+      rows: rows as List<DataRow>,
+    );
+    Widget? tabBar = attendedPage!.buildChipBar(
+        totalCount: totalCount,
+        offset: _fieldData.theOffset,
+        pageSize: _fieldData.thePageSize,
+        onTap: (offset) {
+          _fieldData.theOffset = offset;
+          requestRecords();
+          setState(() => 1);
+        });
+    final frameWidget = ListView(children: [
+      form,
+      if (tabBar != null) tabBar,
+      SizedBox(height: padding),
+      SizedBox(width: double.infinity, child: table),
+    ]);
+    return frameWidget;
+  }
+
+  @override
+  void didChangeDependencies() {
+    super.didChangeDependencies();
+    requestRecords();
+  }
+
+  @override
+  void dispose() {
+    helperDummyUsage(DataType.string);
+    globalWidgetDummyUsage();
+    super.dispose();
+  }
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  void requestRecords() =>  _futureDbData = globalData.restPersistence!.query(
+    what: 'query', data: {
+      'module': 'Users',
+      'sql': 'list',
+      'offset': _fieldData.theOffset,
+      'size': _fieldData.thePageSize,
+#PARAM_DEF    });
+
+  void search() {
+    attendedPage!.pageStates.dbDataState.clear();
+    if (_formKey.currentState!.validate()) {
+      _formKey.currentState!.save();
+      requestRecords();
+      setState(() => 1);
+    }
+  }
+}
+
 class _FieldData {
   int thePageSize = 10;
   int theOffset = 0;
@@ -803,6 +957,9 @@ StatefulWidget? customPageByRoute(String route) {
       case PageType.custom:
         rc = createRecordCustomized(page);
         break;
+      case PageType.mapping:
+        rc = createMappingCustomized(page as MappingPageMetaData);
+        break;
     }
     return rc;
   }
@@ -826,6 +983,16 @@ StatefulWidget? customPageByRoute(String route) {
     return rc;
   }
 
+  /// Creates the customozed part of the [page] that is PageType.mapping.
+  String createMappingCustomized(MappingPageMetaData page) {
+    var rc = replaceVariables(templateMappingCustom, page)
+        .replaceFirst('#DEF_CONTROLLERS', buildDefinitionControllers(page))
+        .replaceFirst('#INIT_COMBOS', buildInitializeComboBoxes(page))
+        .replaceFirst('#FORM_ITEMS', buildFormItems(page, withController: true))
+        .replaceFirst('#PARAM_DEF', buildParamDefinitions(page));
+    return rc;
+  }
+
   /// Returns a Dart class definition of the [page] that should not be modified.
   String createPage(PageMetaData page) {
     var rc = replaceVariables(templatePage, page);
@@ -896,8 +1063,8 @@ StatefulWidget? customPageByRoute(String route) {
         hasPrimary = true;
         break;
       case PageType.custom:
-        break;
       case PageType.list:
+      case PageType.mapping:
         break;
     }
     var rc = replaceVariables(templateRecordCustom, page)