]> gitweb.hamatoma.de Git - flutter_bones.git/commitdiff
daily work: page role.list works model driven
authorHamatoma <author@hamatoma.de>
Wed, 21 Oct 2020 11:39:24 +0000 (13:39 +0200)
committerHamatoma <author@hamatoma.de>
Wed, 21 Oct 2020 11:39:24 +0000 (13:39 +0200)
29 files changed:
lib/app.dart
lib/flutter_bones.dart
lib/src/helper/string_helper.dart
lib/src/model/standard/role_model.dart
lib/src/page/application_data.dart [new file with mode: 0644]
lib/src/page/configuration/configuration_change_page.dart [new file with mode: 0644]
lib/src/page/configuration/configuration_controller.dart [new file with mode: 0644]
lib/src/page/configuration/configuration_create_page.dart [new file with mode: 0644]
lib/src/page/configuration/configuration_list_page.dart [new file with mode: 0644]
lib/src/page/login_page.dart
lib/src/page/page_data.dart [deleted file]
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 [new file with mode: 0644]
lib/src/page/user/user_controller.dart [new file with mode: 0644]
lib/src/page/user/user_create_page.dart [new file with mode: 0644]
lib/src/page/user/user_list_page.dart [new file with mode: 0644]
lib/src/page/user_page.dart
lib/src/persistence/rest_persistence.dart
lib/src/private/bdrawer.dart
lib/src/private/bsettings.dart
lib/src/widget/filter_fields.dart [new file with mode: 0644]
lib/src/widget/filters.dart [deleted file]
lib/src/widget/list_form.dart
test/helpers/string_helper_test.dart
test/rest_persistence_test.dart
test/widget/widget_test.dart

