]> gitweb.hamatoma.de Git - flutter_bones.git/commitdiff
daily work
authorHamatoma <author@hamatoma.de>
Mon, 26 Oct 2020 21:50:56 +0000 (22:50 +0100)
committerHamatoma <author@hamatoma.de>
Mon, 26 Oct 2020 21:50:56 +0000 (22:50 +0100)
31 files changed:
lib/app.dart
lib/src/model/db_reference_model.dart
lib/src/model/page_model.dart
lib/src/model/standard/configuration_model.dart
lib/src/model/standard/role_model.dart
lib/src/model/standard/user_model.dart
lib/src/model/table_model.dart
lib/src/page/application_data.dart
lib/src/page/configuration/configuration_change_page.dart
lib/src/page/configuration/configuration_controller.dart
lib/src/page/configuration/configuration_create_page.dart
lib/src/page/configuration/configuration_list_page.dart
lib/src/page/role/role_change_page.dart
lib/src/page/role/role_controller.dart
lib/src/page/role/role_create_page.dart
lib/src/page/role/role_list_page.dart
lib/src/page/user/user_change_page.dart
lib/src/page/user/user_controller.dart
lib/src/page/user/user_create_page.dart
lib/src/page/user/user_list_page.dart
lib/src/private/bdrawer.dart
lib/src/widget/callback_controller_bones.dart
lib/src/widget/checkbox_form_field.dart
lib/src/widget/edit_form.dart
lib/src/widget/list_form.dart
lib/src/widget/page_controller_bones.dart
lib/src/widget/view.dart
lib/src/widget/widget_list.dart
test/model/db_model_test.dart
test/model/model_test.dart
test/widget/widget_test.dart

index 0f6d5e88489ae4addc54ff476e7f5267a7224e7e..cb4cf07e31279b9dfd8a4462dc1dc7f85f968151 100644 (file)
@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
 
 import 'src/helper/settings.dart';
 import 'src/page/login_page.dart';
-import 'src/page/role/role_change_page.dart';
 import 'src/page/role/role_create_page.dart';
 import 'src/page/role/role_list_page.dart';
 import 'src/private/bsettings.dart';
index f93fabacd5b451acf321d6edd70495faa6829cea..785e0db867592458be5ea2ffb675bc418621e7ab 100644 (file)
@@ -37,6 +37,9 @@ class DbReferenceModel extends FieldModel {
     this.column = column;
     maxSize = column.size;
     rows = column.rows;
+    if (column.hasOption('primary') && ! column.hasOption('readonly')){
+      options.add('readonly');
+    }
   }
 
   /// Dumps the internal structure into a [stringBuffer]
