From: Hamatoma Date: Wed, 21 Oct 2020 11:39:24 +0000 (+0200) Subject: daily work: page role.list works model driven X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=30d649bf268e8182dc1e9200553399340d237f45;p=flutter_bones.git daily work: page role.list works model driven --- diff --git a/lib/app.dart b/lib/app.dart index 3f40034..51fc23d 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -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 = { 'form.card.padding': '16.0', 'form.gap.field_button.height': '16.0', @@ -32,7 +39,7 @@ class BoneAppState extends State { primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), - initialRoute: '/role/change', + initialRoute: '/role/list', onGenerateRoute: _getRoute, ); } @@ -43,16 +50,36 @@ Route _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) { diff --git a/lib/flutter_bones.dart b/lib/flutter_bones.dart index 3dd8821..86d4457 100644 --- a/lib/flutter_bones.dart +++ b/lib/flutter_bones.dart @@ -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'; diff --git a/lib/src/helper/string_helper.dart b/lib/src/helper/string_helper.dart index e94e597..a2cca4e 100644 --- a/lib/src/helper/string_helper.dart +++ b/lib/src/helper/string_helper.dart @@ -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 ...). diff --git a/lib/src/model/standard/role_model.dart b/lib/src/model/standard/role_model.dart index 553a838..1d3e283 100644 --- a/lib/src/model/standard/role_model.dart +++ b/lib/src/model/standard/role_model.dart @@ -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 index 0000000..3cc7b5c --- /dev/null +++ b/lib/src/page/application_data.dart @@ -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 index 0000000..eff1594 --- /dev/null +++ b/lib/src/page/configuration/configuration_change_page.dart @@ -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 { + final ApplicationData pageData; + + final GlobalKey _formKey = GlobalKey(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 index 0000000..2645369 --- /dev/null +++ b/lib/src/page/configuration/configuration_controller.dart @@ -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 formKey, State 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 index 0000000..a776116 --- /dev/null +++ b/lib/src/page/configuration/configuration_create_page.dart @@ -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 { + final ApplicationData pageData; + + final GlobalKey _formKey = GlobalKey(); + + 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 index 0000000..b9b0332 --- /dev/null +++ b/lib/src/page/configuration/configuration_list_page.dart @@ -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 { + ConfigurationListPageState(this.pageData); + + final ApplicationData pageData; + + final GlobalKey _formKey = GlobalKey(); + static Configuration currentConfiguration = Configuration(); + + Iterable getRows(FilterSet filters) { + final rows = >[ + { + '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: [ + RaisedButtonBone( + 'search', + filters, + child: Text('Suchen'), + ), + ], + filters: filters, + ), + ); + } +} + +class Configuration { + int id; + String priority; + String name; +} diff --git a/lib/src/page/login_page.dart b/lib/src/page/login_page.dart index a8282df..e0367fa 100644 --- a/lib/src/page/login_page.dart +++ b/lib/src/page/login_page.dart @@ -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 { LoginPageState(this.pageData); - final PageData pageData; + final ApplicationData pageData; final GlobalKey _formKey = GlobalKey(); static User currentUser = User(); diff --git a/lib/src/page/page_data.dart b/lib/src/page/page_data.dart deleted file mode 100644 index 646e317..0000000 --- a/lib/src/page/page_data.dart +++ /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); -} diff --git a/lib/src/page/role/role_change_page.dart b/lib/src/page/role/role_change_page.dart index 4aa6b23..c0e2e2b 100644 --- a/lib/src/page/role/role_change_page.dart +++ b/lib/src/page/role/role_change_page.dart @@ -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 { - final PageData pageData; + final ApplicationData pageData; - final GlobalKey _formKey = GlobalKey(); + final GlobalKey _formKey = GlobalKey(debugLabel: 'role_change'); RoleController controller; diff --git a/lib/src/page/role/role_controller.dart b/lib/src/page/role/role_controller.dart index 76b27c3..3857773 100644 --- a/lib/src/page/role/role_controller.dart +++ b/lib/src/page/role/role_controller.dart @@ -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; + } } diff --git a/lib/src/page/role/role_create_page.dart b/lib/src/page/role/role_create_page.dart index 85902e8..40a4cf2 100644 --- a/lib/src/page/role/role_create_page.dart +++ b/lib/src/page/role/role_create_page.dart @@ -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 { - final PageData pageData; + final ApplicationData pageData; - final GlobalKey _formKey = GlobalKey(); + final GlobalKey _formKey = GlobalKey(debugLabel: 'role_create'); RoleController controller; diff --git a/lib/src/page/role/role_list_page.dart b/lib/src/page/role/role_list_page.dart index 5d26db0..e51158e 100644 --- a/lib/src/page/role/role_list_page.dart +++ b/lib/src/page/role/role_list_page.dart @@ -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 { - RoleListPageState(this.pageData); - - final PageData pageData; - - final GlobalKey _formKey = GlobalKey(); - static Role currentRole = Role(); + final ApplicationData pageData; - List> getRows(Filters filters) { - final rows = >[ - { - '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 _formKey = + GlobalKey(debugLabel: 'role_list'); + Iterable 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 { 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: [ - 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 index 0000000..a770ffa --- /dev/null +++ b/lib/src/page/user/user_change_page.dart @@ -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 { + final ApplicationData pageData; + + final GlobalKey _formKey = GlobalKey(); + + 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 index 0000000..1532e09 --- /dev/null +++ b/lib/src/page/user/user_controller.dart @@ -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 formKey, State 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 index 0000000..fb9a20a --- /dev/null +++ b/lib/src/page/user/user_create_page.dart @@ -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 { + final ApplicationData pageData; + + final GlobalKey _formKey = GlobalKey(); + + 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 index 0000000..fbdcf70 --- /dev/null +++ b/lib/src/page/user/user_list_page.dart @@ -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 { + UserListPageState(this.pageData); + + final ApplicationData pageData; + + final GlobalKey _formKey = GlobalKey(); + static User currentUser = User(); + + List> getRows(FilterSet filters) { + final rows = >[ + { + '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: [ + RaisedButtonBone( + 'search', + filters, + child: Text('Suchen'), + ), + ], + filters: filters, + ), + ); + } +} + +class User { + int id; + String priority; + String name; +} diff --git a/lib/src/page/user_page.dart b/lib/src/page/user_page.dart index 127a3cd..20276e9 100644 --- a/lib/src/page/user_page.dart +++ b/lib/src/page/user_page.dart @@ -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 { UserPageState(this.pageData); - final PageData pageData; + final ApplicationData pageData; - final GlobalKey _formKey = GlobalKey(); + final GlobalKey _formKey = GlobalKey(debugLabel: 'user_page'); static User currentUser = User(); @override diff --git a/lib/src/persistence/rest_persistence.dart b/lib/src/persistence/rest_persistence.dart index 68896af..676fd52 100644 --- a/lib/src/persistence/rest_persistence.dart +++ b/lib/src/persistence/rest_persistence.dart @@ -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 list( - {String module, String sqlName, Map params}) async { + {String module, String sqlName, Map params}) async { sqlName ??= 'list'; - List rc; + Iterable 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); } diff --git a/lib/src/private/bdrawer.dart b/lib/src/private/bdrawer.dart index 58444f1..c9a9933 100644 --- a/lib/src/private/bdrawer.dart +++ b/lib/src/private/bdrawer.dart @@ -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 menuItems() { - final settings = BSettings.instance; + final settings = BSettings.lastInstance; return [ 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(); diff --git a/lib/src/private/bsettings.dart b/lib/src/private/bsettings.dart index c0b8b5d..15b337c 100644 --- a/lib/src/private/bsettings.dart +++ b/lib/src/private/bsettings.dart @@ -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 index 0000000..c9b1554 --- /dev/null +++ b/lib/src/widget/filter_fields.dart @@ -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 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 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 = []; + final BaseLogger logger; + final GlobalKey globalKey; + + State 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 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; + 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 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 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 index 1c779bb..0000000 --- a/lib/src/widget/filters.dart +++ /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 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 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 = []; - final BaseLogger logger; - final GlobalKey globalKey; - - State 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 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 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 row) { - var rc = true; - for (var filter in filters) { - if (!filter.isValid(row)) { - rc = false; - break; - } - } - return rc; - } -} diff --git a/lib/src/widget/list_form.dart b/lib/src/widget/list_form.dart index 994a8cd..2154dea 100644 --- a/lib/src/widget/list_form.dart +++ b/lib/src/widget/list_form.dart @@ -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 row, int index); @@ -35,7 +35,7 @@ class ListForm { static Widget table({ @required List titles, @required List columnNames, - @required List> rows, + @required Iterable 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 buttons, @required List titles, @required List columnNames, - @required List> rows, + @required Iterable rows, bool showEditIcon = false, TableCallbackController tableCallbackController, @required BaseConfiguration configuration, diff --git a/test/helpers/string_helper_test.dart b/test/helpers/string_helper_test.dart index 7330334..0985f71 100644 --- a/test/helpers/string_helper_test.dart +++ b/test/helpers/string_helper_test.dart @@ -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']; diff --git a/test/rest_persistence_test.dart b/test/rest_persistence_test.dart index bc32ff6..9b3c4ec 100644 --- a/test/rest_persistence_test.dart +++ b/test/rest_persistence_test.dart @@ -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); diff --git a/test/widget/widget_test.dart b/test/widget/widget_test.dart index f713f73..5219b26 100644 --- a/test/widget/widget_test.dart +++ b/test/widget/widget_test.dart @@ -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();