index 3f40034d107ad30b75df471704a2ac90670e364e..51fc23d9f6766a5205b8d9253799b79bb3e9b068 100644 (file)
@@ -6,11 +6,18 @@ 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/page/user/user_change_page.dart';
+import 'src/page/user/user_create_page.dart';
+import 'src/page/user/user_list_page.dart';
+import 'src/page/configuration/configuration_change_page.dart';
+import 'src/page/configuration/configuration_create_page.dart';
+import 'src/page/configuration/configuration_list_page.dart';
 import 'src/private/bsettings.dart';
 
 class BoneApp extends StatefulWidget {
   @override
   BoneAppState createState() {
+    BSettings();
     final mapWidgetData = <String, dynamic>{
       'form.card.padding': '16.0',
       'form.gap.field_button.height': '16.0',
@@ -32,7 +39,7 @@ class BoneAppState extends State<BoneApp> {
         primarySwatch: Colors.blue,
         visualDensity: VisualDensity.adaptivePlatformDensity,
       ),
-      initialRoute: '/role/change',
+      initialRoute: '/role/list',
       onGenerateRoute: _getRoute,
     );
   }
@@ -43,16 +50,36 @@ Route<dynamic> _getRoute(RouteSettings settings) {
   StatefulWidget page;
   switch (settings.name) {
     case '/role/list':
-      page = RoleListPage(BSettings.instance.pageData);
+      page = RoleListPage(BSettings.lastInstance.pageData);
       break;
     case '/role/change':
-      page = RoleChangePage(BSettings.instance.pageData);
+      page = RoleChangePage(BSettings.lastInstance.pageData);
       break;
     case '/role/create':
-      page = RoleCreatePage(BSettings.instance.pageData);
+      page = RoleCreatePage(BSettings.lastInstance.pageData);
       break;
+      /*
+    case '/user/list':
+      page = UserListPage(BSettings.lastInstance.pageData);
+      break;
+    case '/user/change':
+      page = UserChangePage(BSettings.lastInstance.pageData);
+      break;
+    case '/user/create':
+      page = UserCreatePage(BSettings.lastInstance.pageData);
+      break;
+    case '/configuration/list':
+      page = ConfigurationListPage(BSettings.lastInstance.pageData);
+      break;
+    case '/configuration/change':
+      page = ConfigurationChangePage(BSettings.lastInstance.pageData);
+      break;
+    case '/configuration/create':
+      page = ConfigurationCreatePage(BSettings.lastInstance.pageData);
+      break;
+      */
     default:
-      page = LoginPage(BSettings.instance.pageData);
+      page = LoginPage(BSettings.lastInstance.pageData);
       break;
   }
   if (page != null) {
index 3dd8821a0a32f4859926577b9c2fcf3a9546aad0..86d4457086b145497354283bc9de777d52f72096 100644 (file)
@@ -23,8 +23,10 @@ export 'src/model/text_field_model.dart';
 export 'src/model/text_model.dart';
 export 'src/model/widget_model.dart';
 export 'src/page/login_page.dart';
-export 'src/page/page_data.dart';
+export 'src/page/application_data.dart';
 export 'src/page/role/role_create_page.dart';
+export 'src/page/user/user_create_page.dart';
+export 'src/page/configuration/configuration_create_page.dart';
 export 'src/page/user_page.dart';
 export 'src/persistence/persistence.dart';
 export 'src/persistence/rest_persistence.dart';
index e94e597d3a025ac7f491b642772169fa1bc7e253..a2cca4e34f18fc9f24caf431563c0299d26fe5cf 100644 (file)
@@ -7,6 +7,22 @@ class StringHelper {
   static final regExpFalse = RegExp(r'^(false|no)$', caseSensitive: false);
   static const locale = 'de_DE';
 
+  /// Converts any [data] to a string.
+  /// [withSeconds]: only used for DateTime data: true: seconds will be shown
+  /// [sortable]: only used for DateTime data: true: the date is sortable (year first)
+  static String asString(dynamic data,
+      {bool withSeconds = true, bool sortable = true}) {
+    String rc;
+    if (data is String) {
+      rc = data;
+    } else if (data is DateTime) {
+      rc = dateTimeToString(data, withSeconds: withSeconds, sortable: sortable);
+    } else {
+      rc = data.toString();
+    }
+    return rc;
+  }
+
   /// Converts a [dateTime] into a string.
   /// If [dateTime] is null the current date and time is used.
   /// If [sortable] is true the result is sortable (year.month.day ...).
index 553a838b4ddcb4d120ec4194286b80ce3956cf7a..1d3e28384a56503375f7d8958c4f9cc1d5e29077 100644 (file)
@@ -74,6 +74,8 @@ class RoleModel extends ModuleModel {
                 "widgetType": "textField",
                 "filterType": "pattern",
                 "name": "role_name",
+                "label": "Name",
+                "toolTip": "Suchmuster des Rollennamens: Joker: '*' (beliebiger Text), z.B. '*min*'"
               }
             ]
           }
diff --git a/lib/src/page/application_data.dart b/lib/src/page/application_data.dart
new file mode 100644 (file)
index 0000000..3cc7b5c
--- /dev/null
@@ -0,0 +1,18 @@
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+/// Data class for storing parameter to build a page.
+class ApplicationData {
+  final BaseConfiguration configuration;
+
+  /// Signature: AppBar func(String title)
+  final AppBar Function(String title) appBarBuilder;
+  final Drawer Function(dynamic context) drawerBuilder;
+  final Persistence persistence;
+  /// Constructor.
+  /// [configuration] is a map with the widget data (e.g. padding)
+  /// [appBarBuilder] is a factory of a function returning a outside designed AppBar
+  /// [drawerBuilder] is a factory of a function returning a Drawer which handles the "Hamburger menu"
+  ApplicationData(this.configuration, this.appBarBuilder, this.drawerBuilder, this.persistence);
+}
diff --git a/lib/src/page/configuration/configuration_change_page.dart b/lib/src/page/configuration/configuration_change_page.dart
new file mode 100644 (file)
index 0000000..eff1594
--- /dev/null
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../widget/edit_form.dart';
+import 'configuration_controller.dart';
+
+class ConfigurationChangePage extends StatefulWidget {
+  final ApplicationData pageData;
+  final logger = Settings().logger;
+  ConfigurationChangePageState lastState;
+
+  ConfigurationChangePage(this.pageData, {Key key}) : super(key: key);
+
+  @override
+  ConfigurationChangePageState createState() {
+    final rc = lastState = ConfigurationChangePageState(pageData);
+    return rc;
+  }
+}
+
+class ConfigurationChangePageState extends State<ConfigurationChangePage> {
+  final ApplicationData pageData;
+
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>(debugLabel: 'configuration');
+
+  ConfigurationController controller;
+
+  ConfigurationChangePageState(this.pageData);
+
+  @override
+  Widget build(BuildContext context) {
+    controller = controller ?? ConfigurationController(_formKey, this);
+    return Scaffold(
+        appBar: pageData.appBarBuilder('Rolle ändern'),
+        drawer: pageData.drawerBuilder(context),
+        body: EditForm.editForm(
+          key: _formKey,
+          isCreateForm: false,
+          moduleController: controller,
+          configuration: pageData.configuration,
+        ));
+  }
+}
diff --git a/lib/src/page/configuration/configuration_controller.dart b/lib/src/page/configuration/configuration_controller.dart
new file mode 100644 (file)
index 0000000..2645369
--- /dev/null
@@ -0,0 +1,12 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../model/standard/configuration_model.dart';
+import '../../widget/module_controller.dart';
+
+class ConfigurationController extends ModuleController {
+  ConfigurationController(GlobalKey<FormState> formKey, State<StatefulWidget> parent)
+      : super(formKey, parent, ConfigurationModel(Settings().logger)) {
+    moduleModel.parse();
+  }
+}
diff --git a/lib/src/page/configuration/configuration_create_page.dart b/lib/src/page/configuration/configuration_create_page.dart
new file mode 100644 (file)
index 0000000..a776116
--- /dev/null
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../widget/edit_form.dart';
+import 'configuration_controller.dart';
+
+class ConfigurationCreatePage extends StatefulWidget {
+  final ApplicationData pageData;
+  final logger = Settings().logger;
+  ConfigurationCreatePageState lastState;
+
+  ConfigurationCreatePage(this.pageData, {Key key}) : super(key: key);
+
+  @override
+  ConfigurationCreatePageState createState() {
+    final rc = lastState = ConfigurationCreatePageState(pageData);
+    return rc;
+  }
+}
+
+class ConfigurationCreatePageState extends State<ConfigurationCreatePage> {
+  final ApplicationData pageData;
+
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+
+  ConfigurationController controller;
+
+  ConfigurationCreatePageState(this.pageData);
+
+  @override
+  Widget build(BuildContext context) {
+    controller = controller ?? ConfigurationController(_formKey, this);
+    return Scaffold(
+        appBar: pageData.appBarBuilder('Neue Rolle'),
+        drawer: pageData.drawerBuilder(context),
+        body: EditForm.editForm(
+          key: _formKey,
+          isCreateForm: true,
+          moduleController: controller,
+          configuration: pageData.configuration,
+        ));
+  }
+}
diff --git a/lib/src/page/configuration/configuration_list_page.dart b/lib/src/page/configuration/configuration_list_page.dart
new file mode 100644 (file)
index 0000000..b9b0332
--- /dev/null
@@ -0,0 +1,103 @@
+import 'package:flutter/material.dart';
+
+import '../../helper/settings.dart';
+import '../../model/model_types.dart';
+import '../../widget/filter_fields.dart';
+import '../../widget/list_form.dart';
+import '../../widget/raised_button_bone.dart';
+import '../application_data.dart';
+
+class ConfigurationListPage extends StatefulWidget {
+  final ApplicationData pageData;
+
+  ConfigurationListPage(this.pageData, {Key key}) : super(key: key);
+
+  @override
+  ConfigurationListPageState createState() {
+    // ConfigurationListPageState.setPageData(pageData);
+    final rc = ConfigurationListPageState(pageData);
+
+    return rc;
+  }
+}
+
+class ConfigurationListPageState extends State<ConfigurationListPage> {
+  ConfigurationListPageState(this.pageData);
+
+  final ApplicationData pageData;
+
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+  static Configuration currentConfiguration = Configuration();
+
+  Iterable<dynamic> getRows(FilterSet filters) {
+    final rows = <Map<String, dynamic>>[
+      {
+        'configuration_id': '1',
+        'configuration_name': 'Administrator',
+        'configuration_priority': '10',
+      },
+      {
+        'configuration_id': '2',
+        'configuration_name': 'Verwalter',
+        'configuration_priority': '20',
+      },
+      {
+        'configuration_id': '3',
+        'configuration_name': 'Benutzer',
+        'configuration_priority': '30',
+      },
+      {
+        'configuration_id': '4',
+        'configuration_name': 'Gast',
+        'configuration_priority': '40',
+      },
+    ];
+    final rc = rows.where((row) => filters.isValid(row)).toList();
+    return rc;
+  }
+
+  FilterSet filters;
+
+  @override
+  Widget build(BuildContext context) {
+    final logger = Settings().logger;
+    if (filters == null) {
+      filters = FilterSet.ready(
+          _formKey,
+          this,
+          [
+            FilterItem(
+                name: 'configuration_name',
+                filterType: FilterType.pattern,
+                label: 'Name'),
+          ],
+          logger);
+    }
+    return Scaffold(
+      appBar: pageData.appBarBuilder('Rollen'),
+      drawer: pageData.drawerBuilder(context),
+      body: ListForm.listForm(
+        key: _formKey,
+        configuration: pageData.configuration,
+        titles: ListForm.stringsToTitles(';Id;Name;Priorität'),
+        columnNames: 'configuration_id configuration_name configuration_priority'.split(' '),
+        rows: getRows(filters),
+        showEditIcon: true,
+        buttons: <Widget>[
+          RaisedButtonBone(
+            'search',
+            filters,
+            child: Text('Suchen'),
+          ),
+        ],
+        filters: filters,
+      ),
+    );
+  }
+}
+
+class Configuration {
+  int id;
+  String priority;
+  String name;
+}
index a8282dff57e118b6459b3ceb62927cd83f9e2cb9..e0367fa204e22b15d6e44449f60c5565e9707a56 100644 (file)
@@ -3,7 +3,7 @@ import 'package:dart_bones/dart_bones.dart';
 import 'package:flutter_bones/flutter_bones.dart';
 
 class LoginPage extends StatefulWidget {
-  final PageData pageData;
+  final ApplicationData pageData;
   LoginPage(this.pageData, {Key key}) : super(key: key);
 
   @override
@@ -18,7 +18,7 @@ class LoginPage extends StatefulWidget {
 class LoginPageState extends State<LoginPage> {
   LoginPageState(this.pageData);
 
-  final PageData pageData;
+  final ApplicationData pageData;
 
   final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
   static User currentUser = User();
diff --git a/lib/src/page/page_data.dart b/lib/src/page/page_data.dart
deleted file mode 100644 (file)
index 646e317..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-import 'package:dart_bones/dart_bones.dart';
-import 'package:flutter/material.dart';
-
-/// Data class for storing parameter to build a page.
-class PageData {
-  BaseConfiguration configuration;
-
-  /// Signature: AppBar func(String title)
-  AppBar Function(String title) appBarBuilder;
-  Drawer Function(dynamic context) drawerBuilder;
-
-  /// Constructor.
-  /// [configuration] is a map with the widget data (e.g. padding)
-  /// [appBarBuilder] is a factory of a function returning a outside designed AppBar
-  /// [drawerBuilder] is a factory of a function returning a Drawer which handles the "Hamburger menu"
-  PageData(this.configuration, this.appBarBuilder, this.drawerBuilder);
-}
index 4aa6b2305c5013c0c354f8e8fe09e57b136edcc9..c0e2e2baf92db395953a6be7547d49389edf7c4f 100644 (file)
@@ -5,7 +5,7 @@ import '../../widget/edit_form.dart';
 import 'role_controller.dart';
 
 class RoleChangePage extends StatefulWidget {
-  final PageData pageData;
+  final ApplicationData pageData;
   final logger = Settings().logger;
   RoleChangePageState lastState;
 
@@ -19,9 +19,9 @@ class RoleChangePage extends StatefulWidget {
 }
 
 class RoleChangePageState extends State<RoleChangePage> {
-  final PageData pageData;
+  final ApplicationData pageData;
 
-  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>(debugLabel: 'role_change');
 
   RoleController controller;
 
index 76b27c3323623b96ec9f11351b68b8064bf6d0bb..385777321b8baad4eff9d921ac150e7e35f8fab0 100644 (file)
@@ -1,5 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/filter_fields.dart';
 
 import '../../model/standard/role_model.dart';
 import '../../widget/module_controller.dart';
@@ -9,4 +10,20 @@ class RoleController extends ModuleController {
       : super(formKey, parent, RoleModel(Settings().logger)) {
     moduleModel.parse();
   }
+  FilterSet filterSet({@required String page}) {
+    final rc = FilterSet(globalKey, parent, moduleModel.logger);
+    moduleModel
+        .pageByName(page)
+        .fields
+        .values
+        .where((element) => element.filterType != null)
+        .forEach((element) {
+      rc.add(FilterItem(
+          label: element.label,
+          filterType: element.filterType,
+          toolTip: element.toolTip,
+          name: element.name));
+    });
+    return rc;
+  }
 }
index 85902e8676594d7c6b3be3bceceaccd22290e997..40a4cf2c0a7d9983394dd9652e72724fe3d8afba 100644 (file)
@@ -5,7 +5,7 @@ import '../../widget/edit_form.dart';
 import 'role_controller.dart';
 
 class RoleCreatePage extends StatefulWidget {
-  final PageData pageData;
+  final ApplicationData pageData;
   final logger = Settings().logger;
   RoleCreatePageState lastState;
 
@@ -19,9 +19,9 @@ class RoleCreatePage extends StatefulWidget {
 }
 
 class RoleCreatePageState extends State<RoleCreatePage> {
-  final PageData pageData;
+  final ApplicationData pageData;
 
-  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>(debugLabel: 'role_create');
 
   RoleController controller;
 
index 5d26db03dc2dbc951caf9943b464fa1aeaa57da9..e51158ea9695fdd1668ed9bbfe1194e8ad4aa8eb 100644 (file)
@@ -2,13 +2,14 @@ import 'package:flutter/material.dart';
 
 import '../../helper/settings.dart';
 import '../../model/model_types.dart';
-import '../../widget/filters.dart';
+import '../../widget/filter_fields.dart';
 import '../../widget/list_form.dart';
 import '../../widget/raised_button_bone.dart';
-import '../page_data.dart';
+import '../application_data.dart';
+import 'role_controller.dart';
 
 class RoleListPage extends StatefulWidget {
-  final PageData pageData;
+  final ApplicationData pageData;
 
   RoleListPage(this.pageData, {Key key}) : super(key: key);
 
@@ -22,57 +23,21 @@ class RoleListPage extends StatefulWidget {
 }
 
 class RoleListPageState extends State<RoleListPage> {
-  RoleListPageState(this.pageData);
-
-  final PageData pageData;
-
-  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
-  static Role currentRole = Role();
+  final ApplicationData pageData;
 
-  List<Map<String, dynamic>> getRows(Filters filters) {
-    final rows = <Map<String, dynamic>>[
-      {
-        'role_id': '1',
-        'role_name': 'Administrator',
-        'role_priority': '10',
-      },
-      {
-        'role_id': '2',
-        'role_name': 'Verwalter',
-        'role_priority': '20',
-      },
-      {
-        'role_id': '3',
-        'role_name': 'Benutzer',
-        'role_priority': '30',
-      },
-      {
-        'role_id': '4',
-        'role_name': 'Gast',
-        'role_priority': '40',
-      },
-    ];
-    final rc = rows.where((row) => filters.isValid(row)).toList();
-    return rc;
-  }
-
-  Filters filters;
+  final GlobalKey<FormState> _formKey =
+      GlobalKey<FormState>(debugLabel: 'role_list');
+  Iterable<dynamic> rows;
+  RoleController controller;
+  FilterSet filters;
+  RoleListPageState(this.pageData);
 
   @override
   Widget build(BuildContext context) {
     final logger = Settings().logger;
-    if (filters == null) {
-      filters = Filters.ready(
-          _formKey,
-          this,
-          [
-            FilterItem(
-                name: 'role_name',
-                filterType: FilterType.pattern,
-                label: 'Name'),
-          ],
-          logger);
-    }
+    controller ??= RoleController(_formKey, this);
+    filters ??= controller.filterSet(page: 'list');
+    getRows();
     return Scaffold(
       appBar: pageData.appBarBuilder('Rollen'),
       drawer: pageData.drawerBuilder(context),
@@ -81,23 +46,44 @@ class RoleListPageState extends State<RoleListPage> {
         configuration: pageData.configuration,
         titles: ListForm.stringsToTitles(';Id;Name;Priorität'),
         columnNames: 'role_id role_name role_priority'.split(' '),
-        rows: getRows(filters),
+        rows: rows ?? [],
         showEditIcon: true,
         buttons: <Widget>[
-          RaisedButtonBone(
-            'search',
-            filters,
-            child: Text('Suchen'),
-          ),
+          ButtonBar(alignment: MainAxisAlignment.center, children: [
+            RaisedButton(
+                child: Text('Suchen'),
+                onPressed: () {
+                  rows = null;
+                  if (_formKey.currentState.validate()) {
+                    _formKey.currentState.save();
+                    getRows();
+                  }
+                },
+            ),
+            RaisedButton(
+              child: Text('Neue Rolle'),
+              onPressed: () {},
+            ),
+          ]),
         ],
         filters: filters,
       ),
     );
   }
-}
 
-class Role {
-  int id;
-  String priority;
-  String name;
+  void getRows() {
+    final persistence = pageData.persistence;
+    var rc;
+    final namePattern = filters.valueOf('role_name') ?? '';
+    persistence.list(
+        module: 'role',
+        params: {':role_name': namePattern.replaceAll('*', '%') + '%'}).then((list) {
+      if (rows == null) {
+        rows = list;
+        setState(() {});
+      }
+    }, onError: (error) {
+      pageData.configuration.logger.error('cannot retrieve role list: $error');
+    });
+  }
 }
diff --git a/lib/src/page/user/user_change_page.dart b/lib/src/page/user/user_change_page.dart
new file mode 100644 (file)
index 0000000..a770ffa
--- /dev/null
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../widget/edit_form.dart';
+import 'user_controller.dart';
+
+class UserChangePage extends StatefulWidget {
+  final ApplicationData pageData;
+  final logger = Settings().logger;
+  UserChangePageState lastState;
+
+  UserChangePage(this.pageData, {Key key}) : super(key: key);
+
+  @override
+  UserChangePageState createState() {
+    final rc = lastState = UserChangePageState(pageData);
+    return rc;
+  }
+}
+
+class UserChangePageState extends State<UserChangePage> {
+  final ApplicationData pageData;
+
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+
+  UserController controller;
+
+  UserChangePageState(this.pageData);
+
+  @override
+  Widget build(BuildContext context) {
+    controller = controller ?? UserController(_formKey, this);
+    return Scaffold(
+        appBar: pageData.appBarBuilder('Rolle ändern'),
+        drawer: pageData.drawerBuilder(context),
+        body: EditForm.editForm(
+          key: _formKey,
+          isCreateForm: false,
+          moduleController: controller,
+          configuration: pageData.configuration,
+        ));
+  }
+}
diff --git a/lib/src/page/user/user_controller.dart b/lib/src/page/user/user_controller.dart
new file mode 100644 (file)
index 0000000..1532e09
--- /dev/null
@@ -0,0 +1,12 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../model/standard/user_model.dart';
+import '../../widget/module_controller.dart';
+
+class UserController extends ModuleController {
+  UserController(GlobalKey<FormState> formKey, State<StatefulWidget> parent)
+      : super(formKey, parent, UserModel(Settings().logger)) {
+    moduleModel.parse();
+  }
+}
diff --git a/lib/src/page/user/user_create_page.dart b/lib/src/page/user/user_create_page.dart
new file mode 100644 (file)
index 0000000..fb9a20a
--- /dev/null
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../widget/edit_form.dart';
+import 'user_controller.dart';
+
+class UserCreatePage extends StatefulWidget {
+  final ApplicationData pageData;
+  final logger = Settings().logger;
+  UserCreatePageState lastState;
+
+  UserCreatePage(this.pageData, {Key key}) : super(key: key);
+
+  @override
+  UserCreatePageState createState() {
+    final rc = lastState = UserCreatePageState(pageData);
+    return rc;
+  }
+}
+
+class UserCreatePageState extends State<UserCreatePage> {
+  final ApplicationData pageData;
+
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+
+  UserController controller;
+
+  UserCreatePageState(this.pageData);
+
+  @override
+  Widget build(BuildContext context) {
+    controller = controller ?? UserController(_formKey, this);
+    return Scaffold(
+        appBar: pageData.appBarBuilder('Neue Rolle'),
+        drawer: pageData.drawerBuilder(context),
+        body: EditForm.editForm(
+          key: _formKey,
+          isCreateForm: true,
+          moduleController: controller,
+          configuration: pageData.configuration,
+        ));
+  }
+}
diff --git a/lib/src/page/user/user_list_page.dart b/lib/src/page/user/user_list_page.dart
new file mode 100644 (file)
index 0000000..fbdcf70
--- /dev/null
@@ -0,0 +1,103 @@
+import 'package:flutter/material.dart';
+
+import '../../helper/settings.dart';
+import '../../model/model_types.dart';
+import '../../widget/filter_fields.dart';
+import '../../widget/list_form.dart';
+import '../../widget/raised_button_bone.dart';
+import '../application_data.dart';
+
+class UserListPage extends StatefulWidget {
+  final ApplicationData pageData;
+
+  UserListPage(this.pageData, {Key key}) : super(key: key);
+
+  @override
+  UserListPageState createState() {
+    // UserListPageState.setPageData(pageData);
+    final rc = UserListPageState(pageData);
+
+    return rc;
+  }
+}
+
+class UserListPageState extends State<UserListPage> {
+  UserListPageState(this.pageData);
+
+  final ApplicationData pageData;
+
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+  static User currentUser = User();
+
+  List<Map<String, dynamic>> getRows(FilterSet filters) {
+    final rows = <Map<String, dynamic>>[
+      {
+        'user_id': '1',
+        'user_name': 'Administrator',
+        'user_priority': '10',
+      },
+      {
+        'user_id': '2',
+        'user_name': 'Verwalter',
+        'user_priority': '20',
+      },
+      {
+        'user_id': '3',
+        'user_name': 'Benutzer',
+        'user_priority': '30',
+      },
+      {
+        'user_id': '4',
+        'user_name': 'Gast',
+        'user_priority': '40',
+      },
+    ];
+    final rc = rows.where((row) => filters.isValid(row)).toList();
+    return rc;
+  }
+
+  FilterSet filters;
+
+  @override
+  Widget build(BuildContext context) {
+    final logger = Settings().logger;
+    if (filters == null) {
+      filters = FilterSet.ready(
+          _formKey,
+          this,
+          [
+            FilterItem(
+                name: 'user_name',
+                filterType: FilterType.pattern,
+                label: 'Name'),
+          ],
+          logger);
+    }
+    return Scaffold(
+      appBar: pageData.appBarBuilder('Rollen'),
+      drawer: pageData.drawerBuilder(context),
+      body: ListForm.listForm(
+        key: _formKey,
+        configuration: pageData.configuration,
+        titles: ListForm.stringsToTitles(';Id;Name;Priorität'),
+        columnNames: 'user_id user_name user_priority'.split(' '),
+        rows: getRows(filters),
+        showEditIcon: true,
+        buttons: <Widget>[
+          RaisedButtonBone(
+            'search',
+            filters,
+            child: Text('Suchen'),
+          ),
+        ],
+        filters: filters,
+      ),
+    );
+  }
+}
+
+class User {
+  int id;
+  String priority;
+  String name;
+}
index 127a3cd05335e8246b4021a2bb3b1aaa6502f14c..20276e9a3b3fbfe1fe0431baafa46d91dbeaea92 100644 (file)
@@ -3,7 +3,7 @@ import 'package:dart_bones/dart_bones.dart';
 import 'package:flutter_bones/flutter_bones.dart';
 
 class UserPage extends StatefulWidget {
-  final PageData pageData;
+  final ApplicationData pageData;
   UserPage(this.pageData, {Key key}) : super(key: key);
 
   @override
@@ -18,9 +18,9 @@ class UserPage extends StatefulWidget {
 class UserPageState extends State<UserPage> {
   UserPageState(this.pageData);
 
-  final PageData pageData;
+  final ApplicationData pageData;
 
-  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+  final GlobalKey<FormState> _formKey = GlobalKey<FormState>(debugLabel: 'user_page');
   static User currentUser = User();
 
   @override
index 68896af5179891316095cc54f810f48544bd2b40..676fd5260bfe5652743d13c94a062019e0bd30f3 100644 (file)
@@ -1,5 +1,4 @@
 import 'dart:convert' as convert;
-
 import 'package:dart_bones/dart_bones.dart';
 import 'package:flutter_bones/src/persistence/persistence.dart';
 import 'package:http/http.dart' as http;
@@ -100,11 +99,12 @@ class RestPersistence extends Persistence {
 
   @override
   Future<dynamic> list(
-      {String module, String sqlName, Map<String, dynamic> params}) async {
+      {String module, String sqlName, Map params}) async {
     sqlName ??= 'list';
-    List<dynamic> rc;
+    Iterable<dynamic> rc;
+    final body = params == null ? '{}' : convert.jsonEncode(params);
     final answer = await runRequest(module, sqlName, 'list',
-        body: params == null ? '{}' : convert.jsonEncode(params));
+        body: body);
     if (answer.isNotEmpty) {
       rc = convert.jsonDecode(answer);
     }
index 58444f1163992061fe4e86c1728085f14da5eb4d..c9a993377952a4da9a986f3389e4cec8ce276373 100644 (file)
@@ -1,7 +1,9 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/flutter_bones.dart';
 import 'package:flutter_bones/src/private/bsettings.dart';
-
+import '../page/configuration/configuration_list_page.dart';
+import '../page/role/role_list_page.dart';
+import '../page/user/user_list_page.dart';
 class MenuItem {
   final String title;
   final dynamic page;
@@ -9,19 +11,25 @@ class MenuItem {
   MenuItem(this.title, this.page, this.icon);
 
   static List<MenuItem> menuItems() {
-    final settings = BSettings.instance;
+    final settings = BSettings.lastInstance;
     return <MenuItem>[
       MenuItem('Login', () => LoginPage(settings.pageData),
           Icons.account_box_outlined),
+      MenuItem('Rollen', () => RoleListPage(settings.pageData),
+          Icons.account_box_outlined),
+      MenuItem('Benutzer', () => UserListPage(settings.pageData),
+          Icons.account_box_outlined),
+      MenuItem('Konfiguration', () => ConfigurationListPage(settings.pageData),
+          Icons.account_box_outlined),
     ];
   }
 }
 
-class VFrageDrawer extends Drawer {
-  VFrageDrawer(context) : super(child: buildGrid(context));
+class BonesDrawer extends Drawer {
+  BonesDrawer(context) : super(child: buildGrid(context));
 
   /// Returns a method creating a drawer.
-  static VFrageDrawer builder(dynamic context) => VFrageDrawer(context);
+  static BonesDrawer builder(dynamic context) => BonesDrawer(context);
 
   static Widget buildGrid(context) {
     final list = MenuItem.menuItems();
index c0b8b5d05b74ab8ce478522ce5bf0e41ea50a8a9..15b337c0e92ed7ba0a7c9956e3323394e91f347f 100644 (file)
@@ -1,30 +1,32 @@
 import 'package:dart_bones/dart_bones.dart';
 import 'package:flutter_bones/flutter_bones.dart';
-import 'package:flutter_bones/src/private/bdrawer.dart';
 import 'package:flutter_bones/src/private/bappbar.dart';
+import 'package:flutter_bones/src/private/bdrawer.dart';
 
 class BSettings {
-  static BSettings _instance;
-
-  /// Returns the singleton of VSetting.
-  static BSettings get instance {
-    if (_instance == null) {
-      final map = {
-        'form.card.padding': '16.0',
-        'form.gap.field_button.height': '16.0',
-      };
-      final logger = MemoryLogger(LEVEL_FINE);
-      final pageData = PageData(BaseConfiguration(map, logger), BAppBar.builder,
-          VFrageDrawer.builder);
-      _instance = BSettings(BaseConfiguration(map, logger), pageData, logger);
-    }
-    return _instance;
-  }
-
   final BaseConfiguration configuration;
-
   final BaseLogger logger;
-
-  final PageData pageData;
-  BSettings(this.configuration, this.pageData, this.logger);
+  final ApplicationData pageData;
+  Persistence persistence;
+  static BSettings lastInstance;
+  /// Returns the singleton of VSetting.
+  factory BSettings() {
+    final map = {
+      'form.card.padding': '16.0',
+      'form.gap.field_button.height': '16.0',
+    };
+    final logger = MemoryLogger(LEVEL_FINE);
+    final persistence = RestPersistence(
+        application: 'flutter_bones',
+        version: '1.0',
+        port: 58011,
+        host: 'localhost',
+        logger: logger);
+    final pageData = ApplicationData(BaseConfiguration(map, logger), BAppBar.builder,
+        BonesDrawer.builder, persistence);
+    final rc =
+        BSettings.internal(BaseConfiguration(map, logger), pageData, persistence, logger);
+    return lastInstance = rc;
+  }
+  BSettings.internal(this.configuration, this.pageData, this.persistence, this.logger);
 }
diff --git a/lib/src/widget/filter_fields.dart b/lib/src/widget/filter_fields.dart
new file mode 100644 (file)
index 0000000..c9b1554
--- /dev/null
@@ -0,0 +1,175 @@
+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/list_form.dart';
+
+import 'text_form_field_bone.dart';
+
+typedef FilterPredicate = bool Function(Map<String, dynamic> row);
+
+class FilterItem {
+  final String name;
+  final String label;
+  final FilterType filterType;
+  final String toolTip;
+  final FilterPredicate filterPredicate;
+  var value;
+
+  FilterItem({
+    this.label,
+    this.filterType,
+    this.toolTip,
+    this.name,
+    this.filterPredicate,
+  });
+
+  bool isValid(Map<String, dynamic> row) {
+    bool rc = true;
+    if (filterPredicate != null) {
+      rc = filterPredicate(row);
+    } else {
+      final current = row[name].toString();
+      final value2 = value ?? '';
+      switch (filterType) {
+        case FilterType.pattern:
+          rc = value2 == ''
+              ? true
+              : (value2.startsWith('*')
+                  ? current.contains(value2.replaceAll('*', ''))
+                  : current.startsWith(value2));
+          break;
+        case FilterType.dateFrom:
+          // TODO: Handle this case.
+          break;
+        case FilterType.dateTil:
+          // TODO: Handle this case.
+          break;
+        case FilterType.dateTimeFrom:
+          // TODO: Handle this case.
+          break;
+        case FilterType.dateTimeTil:
+          // TODO: Handle this case.
+          break;
+        default:
+          rc = true;
+          break;
+      }
+    }
+    return rc;
+  }
+}
+
+class FilterSet
+    implements
+        TextFormCallbackController,
+        ButtonCallbackController,
+        TableCallbackController {
+  var filters = <FilterItem>[];
+  final BaseLogger logger;
+  final GlobalKey globalKey;
+
+  State<StatefulWidget> parent;
+
+  FilterSet(this.globalKey, this.parent, this.logger);
+
+  FilterSet.ready(this.globalKey, this.parent, this.filters, this.logger);
+
+  void add(FilterItem item) => filters.add(item);
+
+  FilterItem byName(String name) =>
+      filters.firstWhere((element) => element.name == name, orElse: () => null);
+  @override
+  getOnChanged(String customString, TextFormCallbackController controller) {
+    return null;
+  }
+  @override
+  getOnEditingComplete(
+      String customString, TextFormCallbackController controller) {
+    return null;
+  }
+
+  @override
+  getOnEditTap(String customString, TableCallbackController controller,
+      Map<String, dynamic> row) {
+    return null;
+  }
+
+  @override
+  getOnFieldSubmitted(
+      String customString, TextFormCallbackController controller) {
+    return null;
+  }
+
+  @override
+  getOnHighlightChanged(
+      String customString, ButtonCallbackController controller) {
+    return null;
+  }
+
+  @override
+  getOnLongPressed(String customString, ButtonCallbackController controller) {
+    return null;
+  }
+
+  @override
+  getOnPressed(String customString, ButtonCallbackController controller) {
+    var rc;
+    if (customString == 'search') {
+      rc = () {
+        final key = globalKey as GlobalKey<FormState>;
+        if (key.currentState.validate()) {
+          key.currentState.save();
+          parent.setState(() => null);
+        }
+      };
+    }
+    return rc;
+  }
+
+  @override
+  getOnSaved(String customString, TextFormCallbackController controller) {
+    return (input) {
+      byName(customString).value = input;
+    };
+  }
+
+  @override
+  getOnTap(String customString, TextFormCallbackController controller) {
+    return null;
+  }
+
+  @override
+  getValidator(String customString, TextFormCallbackController controller) {
+    return null;
+  }
+
+  /// Returns a list of widgets for the filter fields.
+  List<Widget> getWidgets() {
+    final rc = filters.map((filter) {
+      Widget rc = TextFormFieldBone(
+        filter.name,
+        this,
+        decoration: InputDecoration(labelText: filter.label),
+      );
+      if (filter.toolTip != null) {
+        rc = Tooltip(message: filter.toolTip, child: rc);
+      }
+      return rc;
+    }).toList();
+    return rc;
+  }
+
+  /// Tests whether the [row] belongs to the result.
+  bool isValid(Map<String, dynamic> row) {
+    var rc = true;
+    for (var filter in filters) {
+      if (!filter.isValid(row)) {
+        rc = false;
+        break;
+      }
+    }
+    return rc;
+  }
+
+  dynamic valueOf(String name) => byName(name).value;
+}
diff --git a/lib/src/widget/filters.dart b/lib/src/widget/filters.dart
deleted file mode 100644 (file)
index 1c779bb..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-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/list_form.dart';
-
-import 'text_form_field_bone.dart';
-
-typedef FilterPredicate = bool Function(Map<String, dynamic> row);
-
-class FilterItem {
-  final String name;
-  final String label;
-  final FilterType filterType;
-  final String toolTip;
-  final FilterPredicate filterPredicate;
-  var value;
-
-  FilterItem({
-    this.label,
-    this.filterType,
-    this.toolTip,
-    this.name,
-    this.filterPredicate,
-  });
-
-  bool isValid(Map<String, dynamic> row) {
-    bool rc = true;
-    if (filterPredicate != null) {
-      rc = filterPredicate(row);
-    } else {
-      final current = row[name].toString();
-      final value2 = value ?? '';
-      switch (filterType) {
-        case FilterType.pattern:
-          rc = value2 == ''
-              ? true
-              : (value2.startsWith('*')
-                  ? current.contains(value2.replaceAll('*', ''))
-                  : current.startsWith(value2));
-          break;
-        case FilterType.dateFrom:
-          // TODO: Handle this case.
-          break;
-        case FilterType.dateTil:
-          // TODO: Handle this case.
-          break;
-        case FilterType.dateTimeFrom:
-          // TODO: Handle this case.
-          break;
-        case FilterType.dateTimeTil:
-          // TODO: Handle this case.
-          break;
-        default:
-          rc = true;
-          break;
-      }
-    }
-    return rc;
-  }
-}
-
-class Filters
-    implements
-        TextFormCallbackController,
-        ButtonCallbackController,
-        TableCallbackController {
-  var filters = <FilterItem>[];
-  final BaseLogger logger;
-  final GlobalKey<FormState> globalKey;
-
-  State<StatefulWidget> parent;
-
-  Filters(this.globalKey, this.parent, this.logger);
-
-  Filters.ready(this.globalKey, this.parent, this.filters, this.logger);
-
-  void add(FilterItem item) => filters.add(item);
-
-  FilterItem byName(String name) =>
-      filters.firstWhere((element) => element.name == name, orElse: () => null);
-
-  @override
-  getOnChanged(String customString, TextFormCallbackController controller) {
-    return null;
-  }
-
-  @override
-  getOnEditingComplete(
-      String customString, TextFormCallbackController controller) {
-    return null;
-  }
-
-  @override
-  getOnEditTap(String customString, TableCallbackController controller,
-      Map<String, dynamic> row) {
-    return null;
-  }
-
-  @override
-  getOnFieldSubmitted(
-      String customString, TextFormCallbackController controller) {
-    return null;
-  }
-
-  @override
-  getOnHighlightChanged(String customString,
-      ButtonCallbackController controller) {
-    return null;
-  }
-
-  @override
-  getOnLongPressed(String customString, ButtonCallbackController controller) {
-    return null;
-  }
-
-  @override
-  getOnPressed(String customString, ButtonCallbackController controller) {
-    var rc;
-    if (customString == 'search') {
-      rc = () {
-        if (globalKey.currentState.validate()) {
-          globalKey.currentState.save();
-          parent.setState(() => null);
-        }
-      };
-    }
-    return rc;
-  }
-
-  @override
-  getOnSaved(String customString, TextFormCallbackController controller) {
-    return (input) {
-      byName(customString).value = input;
-    };
-  }
-
-  @override
-  getOnTap(String customString, TextFormCallbackController controller) {
-    return null;
-  }
-
-  @override
-  getValidator(String customString, TextFormCallbackController controller) {
-    return null;
-  }
-
-  /// Returns a list of widgets for the filter fields.
-  List<Widget> getWidgets() {
-    final rc = filters.map((filter) {
-      Widget rc = TextFormFieldBone(
-        filter.name,
-        this,
-        decoration: InputDecoration(labelText: filter.label),
-      );
-      if (filter.toolTip != null) {
-        rc = Tooltip(message: filter.toolTip, child: rc);
-      }
-      return rc;
-    }).toList();
-    return rc;
-  }
-
-  /// Tests whether the [row] belongs to the result.
-  bool isValid(Map<String, dynamic> row) {
-    var rc = true;
-    for (var filter in filters) {
-      if (!filter.isValid(row)) {
-        rc = false;
-        break;
-      }
-    }
-    return rc;
-  }
-}
index 994a8cdd81bb6c0801b966f8b0c1b7380f06e005..2154deace83826e6922b538c535836493fb67770 100644 (file)
@@ -1,7 +1,7 @@
 import 'package:dart_bones/dart_bones.dart';
 import 'package:flutter/material.dart';
-
-import 'filters.dart';
+import 'filter_fields.dart';
+import '../helper/string_helper.dart';
 
 typedef Function OnEditTap(Map<String, dynamic> row, int index);
 
@@ -35,7 +35,7 @@ class ListForm {
   static Widget table({
     @required List<Widget> titles,
     @required List<String> columnNames,
-    @required List<Map<String, dynamic>> rows,
+    @required Iterable<dynamic> rows,
     bool showEditIcon = false,
     int sortIndex,
     TableCallbackController tableCallbackController,
@@ -61,7 +61,7 @@ class ListForm {
               }
               for (var key in columnNames) {
                 cells.add(DataCell(
-                  Text(row[key]),
+                  Text(StringHelper.asString(row[key])),
                   onTap: () => tableCallbackController.getOnEditTap(
                       customString, tableCallbackController, row),
                 ));
@@ -78,11 +78,11 @@ class ListForm {
   /// each row is a map with (key, value) pairs.
   /// If [showEditItems] is true the edit icon is shown in the first column.
   static Form listForm({@required Key key,
-    @required Filters filters,
+    @required FilterSet filters,
     @required List<Widget> buttons,
     @required List<Widget> titles,
     @required List<String> columnNames,
-    @required List<Map<String, dynamic>> rows,
+    @required Iterable<dynamic> rows,
     bool showEditIcon = false,
     TableCallbackController tableCallbackController,
     @required BaseConfiguration configuration,
index 7330334e5b170496e8b7c4cb0e6d28025b4442c0..0985f7162c68d0b9447b863c6ec9b67c3bea1723 100644 (file)
@@ -79,6 +79,19 @@ void main() {
           isTrue);
     });
   });
+  group('conversion', () {
+    test('asString', () {
+      expect(StringHelper.asString('abc'), equals('abc'));
+      expect(StringHelper.asString(345), equals('345'));
+      expect(StringHelper.asString(34.5), equals('34.5'));
+      expect(StringHelper.asString(DateTime(2020, 3, 4, 9, 33, 44)),
+          equals('2020.03.04 09:33:44'));
+      expect(
+          StringHelper.asString(DateTime(2020, 3, 4, 9, 33, 44),
+              sortable: false, withSeconds: false),
+          equals('4.3.2020 09:33'));
+    });
+  });
   group("diverse", () {
     test('splitArgs', () {
       var args = ['a', '-a', 'b'];
index bc32ff6b2c889f9f343999ebed73293cae5d2f3c..9b3c4ecdf548f989bc2d339e9dbf073d7618404d 100644 (file)
@@ -27,11 +27,19 @@ void main() async {
     test('list', () async {
       final rest = RestPersistence();
       final list = await rest.list(
-          module: 'role', sqlName: 'list', params: {'":role_name"': '"A%"'});
+          module: 'role', sqlName: 'list', params: {':role_name': 'A%'});
       expect(list, isNotNull);
       expect(list.length, equals(1));
       expect(list[0].containsKey('role_id'), isTrue);
     });
+    test('list-all', () async {
+      final rest = RestPersistence();
+      final list = await rest.list(
+          module: 'role', sqlName: 'list', params: {':role_name': '%'});
+      expect(list, isNotNull);
+      expect(list.length, greaterThanOrEqualTo(4));
+      expect(list[0].containsKey('role_id'), isTrue);
+    });
     test('record', () async {
       final rest = RestPersistence();
       final record = await rest.record(module: 'role', id: 2);
index f713f73bf9fa9422b387605c1797574013f30593..5219b264b8431a9b4226f22ab62070f0b8292129 100644 (file)
@@ -10,6 +10,7 @@ import 'package:flutter/material.dart';
 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/private/bsettings.dart';
 import 'package:flutter_bones/src/widget/widget_helper.dart';
 import 'package:test/test.dart';
 
@@ -29,8 +30,9 @@ void main() {
   });
   group('ModuleController', () {
     test('basic', () {
-      PageData pageData = PageData(
-          BaseConfiguration({}, logger), (title) => null, (context) => null);
+      ApplicationData pageData = ApplicationData(
+          BaseConfiguration({}, logger), (title) => null, (context) => null,
+      BSettings.lastInstance.persistence);
       final role = RoleCreatePage(pageData);
       if (role.lastState == null) {
         role.createState();