index 858c0b4abbefdbbbcc1afda0c5a0cddf059472ee..6df201e4ed5e7f7e4b78ed50fcbbbff1c5c9d144 100644 (file)
@@ -20,6 +20,8 @@ class PageModel extends ModelBase {
   final fields = <FieldModel>[];
   final buttons = <ButtonModel>[];
   final widgets = <WidgetModel>[];
+  List<String> tableTitles;
+  List<String> tableColumns;
 
   PageModel(this.module, this.map, BaseLogger logger) : super(logger);
 
@@ -58,7 +60,7 @@ class PageModel extends ModelBase {
     final name = field.name;
     if (hasField(name)) {
       logger.error('field ${field.fullName()} already defined: ' +
-          getField(name).fullName());
+          fieldByName(name).fullName());
     } else {
       fields.add(field);
     }
@@ -79,7 +81,7 @@ class PageModel extends ModelBase {
   String fullName() => '${module.name}.$name';
 
   /// Returns a field by [name] or null on error.
-  FieldModel getField(String name, {bool required = true}) {
+  FieldModel fieldByName(String name, {bool required = true}) {
     final rc = fields.firstWhere((element) => element.name == name,
         orElse: () => null);
     if (required && rc == null) {
@@ -106,7 +108,7 @@ class PageModel extends ModelBase {
   void parse() {
     name = parseString('page', map, required: true);
     checkSuperfluousAttributes(
-        map, 'options page pageType sections'.split(' '));
+        map, 'options page pageType sections tableColumns tableTitles'.split(' '));
     pageModelType = parseEnum<PageModelType>(
         'pageType', map, PageModelType.values,
         required: true);
@@ -122,6 +124,20 @@ class PageModel extends ModelBase {
         SectionModel.parseSections(this, null, item, logger);
       }
     }
+    tableTitles = parseStringList('tableTitles', map);
+    tableColumns = parseString('tableColumns', map)?.split(' ');
+    if (pageModelType != PageModelType.list &&
+        (tableTitles != null || tableColumns != null)) {
+      logger.error(
+          'tableTitles and tableColumns are only meaningful in list pages: ${fullName()}');
+    }
+    if (tableTitles != null &&
+        tableColumns != null &&
+        tableTitles.length != tableColumns.length) {
+      logger.error(
+          'different sizes of tableTitles/tableColumns: ${tableTitles.length}/${tableColumns.length}');
+    }
+
     if (!options.contains('noAutoButton') &&
         buttonByName('search', required: false) == null) {
       final section = null;
index a9534db32f5c1641fde4f4d4b3afdf3260c1a1b2..2351d9d55a27fc35d3633c97ff61f02f7b2717e2 100644 (file)
@@ -89,6 +89,8 @@ class ConfigurationModel extends ModuleModel {
       {
         "page": "list",
         "pageType": "list",
+        "tableColumns": "configuration_id configuration_scope configuration_property configuration_order configuration_value configuration_type",
+        "tableTitles": ";Id;Bereich;Eigenschaft;Reihe;Wert;Typ",
         "sections": [
           {
             "sectionType": "filterPanel",
index 32af803997dc2cd9ff31bc1edd660b8013d35b7f..3a1f642d74a2c10c9bcaf18ea5812033bb7893ef 100644 (file)
@@ -67,6 +67,8 @@ class RoleModel extends ModuleModel {
       {
         "page": "list",
         "pageType": "list",
+        "tableColumns": "role_id role_name role_prio",
+        "tableTitles": ";Id;Rolle;Priorität",
         "sections": [
           {
             "sectionType": "filterPanel",
index a8b0c54af7ebc8b26ec45361675360da53ad2969..3aa5c50b75f43ab683477b4d4258fca27fcec6c2 100644 (file)
@@ -84,6 +84,8 @@ class UserModel extends ModuleModel {
       {
         "page": "list",
         "pageType": "list",
+        "tableColumns": "user_id user_name user_displayname user_email user_role",
+        "tableTitles": ";Id;Name;Anzeigename;EMail;Rolle",
         "sections": [
           {
             "sectionType": "filterPanel",
index e1753d6c80e19e6532a48a043368e7ccc10bd1ee..1ca200275e998d2d9e9d7a7f61ea74ad999ed6f7 100644 (file)
@@ -1,5 +1,4 @@
 import 'package:dart_bones/dart_bones.dart';
-import 'package:meta/meta.dart';
 
 import 'column_model.dart';
 import 'model_base.dart';
@@ -13,7 +12,6 @@ class TableModel extends ModelBase {
   final Map<String, dynamic> map;
   String name;
   List<String> options;
-  @protected
   final columns = <ColumnModel>[];
   ColumnModel primary;
 
index 99b1dc1078d75ba95f04ff6aeb10ee219816ddcc..75b6e583b8590b50b84f8426dc1e5ad906a8fb69 100644 (file)
@@ -1,6 +1,8 @@
 import 'package:dart_bones/dart_bones.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
+import 'package:flutter_bones/src/widget/page_controller_bones.dart';
 
 /// Data class for storing parameter to build a page.
 class ApplicationData {
@@ -13,6 +15,10 @@ class ApplicationData {
   final Persistence persistence;
   String currentUser;
   int currentRoleId;
+  /// for unittests:
+  dynamic lastModuleState;
+  @protected
+  final callerStack = <PageControllerBones>[];
 
   /// Constructor.
   /// [configuration] is a map with the widget data (e.g. padding)
@@ -23,4 +29,20 @@ class ApplicationData {
     currentUser = 'Gast';
     currentRoleId = 100;
   }
+  /// Enforces a redraw of the caller of the current page.
+  /// [reason] specifies why the redraw is needed and [customString]
+  /// is an additional info for the reason.
+  void callerRedraw(RedrawReason reason, [String customString]){
+    if (callerStack.isNotEmpty && callerStack.last != null){
+      callerStack.last.redraw(reason, customString);
+    }
+  }
+  void pushCaller(PageControllerBones controller){
+    callerStack.add(controller);
+  }
+  void popCaller(){
+    if (callerStack.isNotEmpty){
+      callerStack.removeLast();
+    }
+  }
 }
index 55c0e60a7bf88406fb5c55ad8e8e0f93e205c4c3..e8c02899fc63064671e664c7885e053961457cb4 100644 (file)
@@ -1,40 +1,52 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
 
 import '../../widget/edit_form.dart';
 import 'configuration_controller.dart';
 
 class ConfigurationChangePage extends StatefulWidget {
   final ApplicationData applicationData;
+  final Map initialRow;
   final logger = Settings().logger;
-
+  final int primaryId;
   //ConfigurationChangePageState lastState;
 
-  ConfigurationChangePage(this.applicationData, {Key key}) : super(key: key);
+  ConfigurationChangePage(this.primaryId, this.applicationData, this.initialRow,
+      {Key key})
+      : super(key: key);
 
   @override
   ConfigurationChangePageState createState() {
-    final rc = ConfigurationChangePageState(applicationData);
-    // lastState = rc;
+    final rc = ConfigurationChangePageState(primaryId, applicationData, initialRow);
+
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
 
 class ConfigurationChangePageState extends State<ConfigurationChangePage> {
   final ApplicationData applicationData;
-
+  final int primaryId;
+  final Map initialRow;
   final GlobalKey<FormState> _formKey =
       GlobalKey<FormState>(debugLabel: 'configuration_change');
 
   ConfigurationController controller;
 
-  ConfigurationChangePageState(this.applicationData);
+  ConfigurationChangePageState(this.primaryId, this.applicationData, this.initialRow);
 
   @override
   Widget build(BuildContext context) {
-    controller = controller ??
-        ConfigurationController(
-            _formKey, this, 'change', context, applicationData);
+    if (controller == null) {
+      controller = ConfigurationController(
+          _formKey, this, 'change', context, applicationData,
+          redrawCallback: (RedrawReason reason, String customString) =>
+              setState(() => null));
+      controller.initialize();
+    }
+    // controller.buildWidgetList() is called in editForm
     return Scaffold(
         appBar: applicationData.appBarBuilder('Rolle ändern'),
         drawer: applicationData.drawerBuilder(context),
@@ -42,6 +54,12 @@ class ConfigurationChangePageState extends State<ConfigurationChangePage> {
           key: _formKey,
           pageController: controller,
           configuration: applicationData.configuration,
+          primaryId: primaryId,
+          initialRow: initialRow,
         ));
   }
+  void dispose() {
+    controller.dispose();
+    super.dispose();
+  }
 }
index 27af1e1f5d5cffea4186d8289fb7dafa860e8fca..7b9eb09c5a971e02140acb20f82da99578490e09 100644 (file)
@@ -2,25 +2,22 @@ import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
 
 import '../../model/standard/configuration_model.dart';
+import 'configuration_change_page.dart';
 import '../../widget/page_controller_bones.dart';
 
 class ConfigurationController extends PageControllerBones {
   /// Controller for a page named [pageName].
-  ConfigurationController(
-      GlobalKey<FormState> formKey,
-      State<StatefulWidget> parent,
-      String pageName,
-      BuildContext context,
-      ApplicationData applicationData,
-      {Function fetchRows})
-      : super(
-          formKey,
-          parent,
-          ConfigurationModel(Settings().logger),
-          pageName,
-          context,
-          applicationData,
-        ) {
+  ConfigurationController(GlobalKey<FormState> formKey, State<StatefulWidget> parent,
+      String pageName, BuildContext context, ApplicationData applicationData,
+      {Function redrawCallback})
+      : super(formKey, parent, ConfigurationModel(Settings().logger), pageName, context,
+            applicationData, redrawCallback) {
     moduleModel.parse();
   }
+  @override
+  void startChange(int id, Map row) {
+    applicationData.pushCaller(this);
+    Navigator.push(context,
+        MaterialPageRoute(builder: (context) => ConfigurationChangePage(id, applicationData, row)));
+  }
 }
index 6e6b0d341e4e9114b52b33a4862208437bb5f03a..331a57b3d9596c966e6bc680671b38ad6fb97a92 100644 (file)
@@ -5,14 +5,17 @@ import '../../widget/edit_form.dart';
 import 'configuration_controller.dart';
 
 class ConfigurationCreatePage extends StatefulWidget {
-  final ApplicationData pageData;
+  final ApplicationData applicationData;
   final logger = Settings().logger;
 
-  ConfigurationCreatePage(this.pageData, {Key key}) : super(key: key);
+  ConfigurationCreatePage(this.applicationData, {Key key}) : super(key: key);
 
   @override
   ConfigurationCreatePageState createState() {
-    final rc = ConfigurationCreatePageState(pageData);
+    final rc = ConfigurationCreatePageState(applicationData);
+
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
@@ -29,9 +32,12 @@ class ConfigurationCreatePageState extends State<ConfigurationCreatePage> {
 
   @override
   Widget build(BuildContext context) {
-    controller = controller ??
-        ConfigurationController(
-            _formKey, this, 'create', context, applicationData);
+    if (controller == null) {
+      controller =
+          ConfigurationController(_formKey, this, 'create', context, applicationData);
+      controller.initialize();
+    }
+    controller.buildWidgetList();
     return Scaffold(
         appBar: applicationData.appBarBuilder('Neue Rolle'),
         drawer: applicationData.drawerBuilder(context),
index 57d9ac6c4840c5198c0d6c420ebb65291b0fba32..e42bab4876d9e0c26a7f94297d9f472ff8553d87 100644 (file)
@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
 
 import '../../widget/filter_set.dart';
 import '../../widget/list_form.dart';
@@ -6,15 +7,16 @@ import '../application_data.dart';
 import 'configuration_controller.dart';
 
 class ConfigurationListPage extends StatefulWidget {
-  final ApplicationData pageData;
+  final ApplicationData applicationData;
 
-  ConfigurationListPage(this.pageData, {Key key}) : super(key: key);
+  ConfigurationListPage(this.applicationData, {Key key}) : super(key: key);
 
   @override
   ConfigurationListPageState createState() {
     // ConfigurationListPageState.setPageData(pageData);
-    final rc = ConfigurationListPageState(pageData);
-
+    final rc = ConfigurationListPageState(applicationData);
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
@@ -24,7 +26,7 @@ class ConfigurationListPageState extends State<ConfigurationListPage> {
 
   final GlobalKey<FormState> _formKey =
       GlobalKey<FormState>(debugLabel: 'configuration_list');
-  Iterable<dynamic> rows;
+  Iterable<dynamic> rowsDeprecated;
   ConfigurationController controller;
   FilterSet filters;
 
@@ -32,38 +34,36 @@ class ConfigurationListPageState extends State<ConfigurationListPage> {
 
   @override
   Widget build(BuildContext context) {
-    controller ??= ConfigurationController(
-        _formKey, this, 'list', context, applicationData);
+    if (controller == null) {
+      controller = ConfigurationController(
+          _formKey, this, 'list', context, applicationData,
+          redrawCallback: (RedrawReason reason, String customString) => setState(() => null));
+      controller.initialize();
+      controller.buildWidgetList();
+    }
     filters ??= controller.filterSet(pageName: 'list');
-    getRows();
+    controller.buildRows();
     return Scaffold(
       appBar: applicationData.appBarBuilder('Rollen'),
       drawer: applicationData.drawerBuilder(context),
       body: ListForm.listForm(
         key: _formKey,
         configuration: applicationData.configuration,
-        titles: ListForm.stringsToTitles(';Id;Name;Priorität'),
-        columnNames:
-            'configuration_id configuration_name configuration_priority'
-                .split(' '),
-        rows: rows ?? [],
+        titles: ListForm.stringsToTitles(controller.page.tableTitles),
+        columnNames: controller.page.tableColumns ?? [],
+        rows: controller.listRows ?? [],
         showEditIcon: true,
+        pageController: controller,
         buttons: <Widget>[
           ButtonBar(alignment: MainAxisAlignment.center, children: [
-            RaisedButton(
-              child: Text('Suchen'),
-              onPressed: () {
-                rows = null;
-                if (_formKey.currentState.validate()) {
-                  _formKey.currentState.save();
-                  getRows();
-                }
-              },
-            ),
+            controller.searchButton(),
             RaisedButton(
               child: Text('Neue Rolle'),
               onPressed: () {
                 Navigator.pushNamed(context, '/configuration/create');
+
+                /// Force the redraw on return:
+                controller.listRows = null;
               },
             ),
           ]),
@@ -72,20 +72,4 @@ class ConfigurationListPageState extends State<ConfigurationListPage> {
       ),
     );
   }
-
-  void getRows() {
-    final persistence = applicationData.persistence;
-    final namePattern = filters.valueOf('configuration_name') ?? '';
-    persistence.list(module: 'configuration', params: {
-      ':configuration_name': namePattern.replaceAll('*', '%') + '%'
-    }).then((list) {
-      if (rows == null) {
-        rows = list;
-        setState(() {});
-      }
-    }, onError: (error) {
-      applicationData.logger
-          .error('cannot retrieve configuration list: $error');
-    });
-  }
 }
index 5ee94d7ee2f66bc85e9198ca36d3575400ec825c..8c65cf3f97d2898346a8afe0fae29f57aff5124f 100644 (file)
@@ -1,22 +1,27 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
 
 import '../../widget/edit_form.dart';
 import 'role_controller.dart';
 
 class RoleChangePage extends StatefulWidget {
   final ApplicationData applicationData;
+  final Map initialRow;
   final logger = Settings().logger;
   final int primaryId;
   //RoleChangePageState lastState;
 
-  RoleChangePage(this.primaryId, this.applicationData, {Key key})
+  RoleChangePage(this.primaryId, this.applicationData, this.initialRow,
+      {Key key})
       : super(key: key);
 
   @override
   RoleChangePageState createState() {
-    final rc = RoleChangePageState(primaryId, applicationData);
-    // lastState = rc;
+    final rc = RoleChangePageState(primaryId, applicationData, initialRow);
+
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
@@ -24,21 +29,24 @@ class RoleChangePage extends StatefulWidget {
 class RoleChangePageState extends State<RoleChangePage> {
   final ApplicationData applicationData;
   final int primaryId;
+  final Map initialRow;
   final GlobalKey<FormState> _formKey =
       GlobalKey<FormState>(debugLabel: 'role_change');
 
   RoleController controller;
 
-  RoleChangePageState(this.primaryId, this.applicationData);
+  RoleChangePageState(this.primaryId, this.applicationData, this.initialRow);
 
   @override
   Widget build(BuildContext context) {
     if (controller == null) {
       controller = RoleController(
-          _formKey, this, 'list', context, applicationData,
-          redrawCallback: () => setState(() => null));
+          _formKey, this, 'change', context, applicationData,
+          redrawCallback: (RedrawReason reason, String customString) =>
+              setState(() => null));
       controller.initialize();
     }
+    // controller.buildWidgetList() is called in editForm
     return Scaffold(
         appBar: applicationData.appBarBuilder('Rolle ändern'),
         drawer: applicationData.drawerBuilder(context),
@@ -47,6 +55,11 @@ class RoleChangePageState extends State<RoleChangePage> {
           pageController: controller,
           configuration: applicationData.configuration,
           primaryId: primaryId,
+          initialRow: initialRow,
         ));
   }
+  void dispose() {
+    controller.dispose();
+    super.dispose();
+  }
 }
index 2bfa22c66f4b77f400166e525fa44876ffb7e701..3aff56f50498ff064f8d0b4d143899e72cb43816 100644 (file)
@@ -15,8 +15,9 @@ class RoleController extends PageControllerBones {
     moduleModel.parse();
   }
   @override
-  void startChange(int id) {
+  void startChange(int id, Map row) {
+    applicationData.pushCaller(this);
     Navigator.push(context,
-        MaterialPageRoute(builder: (context) => RoleChangePage(id, applicationData)));
+        MaterialPageRoute(builder: (context) => RoleChangePage(id, applicationData, row)));
   }
 }
index 30174877d8a994fe5da988b6be84ff03322fc4a3..875bea9c9158fd34b7007c9c6d09ead1907c69c5 100644 (file)
@@ -5,14 +5,17 @@ import '../../widget/edit_form.dart';
 import 'role_controller.dart';
 
 class RoleCreatePage extends StatefulWidget {
-  final ApplicationData pageData;
+  final ApplicationData applicationData;
   final logger = Settings().logger;
 
-  RoleCreatePage(this.pageData, {Key key}) : super(key: key);
+  RoleCreatePage(this.applicationData, {Key key}) : super(key: key);
 
   @override
   RoleCreatePageState createState() {
-    final rc = RoleCreatePageState(pageData);
+    final rc = RoleCreatePageState(applicationData);
+
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
@@ -34,6 +37,7 @@ class RoleCreatePageState extends State<RoleCreatePage> {
           RoleController(_formKey, this, 'create', context, applicationData);
       controller.initialize();
     }
+    controller.buildWidgetList();
     return Scaffold(
         appBar: applicationData.appBarBuilder('Neue Rolle'),
         drawer: applicationData.drawerBuilder(context),
index e27f868bf80b95dfe3edd7354f0f4173721923fc..6b85f500a87fe8f2bc541d09e06ab886e2a020d0 100644 (file)
@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
 
 import '../../widget/filter_set.dart';
 import '../../widget/list_form.dart';
@@ -6,15 +7,17 @@ import '../application_data.dart';
 import 'role_controller.dart';
 
 class RoleListPage extends StatefulWidget {
-  final ApplicationData pageData;
+  final ApplicationData applicationData;
 
-  RoleListPage(this.pageData, {Key key}) : super(key: key);
+  RoleListPage(this.applicationData, {Key key}) : super(key: key);
 
   @override
   RoleListPageState createState() {
     // RoleListPageState.setPageData(pageData);
-    final rc = RoleListPageState(pageData);
+    final rc = RoleListPageState(applicationData);
 
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
@@ -33,10 +36,21 @@ class RoleListPageState extends State<RoleListPage> {
   @override
   Widget build(BuildContext context) {
     if (controller == null) {
-      controller = RoleController(
-          _formKey, this, 'list', context, applicationData,
-          redrawCallback: () => setState(() => null));
+      controller =
+          RoleController(_formKey, this, 'list', context, applicationData,
+              redrawCallback: (RedrawReason reason, String customString) {
+        if (reason == RedrawReason.fetchList) {
+          applicationData.persistence
+              .list(
+                  module: controller.moduleModel.name,
+                  params: controller.buildSqlParams())
+              .then((rows) {
+            setState(() => null);
+          });
+        }
+      });
       controller.initialize();
+      controller.buildWidgetList();
     }
     filters ??= controller.filterSet(pageName: 'list');
     controller.buildRows();
@@ -46,8 +60,8 @@ class RoleListPageState extends State<RoleListPage> {
       body: ListForm.listForm(
         key: _formKey,
         configuration: applicationData.configuration,
-        titles: ListForm.stringsToTitles(';Id;Name;Priorität'),
-        columnNames: 'role_id role_name role_priority'.split(' '),
+        titles: ListForm.stringsToTitles(controller.page.tableTitles),
+        columnNames: controller.page.tableColumns ?? [],
         rows: controller.listRows ?? [],
         showEditIcon: true,
         pageController: controller,
index 50f2cab67c807008b2a04ffdbf6622e4fd0cd7e7..c548fa1a3c09a8072a8a731a272b25e9ef137ae4 100644 (file)
@@ -1,39 +1,52 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
 
 import '../../widget/edit_form.dart';
 import 'user_controller.dart';
 
 class UserChangePage extends StatefulWidget {
   final ApplicationData applicationData;
+  final Map initialRow;
   final logger = Settings().logger;
-
+  final int primaryId;
   //UserChangePageState lastState;
 
-  UserChangePage(this.applicationData, {Key key}) : super(key: key);
+  UserChangePage(this.primaryId, this.applicationData, this.initialRow,
+      {Key key})
+      : super(key: key);
 
   @override
   UserChangePageState createState() {
-    final rc = UserChangePageState(applicationData);
-    // lastState = rc;
+    final rc = UserChangePageState(primaryId, applicationData, initialRow);
+
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
 
 class UserChangePageState extends State<UserChangePage> {
   final ApplicationData applicationData;
-
+  final int primaryId;
+  final Map initialRow;
   final GlobalKey<FormState> _formKey =
       GlobalKey<FormState>(debugLabel: 'user_change');
 
   UserController controller;
 
-  UserChangePageState(this.applicationData);
+  UserChangePageState(this.primaryId, this.applicationData, this.initialRow);
 
   @override
   Widget build(BuildContext context) {
-    controller = controller ??
-        UserController(_formKey, this, 'change', context, applicationData);
+    if (controller == null) {
+      controller = UserController(
+          _formKey, this, 'change', context, applicationData,
+          redrawCallback: (RedrawReason reason, String customString) =>
+              setState(() => null));
+      controller.initialize();
+    }
+    // controller.buildWidgetList() is called in editForm
     return Scaffold(
         appBar: applicationData.appBarBuilder('Rolle ändern'),
         drawer: applicationData.drawerBuilder(context),
@@ -41,6 +54,12 @@ class UserChangePageState extends State<UserChangePage> {
           key: _formKey,
           pageController: controller,
           configuration: applicationData.configuration,
+          primaryId: primaryId,
+          initialRow: initialRow,
         ));
   }
+  void dispose() {
+    controller.dispose();
+    super.dispose();
+  }
 }
index 22db52412c5d8b15ee4005ca342c10b204b1bb88..9358424ad85e64515c10c9cd5ace1aa6c8a79610 100644 (file)
@@ -2,20 +2,22 @@ import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
 
 import '../../model/standard/user_model.dart';
+import 'user_change_page.dart';
 import '../../widget/page_controller_bones.dart';
 
 class UserController extends PageControllerBones {
   /// Controller for a page named [pageName].
   UserController(GlobalKey<FormState> formKey, State<StatefulWidget> parent,
-      String pageName, BuildContext context, ApplicationData applicationData)
-      : super(
-          formKey,
-          parent,
-          UserModel(Settings().logger),
-          pageName,
-          context,
-          applicationData,
-        ) {
+      String pageName, BuildContext context, ApplicationData applicationData,
+      {Function redrawCallback})
+      : super(formKey, parent, UserModel(Settings().logger), pageName, context,
+            applicationData, redrawCallback) {
     moduleModel.parse();
   }
+  @override
+  void startChange(int id, Map row) {
+    applicationData.pushCaller(this);
+    Navigator.push(context,
+        MaterialPageRoute(builder: (context) => UserChangePage(id, applicationData, row)));
+  }
 }
index eada47565b53aa161bcfb3e614d04976620fc483..0837ca8ef921e677379801adf3765a67209d1844 100644 (file)
@@ -5,14 +5,17 @@ import '../../widget/edit_form.dart';
 import 'user_controller.dart';
 
 class UserCreatePage extends StatefulWidget {
-  final ApplicationData pageData;
+  final ApplicationData applicationData;
   final logger = Settings().logger;
 
-  UserCreatePage(this.pageData, {Key key}) : super(key: key);
+  UserCreatePage(this.applicationData, {Key key}) : super(key: key);
 
   @override
   UserCreatePageState createState() {
-    final rc = UserCreatePageState(pageData);
+    final rc = UserCreatePageState(applicationData);
+
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
@@ -29,8 +32,12 @@ class UserCreatePageState extends State<UserCreatePage> {
 
   @override
   Widget build(BuildContext context) {
-    controller = controller ??
-        UserController(_formKey, this, 'create', context, applicationData);
+    if (controller == null) {
+      controller =
+          UserController(_formKey, this, 'create', context, applicationData);
+      controller.initialize();
+    }
+    controller.buildWidgetList();
     return Scaffold(
         appBar: applicationData.appBarBuilder('Neue Rolle'),
         drawer: applicationData.drawerBuilder(context),
index 55ba74ea2f4472160c5acb03c2b2503cf71403ca..2715dac297a74f6dd9a0d73571d5aab1d9fbe74b 100644 (file)
@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
 
 import '../../widget/filter_set.dart';
 import '../../widget/list_form.dart';
@@ -6,15 +7,16 @@ import '../application_data.dart';
 import 'user_controller.dart';
 
 class UserListPage extends StatefulWidget {
-  final ApplicationData pageData;
+  final ApplicationData applicationData;
 
-  UserListPage(this.pageData, {Key key}) : super(key: key);
+  UserListPage(this.applicationData, {Key key}) : super(key: key);
 
   @override
   UserListPageState createState() {
     // UserListPageState.setPageData(pageData);
-    final rc = UserListPageState(pageData);
-
+    final rc = UserListPageState(applicationData);
+    /// for unittests:
+    applicationData.lastModuleState = rc;
     return rc;
   }
 }
@@ -24,7 +26,7 @@ class UserListPageState extends State<UserListPage> {
 
   final GlobalKey<FormState> _formKey =
       GlobalKey<FormState>(debugLabel: 'user_list');
-  Iterable<dynamic> rows;
+  Iterable<dynamic> rowsDeprecated;
   UserController controller;
   FilterSet filters;
 
@@ -32,36 +34,36 @@ class UserListPageState extends State<UserListPage> {
 
   @override
   Widget build(BuildContext context) {
-    controller ??=
-        UserController(_formKey, this, 'list', context, applicationData);
+    if (controller == null) {
+      controller = UserController(
+          _formKey, this, 'list', context, applicationData,
+          redrawCallback: (RedrawReason reason, String customString) => setState(() => null));
+      controller.initialize();
+      controller.buildWidgetList();
+    }
     filters ??= controller.filterSet(pageName: 'list');
-    getRows();
+    controller.buildRows();
     return Scaffold(
       appBar: applicationData.appBarBuilder('Rollen'),
       drawer: applicationData.drawerBuilder(context),
       body: ListForm.listForm(
         key: _formKey,
         configuration: applicationData.configuration,
-        titles: ListForm.stringsToTitles(';Id;Name;Priorität'),
-        columnNames: 'user_id user_name user_priority'.split(' '),
-        rows: rows ?? [],
+        titles: ListForm.stringsToTitles(controller.page.tableTitles),
+        columnNames: controller.page.tableColumns ?? [],
+        rows: controller.listRows ?? [],
         showEditIcon: true,
+        pageController: controller,
         buttons: <Widget>[
           ButtonBar(alignment: MainAxisAlignment.center, children: [
-            RaisedButton(
-              child: Text('Suchen'),
-              onPressed: () {
-                rows = null;
-                if (_formKey.currentState.validate()) {
-                  _formKey.currentState.save();
-                  getRows();
-                }
-              },
-            ),
+            controller.searchButton(),
             RaisedButton(
               child: Text('Neue Rolle'),
               onPressed: () {
                 Navigator.pushNamed(context, '/user/create');
+
+                /// Force the redraw on return:
+                controller.listRows = null;
               },
             ),
           ]),
@@ -70,19 +72,4 @@ class UserListPageState extends State<UserListPage> {
       ),
     );
   }
-
-  void getRows() {
-    final persistence = applicationData.persistence;
-    final namePattern = filters.valueOf('user_name') ?? '';
-    persistence.list(module: 'user', params: {
-      ':user_name': namePattern.replaceAll('*', '%') + '%'
-    }).then((list) {
-      if (rows == null) {
-        rows = list;
-        setState(() {});
-      }
-    }, onError: (error) {
-      applicationData.logger.error('cannot retrieve user list: $error');
-    });
-  }
 }
index dd72b93a4937018324b67169f64b59012d53d504..7fd48334ff283cfe002f766a67055122f020fbd6 100644 (file)
@@ -55,8 +55,11 @@ class BonesDrawer extends Drawer {
                       ),
                     ),
                   ),
-                  onTap: () => Navigator.push(context,
-                      MaterialPageRoute(builder: (context) => item.page())),
+                  onTap: () {
+                    BSettings().pageData.pushCaller(null);
+                    Navigator.push(context,
+                        MaterialPageRoute(builder: (context) => item.page()));
+                  },
                 ),
               ))
           .toList(),
index 8a84fe0f05bd2ddf78f2104ad366b0020b65581e..21ca3adeda713f5e8ef195c458dc196fd87fd63e 100644 (file)
@@ -1,6 +1,9 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
 
+typedef RedrawCallbackFunction = Function(
+    RedrawReason reason, String customString);
+
 /// Interface for a callback controller for flutter_bones specific widgets.
 /// flutter_bones specific widgets: [CheckboxListTileBone],
 /// [DropDownButtonFormBone], [RaisedButtonBone], [TextFormFieldBone]
@@ -8,20 +11,23 @@ abstract class CallbackControllerBones {
   /// Prepares the rows shown in the list page
   void buildRows();
 
-  List<String> comboboxTexts(
-      String customString, CallbackControllerBones controller);
+  /// Returns the texts of the [ComboboxModel] named [name].
+  List<String> comboboxTexts(String name);
 
-  List<dynamic> comboboxValues(
-      String customString, CallbackControllerBones controller);
+  /// Returns the values of the [ComboboxModel] named [name].
+  List<dynamic> comboboxValues(String name);
 
+  /// Frees all resources.
+  void dispose();
+
+  /// Returns the container for application specific information.
   ApplicationData getApplicationData();
 
+  /// Returns the [BuildContext] instance of the page.
   BuildContext getContext();
 
-  FieldModel getModel(String customString, CallbackControllerBones controller);
-
-  String getName();
-
+  /// Returns the [model] named [name].
+  FieldModel getModel(String name);
   ValueChanged<String> getOnChanged(
       String customString, CallbackControllerBones controller);
 
@@ -66,14 +72,26 @@ abstract class CallbackControllerBones {
       String customString, CallbackControllerBones controller, Map row);
 
   /// Rebuilds the view of the page.
-  void redraw();
+  /// [reason] and [customString] will be forwarded to the callback function.
+  void redraw(RedrawReason reason, String customString);
 
   /// Returns a standard search button for the list page.
   Widget searchButton();
 
   /// Starts the change page to edit the record with primary key [id].
-  void startChange(int id);
+  /// [row] contains the db record of [id].
+  void startChange(int id, Map row);
+
+  /// Returns the [TextEditingController] instance of a [TextFormField] assigned
+  /// to a model named [name].
+  TextEditingController textController(String name);
 
-  /// Returns the field value of field named [fieldName] or null if not found.
+  /// Returns the field value of [FieldModel] named [fieldName] or null if not found.
   dynamic valueOf(String fieldName);
 }
+
+enum RedrawReason {
+  custom,
+  fetchList,
+  fetchRecord,
+}
index 2a54d0e6004d4281c6eaba3dec03378f2ae30dbd..0cb325782b528f008303d25b33f9b4e0c7e1ff29 100644 (file)
@@ -1,6 +1,5 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
-import 'page_controller_bones.dart';
 
 class CheckboxFormField extends FormField<bool> {
   CheckboxFormField({
index 7dc0f93e4dfb5c5bffee3fc4d18051083aa2db02..428ef510d87b049b076ea6bb3a741a1b463d0ad5 100644 (file)
@@ -17,13 +17,12 @@ class EditForm {
     @required PageControllerBones pageController,
     @required BaseConfiguration configuration,
     int primaryId,
+    Map initialRow,
   }) {
     final padding =
         configuration.asFloat('form.card.padding', defaultValue: 16.0);
+    pageController.buildWidgetList(initialRow);
     final widgets = pageController.getWidgets();
-    if (primaryId != null){
-      pageController.fetchData(primaryId);
-    }
     return Form(
       key: key,
       child: Card(
index 7d16fbf5c306bcb50bab6144aa284cc9e81307ca..90d0e440867abe9544fc27ca4d51f7ea16a88b7e 100644 (file)
@@ -18,10 +18,8 @@ class ListForm {
   /// Format of [titles]: first character is the delimiter, e.g. ";Id;Name;"
   /// This allows to use different delimiters when the title text
   /// contains characters normally used as delimiters.
-  static List<Widget> stringsToTitles(String titles) {
+  static List<Widget> stringsToTitles(List<String> titles) {
     final rc = titles
-        .substring(1)
-        .split(titles[0])
         .map((String title) =>
             Text(title, style: TextStyle(fontWeight: FontWeight.bold)))
         .toList();
@@ -45,7 +43,9 @@ class ListForm {
     TableCallbackController tableCallbackController,
     String customString,
   }) {
-    assert(titles.length == columnNames.length);
+    if (titles.length != columnNames.length){
+      controller.moduleModel.logger.error('titles.length != columnNames.length: ${titles.length}/${columnNames.length}');
+    }
     final titles2 = titles.map((item) => DataColumn(label: item)).toList();
     if (showEditIcon) {
       titles2.insert(0, DataColumn(label: SizedBox(width: 1)));
index 5d8f6c1914ada0f0b1ffbe0135c99ef3163ff606..c32bbf4e083021ae41b4878cebceb6996d8c328c 100644 (file)
@@ -1,3 +1,4 @@
+import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
 import 'package:flutter_bones/src/widget/widget_list.dart';
@@ -14,9 +15,7 @@ class PageControllerBones implements CallbackControllerBones {
   final ModuleModel moduleModel;
   String primaryColumn;
   WidgetList widgetList;
-  final Function redrawCallback;
-  bool needsRedraw;
-  //WidgetList changeWidgets;
+  final RedrawCallbackFunction redrawCallback;
   final GlobalKey<FormState> globalKey;
   final String pageName;
   PageModel page;
@@ -24,19 +23,20 @@ class PageControllerBones implements CallbackControllerBones {
   State parent;
   final BuildContext context;
   Iterable listRows;
+  final textControllers = <String, TextEditingController>{};
 
   PageControllerBones(this.globalKey, this.parent, this.moduleModel,
       this.pageName, this.context, this.applicationData,
       [this.redrawCallback]);
+
   @override
   void buildRows() {
-    needsRedraw = true;
     final persistence = applicationData.persistence;
     final params = buildSqlParams() ?? {};
     persistence.list(module: 'role', params: params).then((list) {
       if (listRows == null) {
         listRows = list;
-        redraw();
+        redraw(RedrawReason.fetchList, null);
       }
     }, onError: (error) {
       applicationData.logger.error('cannot retrieve role list: $error');
@@ -51,7 +51,6 @@ class PageControllerBones implements CallbackControllerBones {
         dynamic value = element.value;
         DataType dataType = element.dataType;
         String name = element.name;
-        String operator;
         if (element.filterType == FilterType.pattern) {
           if (value == null || value.isEmpty) {
             value = '%';
@@ -67,17 +66,33 @@ class PageControllerBones implements CallbackControllerBones {
     return rc;
   }
 
+  /// Prepares the widgetList: builds the widgets of the page.
+  /// [initialRow] is null or a map with the field values, e.g. { 'role_name': 'admin' ...}
+  void buildWidgetList([Map initialRow]) {
+    widgetList.clear();
+    page.fields.forEach((model) {
+      final value = initialRow == null ? null : initialRow[model.name];
+      widgetList.addWidget(model.name,
+          View(moduleModel.logger).modelToWidget(model, this, value));
+    });
+  }
+
   @override
-  List<String> comboboxTexts(
-      String customString, CallbackControllerBones controller) {
+  List<String> comboboxTexts(String name) {
     return [];
   }
 
   @override
-  List comboboxValues(String customString, CallbackControllerBones controller) {
+  List comboboxValues(String name) {
     return [];
   }
 
+  @override
+  void dispose() {
+    textControllers.values.forEach((controller) => controller.dispose());
+    textControllers.clear();
+  }
+
   /// Gets the data from the database using the [primaryId].
   fetchData(int primaryId) async {
     applicationData.persistence
@@ -86,8 +101,9 @@ class PageControllerBones implements CallbackControllerBones {
       page.fields.forEach((model) {
         model.value = row[model.name];
       });
-      needsRedraw = true;
-      redraw();
+
+      /// navigate to the page "change":
+      startChange(primaryId, row);
     });
   }
 
@@ -118,18 +134,13 @@ class PageControllerBones implements CallbackControllerBones {
   }
 
   @override
-  FieldModel getModel(String customString, CallbackControllerBones controller) {
-    final rc = moduleModel.pageByName(pageName)?.getField(customString);
+  FieldModel getModel(String name) {
+    final rc = moduleModel.pageByName(pageName)?.fieldByName(name);
     return rc;
   }
 
   ModuleModel getModuleModel() => moduleModel;
 
-  @override
-  String getName() {
-    return null;
-  }
-
   @override
   getOnChanged(String customString, CallbackControllerBones controller) {
     return null;
@@ -192,12 +203,17 @@ class PageControllerBones implements CallbackControllerBones {
             case PageModelType.create:
               applicationData.persistence
                   .insert(module: moduleModel.name, data: params);
+                applicationData.popCaller();
               Navigator.pop(controller.getContext());
               break;
             case PageModelType.change:
               applicationData.persistence
-                  .update(module: moduleModel.name, data: params);
-              Navigator.pop(controller.getContext());
+                  .update(module: moduleModel.name, data: params)
+                  .then((value) {
+                applicationData.callerRedraw(RedrawReason.fetchList);
+                applicationData.popCaller();
+                Navigator.pop(controller.getContext());
+              });
               break;
             default:
               moduleModel.logger
@@ -207,7 +223,10 @@ class PageControllerBones implements CallbackControllerBones {
         }
       };
     } else if (customString == 'cancel') {
-      rc = () => Navigator.pop(controller.getContext());
+      rc = () {
+        applicationData.popCaller();
+        Navigator.pop(controller.getContext());
+      };
     }
     return rc;
   }
@@ -215,7 +234,7 @@ class PageControllerBones implements CallbackControllerBones {
   @override
   getOnSaved(String customString, CallbackControllerBones controller) {
     final rc = (input) {
-      FieldModel model = page.getField(customString);
+      FieldModel model = page.fieldByName(customString);
       model.value = StringHelper.fromString(input, model.dataType);
     };
     return rc;
@@ -255,12 +274,16 @@ class PageControllerBones implements CallbackControllerBones {
   /// e.g. ModuleModel.parse() is called.
   /// This method must be called early after the constructor.
   void initialize() {
-    widgetList =
-        WidgetList('${moduleModel.fullName()}.widgets', moduleModel.logger);
     page = moduleModel.pageByName(pageName);
-    page.fields.forEach((model) {
-      widgetList.addWidget(
-          model.name, View(moduleModel.logger).modelToWidget(model, this));
+    widgetList = WidgetList('${page.fullName()}.widgets', moduleModel.logger);
+  }
+
+  /// Copies the values of [initialRow] into the values of the fields.
+  void initializeFields(Map initialRow) {
+    widgetList.widgetMap.keys.forEach((name) {
+      if (initialRow.containsKey(name)) {
+        page.fieldByName(name)?.value = initialRow[name];
+      }
     });
   }
 
@@ -268,19 +291,18 @@ class PageControllerBones implements CallbackControllerBones {
   onEditTap(String customString, CallbackControllerBones controller, Map row) {
     ColumnModel primary = moduleModel.mainTable().primary;
     final id = row[primary.name];
-    controller.startChange(id);
+    applicationData.persistence
+        .record(module: moduleModel.name, id: id)
+        .then((row) => startChange(id, row));
   }
 
   @override
-  void redraw() {
+  void redraw(RedrawReason reason, [String customString]) {
     if (redrawCallback == null) {
       moduleModel.logger.error(
           'not overridden: fetchListRows() in ${moduleModel.widgetName()}.$pageName');
     } else {
-      if (needsRedraw) {
-        needsRedraw = false;
-        redrawCallback();
-      }
+      redrawCallback(reason, customString);
     }
   }
 
@@ -292,14 +314,24 @@ class PageControllerBones implements CallbackControllerBones {
   }
 
   @override
-  void startChange(int id) {
+  void startChange(int id, Map row) {
     moduleModel.logger.error(
         'missing override of startChange() in ${moduleModel.fullName()}');
   }
 
+  /// Returns the [TextEditingController] of a [TextFormField] assigned to
+  /// a model named [name].
+  @override
+  TextEditingController textController(String name) {
+    if (!textControllers.containsKey(name)) {
+      textControllers[name] = TextEditingController();
+    }
+    return textControllers[name];
+  }
+
   @override
   dynamic valueOf(String fieldName) {
-    final rc = page.getField(fieldName)?.value;
+    final rc = page.fieldByName(fieldName)?.value;
     return rc;
   }
 }
index 826e61acef063180771df44f355068a30e804637..2fa200046747c068bc4e745ff9e98bff657f9bff 100644 (file)
@@ -56,23 +56,25 @@ class View {
     return rc;
   }
 
-  /// Creates a checkbox from the [model].
-  Widget checkbox(FieldModel model, CallbackControllerBones controller) {
+  /// Creates a checkbox from the [model] using the controller with the value [initialValue].
+  Widget checkbox(FieldModel model, CallbackControllerBones controller,
+      [bool initialValue]) {
     final tristate = model.hasOption('undef');
     final rc = toolTip(
         CheckboxListTileBone(model.name, controller,
-            value: tristate ? model.value : model.value ?? false,
+            value: tristate ? initialValue : initialValue ?? false,
             tristate: tristate,
             title: Text(model.label),
-            selected: model.value ?? false),
+            selected: initialValue ?? false),
         model);
     return rc;
   }
 
   /// Creates a combobox via the [controller].
-  Widget combobox<T>(FieldModel model, CallbackControllerBones controller) {
-    final texts = controller.comboboxTexts(model.name, controller);
-    final values = controller.comboboxValues(model.name, controller) ?? texts;
+  Widget combobox<T>(
+      FieldModel model, CallbackControllerBones controller, initialValue) {
+    final texts = controller.comboboxTexts(model.name);
+    final values = controller.comboboxValues(model.name) ?? texts;
     final items = <DropdownMenuItem<T>>[];
     for (var ix = 0; ix < texts.length; ix++) {
       items.add(DropdownMenuItem(
@@ -80,19 +82,20 @@ class View {
           value: values[ix],
           child: Text(texts[ix])));
     }
-    final rc = DropdownButtonFormBone(model.name, controller, items: items);
+    final rc = DropdownButtonFormBone(model.name, controller,
+        items: items, value: initialValue);
     return rc;
   }
 
-  Widget dbReference(
-      DbReferenceModel model, CallbackControllerBones controller) {
+  Widget dbReference(DbReferenceModel model, CallbackControllerBones controller,
+      initialValue) {
     var rc;
     if (model.dataType == DataType.bool) {
-      rc = checkbox(model, controller);
+      rc = checkbox(model, controller, initialValue);
     } else if (model.hasOption('combobox')) {
-      rc = combobox(model, controller);
+      rc = combobox(model, controller, initialValue);
     } else {
-      rc = textField(model, controller);
+      rc = textField(model, controller, initialValue);
     }
     return rc;
   }
@@ -122,12 +125,14 @@ class View {
     return rc;
   }
 
-  /// Converts a [model] into a [Widget].
-  Widget modelToWidget(WidgetModel model, CallbackControllerBones controller) {
+  /// Converts a [model] into a [Widget] under control of [controller]
+  /// with the [initialValue].
+  Widget modelToWidget(WidgetModel model, CallbackControllerBones controller,
+      [dynamic initialValue]) {
     Widget rc;
     switch (model?.widgetModelType) {
       case WidgetModelType.textField:
-        rc = textField(model, controller);
+        rc = textField(model, controller, initialValue);
         break;
       case WidgetModelType.button:
         rc = button(model, controller);
@@ -139,7 +144,7 @@ class View {
         rc = text(model);
         break;
       case WidgetModelType.checkbox:
-        rc = checkbox(model, controller);
+        rc = checkbox(model, controller, initialValue);
         break;
       case WidgetModelType.combobox:
         rc = text(model);
@@ -151,7 +156,7 @@ class View {
         rc = section(model);
         break;
       case WidgetModelType.dbReference:
-        rc = dbReference(model, controller);
+        rc = dbReference(model, controller, initialValue);
         break;
       case WidgetModelType.allDbFields:
         break;
@@ -203,11 +208,18 @@ class View {
   }
 
   /// Creates a form text field from the [model].
-  Widget textField(FieldModel model, CallbackControllerBones controller) {
+  Widget textField(
+      FieldModel model, CallbackControllerBones controller, initialValue) {
+    final value =
+        initialValue == null ? null : StringHelper.asString(initialValue);
+    final textController = controller.textController(model.name);
+    textController.text = value;
     var rc = toolTip(
         TextFormFieldBone(
           model.name, controller,
           //validator: model.validator,
+          controller: textController,
+          readOnly: model.hasOption('readonly'),
           decoration: InputDecoration(labelText: model.label),
         ),
         model);
index 1957edda162a62e7895a54096b2a7b5f548f3b2e..9fb72affc2d89bb8674a70d261157f07dc1cc5a9 100644 (file)
@@ -58,12 +58,12 @@ class WidgetList {
       String name;
       if (element is TextFormFieldBone) {
         name = element.customString;
-        final model = page.getField(name, required: true);
+        final model = page.fieldByName(name, required: true);
         value = model?.value;
         dataType = model?.dataType;
       } else if (element is DropdownButtonFormBone) {
         name = element.customString;
-        final model = page.getField(name, required: true);
+        final model = page.fieldByName(name, required: true);
         value = model?.value;
         dataType = model?.dataType;
       }
index 17d301fe77c6d6a27795f4a951ad322241bdfd21..eca107c53901c5d6c75a6f3b1ce418d01376651e 100644 (file)
@@ -47,7 +47,7 @@ void main() {
       expect(userField, isNotNull);
       expect(userField.widgetName(), 'user_id');
       expect(userField.fullName(), equals('user.user_id'));
-      final userRef = page.getField('user');
+      final userRef = page.fieldByName('user');
       expect(userRef, isNotNull);
       expect(userRef.fullName(), equals('create.user'));
       expect(userRef.widgetName(), equals('user'));
index a4b5c6a030385c74f99679d4556aa1712fb99bda..b8400a71bd5242c54f587f00baea9949aaceae90 100644 (file)
@@ -36,7 +36,7 @@ void main() {
     allDbFields 12 options: 
     ] # change.simpleForm1
 ''');
-      final userField = page.getField('user');
+      final userField = page.fieldByName('user');
       expect(userField, isNotNull);
       expect(userField.widgetName(), 'user');
       userField.value = 'Hi';
@@ -120,7 +120,7 @@ void main() {
       module.parse();
       var errors = logger.errors;
       expect(errors.length, equals(0));
-      final checkbox = module.pageByName('create').getField('hidden');
+      final checkbox = module.pageByName('create').fieldByName('hidden');
       expect(checkbox.hasOption('required'), isTrue);
       checkbox.value = true;
       expect(checkbox.value, isTrue);
@@ -143,7 +143,7 @@ void main() {
       module.parse();
       var errors = logger.errors;
       expect(errors.length, equals(0));
-      final checkbox = module.pageByName('create').getField('hidden');
+      final checkbox = module.pageByName('create').fieldByName('hidden');
       expect(checkbox, isNotNull);
       expect(checkbox.dataType, DataType.bool);
       final dump = module.dump(StringBuffer()).toString();
@@ -186,7 +186,7 @@ void main() {
       module.parse();
       var errors = logger.errors;
       expect(errors.length, equals(0));
-      final combobox = module.pageByName('create').getField('class');
+      final combobox = module.pageByName('create').fieldByName('class');
       expect(combobox, isNotNull);
       expect(combobox.dataType, DataType.int);
       final dump = module.dump(StringBuffer()).toString();
index ed13de4416bc2f9336ddbf11e36dd3a7d3327230..d67b471f6ccf92f28050f28423d7d84b0713dbd0 100644 (file)
@@ -10,6 +10,7 @@ import 'package:flutter/src/foundation/diagnostics.dart';
 import 'package:flutter/src/widgets/framework.dart' as x;
 import 'package:flutter_bones/flutter_bones.dart';
 import 'package:flutter_bones/src/widget/widget_helper.dart';
+import 'package:flutter_bones/src/private/bsettings.dart';
 import 'package:test/test.dart';
 
 void main() {
@@ -26,24 +27,23 @@ void main() {
       expect(toolTip.child, equals(widget));
     });
   });
-  /*
   group('ModuleController', () {
     test('basic', () {
-      ApplicationData pageData = ApplicationData(
+      ApplicationData appData = ApplicationData(
           BaseConfiguration({}, logger), (title) => null, (context) => null,
-      BSettings.lastInstance.persistence);
-      final role = RoleCreatePage(pageData);
-      if (role.lastState == null) {
+      BSettings.lastInstance.persistence, logger);
+      final role = RoleCreatePage(appData);
+      if (appData.lastModuleState == null) {
         role.createState();
       }
       expect(role, isNotNull);
       BuildContext context = MyContext();
-      role.lastState.build(context);
-      final widgets = role.lastState.controller.getWidgets(true);
+      RoleCreatePageState lastInstance = appData.lastModuleState;
+      lastInstance.build(context);
+      final widgets = lastInstance.controller.getWidgets();
       expect(widgets.length, equals(3));
     });
   });
-  */
 }
 
 class MyContext extends BuildContext {