DROP TABLE IF EXISTS menu;
CREATE TABLE menu (
menu_id INT(10) UNSIGNED NOT NULL UNIQUE AUTO_INCREMENT,
- menu_name VARCHAR(64) UNIQUE NOT NULL,
- menu_icon INT(10) UNSIGNED,
+ menu_role INT(10) UNSIGNED,
+ menu_starter INT(10) UNSIGNED,
menu_createdat TIMESTAMP NULL,
menu_createdby VARCHAR(16),
menu_changedat TIMESTAMP NULL,
--- /dev/null
+DROP TABLE IF EXISTS starter;
+CREATE TABLE starter (
+ starter_id INT(10) UNSIGNED NOT NULL UNIQUE AUTO_INCREMENT,
+ starter_name VARCHAR(64) UNIQUE NOT NULL,
+ starter_icon INT(10) UNSIGNED,
+ starter_createdat TIMESTAMP NULL,
+ starter_createdby VARCHAR(16),
+ starter_changedat TIMESTAMP NULL,
+ starter_changedby VARCHAR(16),
+ PRIMARY KEY(starter_id)
+);
---
# configuration of the bones backend for configuration:
-created: 2020.11.10 23:47:43
+created: 2020.11.16 18:30:01
author: flutter_bones.module_model.exportSqlBackend()
version: 1.0.0
modules:
---
# configuration of the bones backend for menu:
-created: 2020.11.10 23:47:43
+created: 2020.11.16 18:30:01
author: flutter_bones.module_model.exportSqlBackend()
version: 1.0.0
modules:
sqlInfos:
- name: insert
type: insert
- sql: "INSERT INTO menu(menu_name,menu_icon,menu_createdat,menu_createdby)
- VALUES(:menu_name,:menu_icon,NOW(),:menu_createdby);"
+ sql: "INSERT INTO menu(menu_role,menu_starter,menu_createdat,menu_createdby)
+ VALUES(:menu_role,:menu_starter,NOW(),:menu_createdby);"
- name: update
type: update
sql: "UPDATE menu SET
- menu_name=:menu_name,menu_icon=:menu_icon,menu_changedat=NOW(),menu_changedby=:menu_changedby
+ menu_role=:menu_role,menu_starter=:menu_starter,menu_changedat=NOW(),menu_changedby=:menu_changedby
WHERE menu_id=:menu_id;"
- name: delete
type: delete
- name: record
type: record
sql: "SELECT * from menu WHERE menu_id=:menu_id;"
- - name: by_menu_name
- type: record
- sql: "SELECT * from menu WHERE menu_name=:menu_name&&menu_id!=:excluded;"
- name: list
type: list
- sql: "SELECT t0.*,t1.configuration_property as menu_icon from menu t0
- left join configuration t1 on t1.configuration_id=t0.menu_icon
- WHERE menu_name like :menu_name;"
+ sql: "SELECT t0.*,t1.role_name as menu_role,t2.starter_name as menu_starter from menu t0
+ left join role t1 on t1.role_id=t0.menu_role
+ left join starter t2 on t2.starter_id=t0.menu_starter
+ WHERE menu_role like :menu_role;"
---
# configuration of the bones backend for role:
-created: 2020.11.10 23:47:43
+created: 2020.11.16 18:30:01
author: flutter_bones.module_model.exportSqlBackend()
version: 1.0.0
modules:
--- /dev/null
+---
+# configuration of the bones backend for starter:
+created: 2020.11.16 18:30:01
+author: flutter_bones.module_model.exportSqlBackend()
+version: 1.0.0
+modules:
+ - module: starter
+ sqlInfos:
+ - name: insert
+ type: insert
+ sql: "INSERT INTO starter(starter_name,starter_icon,starter_createdat,starter_createdby)
+ VALUES(:starter_name,:starter_icon,NOW(),:starter_createdby);"
+ - name: update
+ type: update
+ sql: "UPDATE starter SET
+ starter_name=:starter_name,starter_icon=:starter_icon,starter_changedat=NOW(),starter_changedby=:starter_changedby
+ WHERE starter_id=:starter_id;"
+ - name: delete
+ type: delete
+ sql: "DELETE from starter WHERE starter_id=:starter_id;"
+ - name: record
+ type: record
+ sql: "SELECT * from starter WHERE starter_id=:starter_id;"
+ - name: by_starter_name
+ type: record
+ sql: "SELECT * from starter WHERE starter_name=:starter_name&&starter_id!=:excluded;"
+ - name: list
+ type: list
+ sql: "SELECT t0.*,t1.configuration_value as starter_icon from starter t0
+ left join configuration t1 on t1.configuration_id=t0.starter_icon
+ WHERE starter_name like :starter_name;"
---
# configuration of the bones backend for user:
-created: 2020.11.10 23:47:43
+created: 2020.11.16 18:30:01
author: flutter_bones.module_model.exportSqlBackend()
version: 1.0.0
modules:
import 'src/page/user/user_create_page.dart';
import 'src/page/user/user_list_page.dart';
import 'src/page/user/user_login_page.dart';
+import 'src/page/starter/starter_list_page.dart';
+import 'src/page/starter/starter_create_page.dart';
import 'src/private/bsettings.dart';
class BoneApp extends StatefulWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: 'Test Standardseiten',
+ debugShowCheckedModeBanner: true,
+ title: 'Flutter Bones Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
- initialRoute: '/menu/list',
+ initialRoute: '/role/list',
//initialRoute: '/async',
onGenerateRoute: _getRoute,
);
case '/menu/create':
page = MenuCreatePage(BSettings.lastInstance.pageData);
break;
+ case '/starter/list':
+ page = StarterListPage(BSettings.lastInstance.pageData);
+ break;
+ case '/starter/create':
+ page = StarterCreatePage(BSettings.lastInstance.pageData);
+ break;
case '/user/login':
default:
page = UserLoginPage(BSettings.lastInstance.pageData);
export 'src/model/standard/configuration_model.dart';
export 'src/model/standard/menu_model.dart';
export 'src/model/standard/role_model.dart';
-export 'src/model/standard/standard_modules.dart';
export 'src/model/standard/user_model.dart';
export 'src/model/text_field_model.dart';
export 'src/model/text_model.dart';
export 'src/model/widget_model.dart';
export 'src/page/application_data.dart';
export 'src/page/configuration/configuration_create_page.dart';
-export 'src/page/login_page.dart.01';
export 'src/page/role/role_create_page.dart';
export 'src/page/user/user_create_page.dart';
export 'src/page/user_page.dart';
return rc;
}
+ /// Returns null or the index of the first match of a [string]
+ /// or a regular expression defined by [regExp] or a string [pattern].
+ /// Note: exactly one of [string], [regExp] or [pattern] must be not null.
+ static int listIndexOf(List<String> list,
+ {String string, RegExp regExp, String pattern}) {
+ int rc;
+ int ix = -1;
+ if (list != null) {
+ if (string != null) {
+ for (var line in list) {
+ ix++;
+ if (line.contains(string)) {
+ rc = ix;
+ break;
+ }
+ }
+ } else {
+ if (pattern != null) {
+ regExp = RegExp(pattern);
+ }
+ if (regExp != null) {
+ for (var line in list) {
+ ix++;
+ if (regExp.firstMatch(line) != null) {
+ rc = ix;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return rc;
+ }
+
/// Splits a argument list into an [option] list and a true arguments list.
/// [args]: the argument list to split.
/// [options]: OUT: the options list
}
return rc;
}
+
+ /// Converts a [string] to camelCase with an uppercase first character.
+ static String capitalize(String string) {
+ final rc = string[0].toUpperCase() + string.substring(1);
+ return rc;
+ }
}
if (col.hasOption('doStore') ||
(!col.hasOption('hidden') &&
(!isCreatePage || !col.hasOption('primary')))) {
- final field = DbReferenceModel.fromColumn(section, page, col, logger);
- page.addField(field);
- page.widgets.add(field);
+ final model = DbReferenceModel.fromColumn(section, page, col, logger);
+ page.addModel(model);
+ section.children.add(model);
}
});
}
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'module_model.dart';
+import 'standard/role_model.dart';
+import 'standard/user_model.dart';
+import 'standard/menu_model.dart';
+import 'standard/starter_model.dart';
+import 'standard/configuration_model.dart';
+
+class ModelHelper {
+ /// Returns an instance of a module given by [name].
+ ModuleModel moduleByName(String name, BaseLogger logger) {
+ var rc;
+ switch (name) {
+ case 'role':
+ rc = RoleModel(logger);
+ break;
+ case 'user':
+ rc = UserModel(logger);
+ break;
+ case 'configuration':
+ rc = ConfigurationModel(logger);
+ break;
+ case 'menu':
+ rc = MenuModel(logger);
+ break;
+ case 'starter':
+ rc = StarterModel(logger);
+ break;
+ default:
+ logger.error('unknown standard module: $name');
+ break;
+ }
+ return rc;
+ }
+
+ /// Returns the names of the modules.
+ List<String> moduleNames() =>
+ ['configuration', 'menu', 'role', 'starter', 'user'];
+
+}
type: list
sql: "SELECT $select from ${table.name} t0\n$buffer2''');
// @ToDo: joins
- final fields = page.fields
+ final models = page.models.values
.where((item) => item is FieldModel && item.filterType != null);
- if (fields.isEmpty) {
+ if (models.isEmpty) {
buffer.write(' WHERE 1;"');
} else {
buffer.write(' WHERE ');
var first = true;
- for (var field in fields) {
+ for (var item in models) {
+ FieldModel model = item as FieldModel;
if (!first) {
buffer.write(' AND ');
}
- switch (field.filterType) {
+ switch (model.filterType) {
case FilterType.dateFrom:
case FilterType.dateTimeFrom:
- buffer.write('${field.name}>=:${field.name}');
+ buffer.write('${model.name}>=:${model.name}');
break;
case FilterType.dateTil:
case FilterType.dateTimeTil:
- buffer.write('${field.name}<=:${field.name}');
+ buffer.write('${model.name}<=:${model.name}');
break;
case FilterType.equals:
buffer.write(
- '(:${field.name} IS NULL OR ${field.name}=:${field.name})');
+ '(:${model.name} IS NULL OR ${model.name}=:${model.name})');
break;
case FilterType.pattern:
- buffer.write('${field.name} like :${field.name}');
+ buffer.write('${model.name} like :${model.name}');
break;
}
first = false;
final ModuleModel module;
final List<SectionModel> sections = [];
PageModelType pageModelType;
- final fields = <FieldModel>[];
- final buttons = <ButtonModel>[];
- final widgets = <WidgetModel>[];
+ final fieldsDeprecated = <FieldModel>[];
+ final buttonsDeprecated = <ButtonModel>[];
+ final widgetsDeprecated = <WidgetModel>[];
+ final models = <String, WidgetModel>{};
String sql;
+ String title;
List<String> tableTitles;
List<String> tableColumns;
NameBuilder nameBuilder;
nameBuilder = NameBuilder(logger);
}
- /// Adds a [button] to the [this.buttons].
+ /// Adds a [model] to the [this.fields].
/// If already defined and error is logged.
- void addButton(ButtonModel button) {
- if (buttonByName(button.name, required: false) != null) {
- logger.error('button ${button.fullName()} already defined: ' +
- buttonByName(button.name, required: false).fullName());
- } else {
- buttons.add(button);
- }
- }
-
- /// Adds a [field] to the [this.fields].
- /// If already defined and error is logged.
- void addField(FieldModel field) {
- final name = field.name;
- if (hasField(name)) {
- logger.error('field ${field.fullName()} already defined: ' +
+ void addModel(WidgetModel model) {
+ final name = model.name;
+ if (models.containsKey(name)) {
+ logger.error('model ${model.fullName()} already defined: ' +
fieldByName(name).fullName());
} else {
- fields.add(field);
+ models[model.name] = model;
}
}
/// Returns a button named [name] or null if not found.
ButtonModel buttonByName(String name, {bool required = true}) {
- final rc =
- buttons.firstWhere((item) => item.name == name, orElse: () => null);
- if (rc == null && required) {
+ final rc = models.containsKey(name) ? models[name] : null;
+ if ((rc == null || rc.modelType != ModelTypeBones.button) && required) {
logger.error('missing button $name in page ${fullName()}');
}
return rc;
/// Returns a field by [name] or null on error.
FieldModel fieldByName(String name, {bool required = true}) {
- final rc = fields.firstWhere((element) => element.name == name,
- orElse: () => null);
- if (required && rc == null) {
+ final rc = !models.containsKey(name)
+ ? null
+ : (models[name] is FieldModel ? models[name] : null);
+ if ((rc == null || !(rc is FieldModel)) && required) {
logger.error('missing field $name in page ${fullName()}');
}
return rc;
/// If [filter] is none all widgets will be returned.
List<dynamic> getWidgets(FilterWidget filter) {
final rc = filter == null
- ? widgets
- : widgets.fold([], (prevValue, item) {
+ ? sections[0].children
+ : sections[0].children.fold([], (prevValue, item) {
if (filter(item)) {
prevValue.add(item);
}
/// Tests whether the field with [name] is part of the page.
bool hasField(String name) {
- final first = fields.firstWhere((element) => element.name == name,
- orElse: () => null);
- final rc = first != null;
+ final rc = models.containsKey(name) && models[name] is FieldModel;
return rc;
}
}
checkSuperfluousAttributes(
map,
- 'options page pageType sections sql tableColumns tableTitles'
+ 'options page pageType sections sql tableColumns tableTitles title'
.split(' '));
pageModelType = parseEnum<PageModelType>(
'pageType', map, PageModelType.values,
required: true);
+ title = parseString('title', map, required: true);
if (!map.containsKey('sections')) {
logger.error('missing sections in page ${fullName()}');
} else {
}
if (!options.contains('noAutoButton')) {
- final section = null;
+ final section = sections[0];
switch (pageModelType) {
case PageModelType.list:
if (buttonByName('search', required: false) == null) {
- addButton(ButtonModel.direct(section, this, 'search', 'Suchen',
- ButtonModelType.search, [], logger));
+ final model = ButtonModel.direct(section, this, 'search', 'Suchen',
+ ButtonModelType.search, [], logger);
+ addModel(model);
+ sections[0].buttonBar.insert(0, model);
}
break;
case PageModelType.create:
case PageModelType.change:
if (buttonByName('cancel', required: false) == null) {
- addButton(ButtonModel.direct(section, this, 'cancel', 'Abbruch',
- ButtonModelType.cancel, [], logger));
+ final model = ButtonModel.direct(section, this, 'cancel', 'Abbruch',
+ ButtonModelType.cancel, [], logger);
+ addModel(model);
+ sections[0].buttonBar.insert(0, model);
}
if (buttonByName('store', required: false) == null) {
- addButton(ButtonModel.direct(section, this, 'store', 'Speichern',
- ButtonModelType.store, [], logger));
+ final model = ButtonModel.direct(section, this, 'store',
+ 'Speichern', ButtonModelType.store, [], logger);
+ addModel(model);
+ sections[0].buttonBar.insert(0, model);
}
break;
default:
static final regExprOptions = RegExp(r'^(unknown)$');
SectionModelType sectionModelType;
final children = <WidgetModel>[];
- final buttons = <WidgetModel>[];
- final int no;
+ final buttonBar = <WidgetModel>[];
+ final int sectionNo;
- SectionModel(this.no, PageModel page, SectionModel section, BaseLogger logger)
+ SectionModel(
+ this.sectionNo, PageModel page, SectionModel section, BaseLogger logger)
: super(section, page, ModelTypeBones.section, null, logger);
/// Dumps the internal structure into a [stringBuffer]
String fullName() =>
section == null ? '${page.name}.$name' : '${section.name}.$name';
+ WidgetModel buildModel(child, String parentName, int no) {
+ WidgetModel model;
+ if (!ModelBase.isMap(child)) {
+ logger.error('child $no of "children" is not a map in ${fullName()}: '
+ '${StringUtils.limitString(child.toString(), 80)}');
+ } else {
+ if (!child.containsKey('modelType')) {
+ logger.error(
+ 'child $no of "$parentName" does not have "modelType" in ${fullName()}: '
+ '${StringUtils.limitString(child.toString(), 80)}');
+ } else {
+ final modelType = StringUtils.stringToEnum<ModelTypeBones>(
+ child['modelType'].toString(), ModelTypeBones.values);
+ switch (modelType) {
+ case ModelTypeBones.allDbFields:
+ model = AllDbFieldsModel(this, page, logger);
+ break;
+ case ModelTypeBones.checkbox:
+ model = CheckboxModel(this, page, logger);
+ break;
+ case ModelTypeBones.combobox:
+ model = ComboboxModel(this, page, logger);
+ break;
+ case ModelTypeBones.textField:
+ model = TextFieldModel(this, page, logger);
+ break;
+ case ModelTypeBones.button:
+ model = ButtonModel(this, page, logger);
+ break;
+ case ModelTypeBones.text:
+ model = TextModel(this, page, logger);
+ break;
+ case ModelTypeBones.emptyLine:
+ model = EmptyLineModel(this, page, logger);
+ break;
+ case ModelTypeBones.dbReference:
+ model = DbReferenceModel(this, page, logger);
+ break;
+ default:
+ //@ToDo: nested section
+ logger.error(
+ 'Section: unknown "modelType" ${child["modelType"]} in ${fullName()}');
+ break;
+ }
+ if (model != null){
+ model.parse(child);
+ }
+ }
+ }
+ return model;
+ }
+
/// Parses the [map]and stores the data in the instance.
void parse(Map map) {
super.parseBase(map, nameLabel: 'section');
}
sectionModelType = parseEnum<SectionModelType>(
'sectionType', map, SectionModelType.values);
- checkSuperfluousAttributes(map,
- 'children fields modelType section options sectionType'.split(' '));
+ checkSuperfluousAttributes(
+ map,
+ 'buttons children fields modelType section options sectionType'
+ .split(' '));
checkOptionsByRegExpr(regExprOptions);
if (!map.containsKey('children')) {
int no = 0;
for (var child in childrenList) {
no++;
- if (!ModelBase.isMap(child)) {
- logger
- .error('child $no of "children" is not a map in ${fullName()}: '
- '${StringUtils.limitString(child.toString(), 80)}');
- } else {
- if (!child.containsKey('modelType')) {
- logger.error(
- 'child $no of "children" does not have "modelType" in ${fullName()}: '
- '${StringUtils.limitString(child.toString(), 80)}');
- } else {
- final modelType = StringUtils.stringToEnum<ModelTypeBones>(
- child['modelType'].toString(), ModelTypeBones.values);
- WidgetModel widget;
- switch (modelType) {
- case ModelTypeBones.allDbFields:
- widget = AllDbFieldsModel(this, page, logger);
- break;
- case ModelTypeBones.checkbox:
- widget = CheckboxModel(this, page, logger);
- break;
- case ModelTypeBones.combobox:
- widget = ComboboxModel(this, page, logger);
- break;
- case ModelTypeBones.textField:
- widget = TextFieldModel(this, page, logger);
- break;
- case ModelTypeBones.button:
- widget = ButtonModel(this, page, logger);
- break;
- case ModelTypeBones.text:
- widget = TextModel(this, page, logger);
- break;
- case ModelTypeBones.emptyLine:
- widget = EmptyLineModel(this, page, logger);
- break;
- case ModelTypeBones.dbReference:
- widget = DbReferenceModel(this, page, logger);
- break;
- default:
- //@ToDo: nested section
- logger.error(
- 'Section: unknown "modelType" ${child["modelType"]} in ${fullName()}');
- break;
- }
- if (widget != null) {
- children.add(widget);
- widget.parse(child);
- page.widgets.add(widget);
- switch (widget.modelType) {
- case ModelTypeBones.button:
- page.addButton(widget);
- break;
- case ModelTypeBones.textField:
- case ModelTypeBones.combobox:
- case ModelTypeBones.checkbox:
- case ModelTypeBones.dbReference:
- page.addField(widget);
- break;
- default:
- break;
- }
- }
- }
+ WidgetModel widget = buildModel(child, 'children', no);
+ if (widget != null) {
+ children.add(widget);
+ page.addModel(widget);
+ }
+ }
+ }
+ //parseSections(page, this, childrenList, logger);
+ }
+ if (map.containsKey('buttonBar')) {
+ final childrenList = map['buttonBar'];
+ if (!ModelBase.isList(childrenList)) {
+ logger.error('"children" is not a list in ${fullName()}: '
+ '${StringUtils.limitString(childrenList.toString(), 80)}');
+ } else {
+ int no = 0;
+ for (var child in childrenList) {
+ no++;
+ WidgetModel model = buildModel(child, 'buttonBar', no);
+ if (model != null) {
+ buttonBar.add(model);
+ page.addModel(model);
}
}
- //parseSections(page, this, childrenList, logger);
}
+ //parseSections(page, this, childrenList, logger);
}
}
class ConfigurationModel extends ModuleModel {
static final yamlMap = <String, dynamic>{
//
- "module": "configuration",
- "tables": [
+ 'module': 'configuration',
+ 'tables': [
{
// configuration_id | configuration_scope | configuration_property | configuration_order | configuration_type
// | configuration_value | configuration_description
],
'pages': [
{
- "page": "create",
- "pageType": "create",
- "sections": [
+ 'page': 'create',
+ 'title': 'Konfiguration hinzufĂĽgen',
+ 'pageType': 'create',
+ 'sections': [
{
- "sectionType": "simpleForm",
- "children": [
+ 'sectionType': 'simpleForm',
+ 'children': [
{
- 'modelType': "allDbFields",
+ 'modelType': 'allDbFields',
}
]
}
]
},
{
- "page": "change",
- "pageType": "change",
- "sections": [
+ 'page': 'change',
+ 'title': 'Konfiguration ändern',
+ 'pageType': 'change',
+ 'sections': [
{
- "sectionType": "simpleForm",
- "children": [
+ 'sectionType': 'simpleForm',
+ 'children': [
{
- 'modelType': "allDbFields",
+ 'modelType': 'allDbFields',
}
]
}
]
},
{
- "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": [
+ 'page': 'list',
+ 'title': 'Konfiguration',
+ '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",
- "children": [
+ 'sectionType': 'filterPanel',
+ 'children': [
{
- "name": "configuration_scope",
- "label": "Bereich",
- 'modelType': "textField",
- "filterType": "pattern",
- //"options": 'undef',
+ 'name': 'configuration_scope',
+ 'label': 'Bereich',
+ 'modelType': 'textField',
+ 'filterType': 'pattern',
+ //'options': 'undef',
},
{
- "name": "configuration_property",
- "label": "Eigenschaft",
- 'modelType': "textField",
- "filterType": "pattern",
+ 'name': 'configuration_property',
+ 'label': 'Eigenschaft',
+ 'modelType': 'textField',
+ 'filterType': 'pattern',
},
]
}
'options': 'primary',
},
{
- 'column': 'menu_name',
- 'dataType': 'string',
- 'label': 'Name',
- 'size': 64,
- 'options': 'unique notnull',
+ 'column': 'menu_role',
+ 'dataType': 'reference',
+ 'label': 'Rolle',
+ 'foreignKey': 'role.role_id role_name',
+ 'listType': 'dbColumn',
+ 'listOption': 'all.role.list;role_name role_id;',
},
{
- 'column': 'menu_icon',
+ 'column': 'menu_starter',
'dataType': 'reference',
- 'label': 'Bild',
- 'foreignKey': 'configuration.configuration_id configuration_value',
- 'listType': 'configuration',
- 'listOption':
- 'std.scope.icons;configuration_value configuration_id;',
+ 'label': 'Programmpunkt',
+ 'foreignKey': 'starter.starter_id starter_name',
+ 'listType': 'dbColumn',
+ 'listOption': 'all.starter.list;starter_name starter_id;',
},
]
},
'pages': [
{
'page': 'create',
+ 'title': 'StartmenĂĽ hinzufĂĽgen',
'pageType': 'create',
'sections': [
{
},
{
'page': 'change',
+ 'title': 'Startmenü ändern',
'pageType': 'change',
'sections': [
{
},
{
'page': 'list',
+ 'title': 'StartmenĂĽ',
'pageType': 'list',
- 'tableColumns': 'menu_id menu_name menu_icon',
- 'tableTitles': ';Id;Name;Bild',
+ 'tableColumns': 'menu_id menu_role menu_order menu_name',
+ 'tableTitles': ';Id;Rolle;Reihe;Programmpunkt',
'sections': [
{
'sectionType': 'filterPanel',
{
'modelType': 'dbReference',
'filterType': 'pattern',
- 'name': 'menu_name',
- 'column': 'menu_name',
+ 'name': 'menu_role',
+ 'column': 'menu_role',
'toolTip':
- "Filter bezüglich des Namens der anzuzeigenden Einträge: Joker '*' (beliebiger String) ist erlaubt."
+ 'Filter bezüglich der Rolle der anzuzeigenden Einträge.'
},
]
}
import '../module_model.dart';
class RoleModel extends ModuleModel {
+ RoleModel(BaseLogger logger) : super(yamlMap, logger);
+
static final yamlMap = <String, dynamic>{
- "module": "role",
- "tables": [
+ 'module': 'role',
+ 'tables': [
{
'table': 'role',
'columns': [
],
'pages': [
{
- "page": "create",
- "pageType": "create",
- "sections": [
+ 'page': 'create',
+ 'title': 'Rolle hinzufĂĽgen',
+ 'pageType': 'create',
+ 'sections': [
{
- "sectionType": "simpleForm",
- "children": [
+ 'sectionType': 'simpleForm',
+ 'children': [
{
- 'modelType': "allDbFields",
+ 'modelType': 'allDbFields',
}
]
}
]
},
{
- "page": "change",
- "pageType": "change",
- "sections": [
+ 'page': 'change',
+ 'title': 'Rolle ändern',
+ 'pageType': 'change',
+ 'sections': [
{
- "sectionType": "simpleForm",
- "children": [
+ 'sectionType': 'simpleForm',
+ 'children': [
{
- 'modelType': "allDbFields",
+ 'modelType': 'allDbFields',
}
]
}
]
},
{
- "page": "list",
- "pageType": "list",
- "tableColumns": "role_id role_name role_priority",
- "tableTitles": ";Id;Rolle;Priorität",
- "sections": [
+ 'page': 'list',
+ 'title': 'Rollen',
+ 'pageType': 'list',
+ 'tableColumns': 'role_id role_name role_priority',
+ 'tableTitles': ';Id;Rolle;Priorität',
+ 'sections': [
{
- "sectionType": "filterPanel",
- "children": [
+ 'sectionType': 'filterPanel',
+ 'children': [
{
- 'modelType': "textField",
- "filterType": "pattern",
- "name": "role_name",
- "label": "Name",
- "toolTip":
- "Suchmuster des Rollennamens: Joker: '*' (beliebiger Text), z.B. '*min*'"
- }
- ]
+ 'modelType': 'textField',
+ 'filterType': 'pattern',
+ 'name': 'role_name',
+ 'label': 'Name',
+ 'toolTip':
+ 'Suchmuster des Rollennamens: Joker: "*" (beliebiger Text), z.B. "*min*"'
+ },
+ ],
+ 'buttonBar': [
+ {
+ 'modelType': 'button',
+ 'buttonType': 'custom',
+ 'name': 'new',
+ 'label': 'Neue Rolle',
+ 'toolTip': 'Erzeugen einer neuen Rolle'
+ },
+ ],
}
- ]
- },
- ],
+ ],
+ }
+ ]
};
- RoleModel(BaseLogger logger) : super(yamlMap, logger);
-
/// Returns the name including the names of the parent
@override
String fullName() => name;
+++ /dev/null
-import 'package:dart_bones/dart_bones.dart';
-import '../module_model.dart';
-import 'role_model.dart';
-import 'user_model.dart';
-import 'menu_model.dart';
-import 'configuration_model.dart';
-
-/// Returns an instance of a standard module given by [name].
-ModuleModel standardModule(String name, BaseLogger logger) {
- var rc;
- switch (name) {
- case 'role':
- rc = RoleModel(logger);
- break;
- case 'user':
- rc = UserModel(logger);
- break;
- case 'configuration':
- rc = ConfigurationModel(logger);
- break;
- case 'menu':
- rc = MenuModel(logger);
- break;
- default:
- logger.error('unknown standard module: $name');
- break;
- }
- return rc;
-}
-
-/// Returns the names of the standard modules.
-List<String> standardModules() => ['configuration', 'menu', 'role', 'user'];
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+
+import '../module_model.dart';
+
+class StarterModel extends ModuleModel {
+ static final mapStarter = <String, dynamic>{
+ 'module': 'starter',
+ 'tables': [
+ {
+ 'table': 'starter',
+ 'columns': [
+ {
+ 'column': 'starter_id',
+ 'dataType': 'int',
+ 'label': 'Id',
+ 'options': 'primary',
+ },
+ {
+ 'column': 'starter_name',
+ 'dataType': 'string',
+ 'label': 'Name',
+ 'size': 64,
+ 'options': 'unique notnull',
+ },
+ {
+ 'column': 'starter_icon',
+ 'dataType': 'reference',
+ 'label': 'Bild',
+ 'foreignKey': 'configuration.configuration_id configuration_value',
+ 'listType': 'configuration',
+ 'listOption':
+ 'std.scope.icons;configuration_value configuration_id;',
+ },
+ ]
+ },
+ ],
+ 'pages': [
+ {
+ 'page': 'create',
+ 'title': 'Programmpunkt hinzufĂĽgen',
+ 'pageType': 'create',
+ 'sections': [
+ {
+ 'sectionType': 'simpleForm',
+ 'children': [
+ {
+ 'modelType': 'allDbFields',
+ }
+ ]
+ }
+ ]
+ },
+ {
+ 'page': 'change',
+ 'title': 'Programmpunkt hinzufĂĽgen',
+ 'pageType': 'change',
+ 'sections': [
+ {
+ 'sectionType': 'simpleForm',
+ 'children': [
+ {
+ 'modelType': 'allDbFields',
+ },
+ ]
+ }
+ ]
+ },
+ {
+ 'page': 'list',
+ 'title': 'Programmpunkte',
+ 'pageType': 'list',
+ 'tableColumns': 'starter_id starter_name starter_icon',
+ 'tableTitles': ';Id;Name;Bild',
+ 'sections': [
+ {
+ 'sectionType': 'filterPanel',
+ 'children': [
+ {
+ 'modelType': 'dbReference',
+ 'filterType': 'pattern',
+ 'name': 'starter_name',
+ 'column': 'starter_name',
+ 'toolTip':
+ 'Filter bezüglich des Namens der anzuzeigenden Einträge: Joker "*" (beliebiger String) ist erlaubt.'
+ },
+ ]
+ }
+ ]
+ },
+ ]
+ };
+
+ StarterModel(BaseLogger logger) : super(mapStarter, logger);
+
+ /// Returns the name including the names of the parent
+ @override
+ String fullName() => name;
+
+ @override
+ String widgetName() => name;
+}
class UserModel extends ModuleModel {
static final mapUser = <String, dynamic>{
- "module": "user",
- "tables": [
+ 'module': 'user',
+ 'tables': [
{
'table': 'user',
'columns': [
'dataType': 'reference',
'label': 'Rolle',
'foreignKey': 'role.role_id role_name',
- "listType": "dbColumn",
- "listOption": "all.role.list;role_name role_id;:role_name=%",
- "options": "undef",
- "defaultValue": "4",
+ 'listType': 'dbColumn',
+ 'listOption': 'all.role.list;role_name role_id;:role_name=%',
+ 'options': 'undef',
+ 'defaultValue': '4',
},
]
},
],
'pages': [
{
- "page": "create",
- "pageType": "create",
- "sections": [
+ 'page': 'create',
+ 'title': 'Benutzer hinzufĂĽgen',
+ 'pageType': 'create',
+ 'sections': [
{
- "sectionType": "simpleForm",
- "children": [
+ 'sectionType': 'simpleForm',
+ 'children': [
{
- 'modelType': "allDbFields",
+ 'modelType': 'allDbFields',
}
]
}
]
},
{
- "page": "change",
- "pageType": "change",
- "sections": [
+ 'page': 'change',
+ 'title': 'Benutzer ändern',
+ 'pageType': 'change',
+ 'sections': [
{
- "sectionType": "simpleForm",
- "children": [
+ 'sectionType': 'simpleForm',
+ 'children': [
{
- 'modelType': "allDbFields",
+ 'modelType': 'allDbFields',
},
{
- 'modelType': "button",
- "name": "set_password",
- "label": "Passwort ändern",
- "buttonType": "custom",
+ 'modelType': 'button',
+ 'name': 'set_password',
+ 'label': 'Passwort ändern',
+ 'buttonType': 'custom',
},
]
}
]
},
{
- "page": "password",
- "pageType": "change",
- "sql": "update_pw",
- "sections": [
+ 'page': 'password',
+ 'title': 'Passwort ändern',
+ 'pageType': 'change',
+ 'sql': 'update_pw',
+ 'sections': [
{
- "sectionType": "simpleForm",
- "children": [
+ 'sectionType': 'simpleForm',
+ 'children': [
{
- 'modelType': "text",
- "text": "Ă„ndern des Passworts von Benutzer ~user~",
- "options": "placeholder h3"
+ 'modelType': 'text',
+ 'text': 'Ă„ndern des Passworts von Benutzer ~user~',
+ 'options': 'placeholder h3'
},
{
- 'modelType': "textField",
- "name": "user_password",
- "label": "Passwort",
- "options": "password",
- "validators": "required",
+ 'modelType': 'textField',
+ 'name': 'user_password',
+ 'label': 'Passwort',
+ 'options': 'password',
+ 'validators': 'required',
},
{
- 'modelType': "textField",
- "name": "repetition",
- "label": "Wiederholung",
- "options": "password",
- "validators": "required equals=user_password"
+ 'modelType': 'textField',
+ 'name': 'repetition',
+ 'label': 'Wiederholung',
+ 'options': 'password',
+ 'validators': 'required equals=user_password'
},
]
}
]
},
{
- "page": "list",
- "pageType": "list",
- "tableColumns":
- "user_id user_name user_displayname user_email user_role",
- "tableTitles": ";Id;Name;Anzeigename;EMail;Rolle",
- "sections": [
+ 'page': 'list',
+ 'title': 'Benutzer',
+ 'pageType': 'list',
+ 'tableColumns':
+ 'user_id user_name user_displayname user_email user_role',
+ 'tableTitles': ';Id;Name;Anzeigename;EMail;Rolle',
+ 'sections': [
{
- "sectionType": "filterPanel",
- "children": [
+ 'sectionType': 'filterPanel',
+ 'children': [
{
- 'modelType': "dbReference",
- "filterType": "pattern",
- "name": "user_name",
- "column": "user_name",
- "toolTip":
- "Filter bezüglich des Namens der anzuzeigenden Einträge: Joker '*' (beliebiger String) ist erlaubt."
+ 'modelType': 'dbReference',
+ 'filterType': 'pattern',
+ 'name': 'user_name',
+ 'column': 'user_name',
+ 'toolTip':
+ 'Filter bezüglich des Namens der anzuzeigenden Einträge: Joker "*" (beliebiger String) ist erlaubt.'
},
{
- 'modelType': "dbReference",
- "name": "user_role",
- "filterType": "equals",
- "column": "user_role",
- "toolTip":
- "Filter bezüglich der Rolle der anzuzeigenden Einträge. '-' bedeutet keine Einschränkung",
+ 'modelType': 'dbReference',
+ 'name': 'user_role',
+ 'filterType': 'equals',
+ 'column': 'user_role',
+ 'toolTip':
+ 'Filter bezüglich der Rolle der anzuzeigenden Einträge. "-" bedeutet keine Einschränkung',
}
]
}
]
},
{
- "page": "login",
- "pageType": "change",
- "options": "noAutoButton",
- "sections": [
+ 'page': 'login',
+ 'title': 'Anmelden',
+ 'pageType': 'change',
+ 'options': 'noAutoButton',
+ 'sections': [
{
- "sectionType": "simpleForm",
- "children": [
+ 'sectionType': 'simpleForm',
+ 'children': [
{
- 'modelType': "textField",
- "name": "user",
- "label": "Benutzer oder EMail",
- "validators": "required",
+ 'modelType': 'textField',
+ 'name': 'user',
+ 'label': 'Benutzer oder EMail',
+ 'validators': 'required',
},
{
- 'modelType': "textField",
- "name": "password",
- "label": "Password",
- "options": "password",
- "validators": "required",
+ 'modelType': 'textField',
+ 'name': 'password',
+ 'label': 'Password',
+ 'options': 'password',
+ 'validators': 'required',
},
{
- 'modelType': "button",
- "buttonType": "custom",
- "name": "login",
- "label": "Anmelden",
+ 'modelType': 'button',
+ 'buttonType': 'custom',
+ 'name': 'login',
+ 'label': 'Anmelden',
},
]
}
import '../persistence/persistence_cache.dart';
import '../widget/page_controller_bones.dart';
+abstract class FooterBones {
+ List<Widget> widgets(PageControllerBones controller);
+}
+
/// 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 FooterBones Function() footerBuilder;
final Persistence persistence;
PersistenceCache persistenceCache;
int currentUserId;
/// 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"
+ /// [footerBuilder] is a factory of a function returning a footer area (as one widget)
+ ///
ApplicationData(this.configuration, this.appBarBuilder, this.drawerBuilder,
- this.persistence, this.logger) {
+ this.footerBuilder, this.persistence, this.logger) {
currentUserId = 0;
currentUserName = 'Gast';
currentRoleId = 0;
import 'package:flutter/material.dart';
import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_markdown/flutter_markdown.dart';
class DemoPage extends StatefulWidget {
final ApplicationData pageData;
final items = texts
.map((text) => DropdownMenuItem<String>(value: text, child: Text(text)))
.toList();
- return Scaffold(
- appBar: pageData.appBarBuilder('Demo'),
- drawer: pageData.drawerBuilder(context),
- body: SimpleForm.simpleForm(
- key: _formKey,
- configuration: pageData.configuration,
- fields: <Widget>[
- TextFormField(
- validator: checkNotEmpty,
- decoration: InputDecoration(labelText: 'Name'),
- onSaved: (input) => item.name = input,
- ),
- DropdownButtonFormField<String>(
- value: 'two',
- items: items,
- decoration: InputDecoration(labelText: 'Number'),
- onChanged: (value) => item.number = value,
- ),
- ],
- buttons: <Widget>[
- RaisedButton(
- onPressed: () => login(context),
- child: Text('Anmelden'),
- ),
- ],
- ));
+ const String _markdownData = """
+# Minimal Markdown Test
+---
+This is a simple Markdown test. Provide a text string with Markdown tags
+to the Markdown widget and it will display the formatted output in a
+scrollable widget.
+
+## Section 1
+Maecenas eget **arcu egestas**, mollis ex vitae, posuere magna. Nunc eget
+aliquam tortor. Vestibulum porta sodales efficitur. Mauris interdum turpis
+eget est condimentum, vitae porttitor diam ornare.
+
+### Subsection A
+Sed et massa finibus, blandit massa vel, vulputate velit. Vestibulum vitae
+venenatis libero. **__Curabitur sem lectus, feugiat eu justo in, eleifend
+accumsan ante.__** Sed a fermentum elit. Curabitur sodales metus id mi
+ornare, in ullamcorper magna congue.
+""";
+ if ('a'.startsWith('a')) {
+ return Scaffold(
+ appBar: pageData.appBarBuilder('Demo'),
+ drawer: pageData.drawerBuilder(context),
+ body: SafeArea(child: Markdown(data: _markdownData)));
+ } else {
+ return Scaffold(
+ appBar: pageData.appBarBuilder('Demo'),
+ drawer: pageData.drawerBuilder(context),
+ body: SimpleForm.simpleForm(
+ key: _formKey,
+ configuration: pageData.configuration,
+ intro: [Markdown(data: _markdownData)],
+ fields: <Widget>[
+ TextFormField(
+ validator: checkNotEmpty,
+ decoration: InputDecoration(labelText: 'Name'),
+ onSaved: (input) => item.name = input,
+ ),
+ DropdownButtonFormField<String>(
+ value: 'two',
+ items: items,
+ decoration: InputDecoration(labelText: 'Number'),
+ onChanged: (value) => item.number = value,
+ ),
+ ],
+ buttons: <Widget>[
+ RaisedButton(
+ onPressed: () => login(context),
+ child: Text('Anmelden'),
+ ),
+ ],
+ ));
+ }
}
void login(context) async {
import 'package:dart_bones/dart_bones.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_bones/src/page/starter/starter_list_page.dart';
import '../application_data.dart';
import '../configuration/configuration_list_page.dart';
rc = UserPasswordPage(applicationData.currentUserId,
applicationData.currentUserName, applicationData, null);
break;
+ case 'starter.list':
+ rc = StarterListPage(applicationData);
+ break;
case 'demo':
rc = DemoPage(applicationData);
break;
case 'construction_outlined':
rc = Icons.construction_outlined;
break;
+ case 'radio_button_checked_outlined':
+ rc = Icons.radio_button_checked_outlined;
+ break;
default:
logger.error('MenuConverter.iconByName(): unknown icon $name');
break;
import 'package:flutter/material.dart';
+
import '../../helper/settings.dart';
import '../../widget/edit_form.dart';
import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
import 'role_controller.dart';
+//! === BeginOfGeneratedCode: Change only in areas marked as customized
+//! pageType: change
+
class RoleChangePage extends StatefulWidget {
final ApplicationData applicationData;
final Map initialRow;
final logger = Settings().logger;
final int primaryId;
- //RoleChangePageState lastState;
-
+ //! === BeginOfCustomizedVars1 ===
+ //! === EndOfCustomizedVars1 ===
+ //! === BeginOfConstructor1 ===
RoleChangePage(this.primaryId, this.applicationData, this.initialRow,
{Key key})
: super(key: key);
+ //! === EndOfConstructor1 ===
+
@override
RoleChangePageState createState() {
- final rc = RoleChangePageState(primaryId, applicationData, initialRow);
+ //! === BeginOfCall ===
+ final rc =
+ RoleChangePageStateCustomized(primaryId, applicationData, initialRow);
+ //! === EndOfCall ===
/// for unittests:
applicationData.lastModuleState = rc;
}
}
-class RoleChangePageState extends State<RoleChangePage> implements RedrawPage {
+abstract class RoleChangePageState extends State<RoleChangePage>
+ implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final Map initialRow;
final GlobalKey<FormState> _formKey =
- GlobalKey<FormState>(debugLabel: 'role_change');
+ GlobalKey<FormState>(debugLabel: 'role_change');
RoleController controller;
+ //! === BeginOfCustomizedVars2 ===
+ //! === EndOfCustomizedVars2 ===
+ //! === BeginOfConstructor2 ===
RoleChangePageState(this.primaryId, this.applicationData, this.initialRow);
+ //! === EndOfConstructor2 ===
+
@override
Widget build(BuildContext context) {
controller.beginOfBuild(context);
+ //! === BeginOfScaffold ===
return Scaffold(
- appBar: applicationData.appBarBuilder('Rolle ändern'),
+ appBar: applicationData.appBarBuilder(controller.page.title),
drawer: applicationData.drawerBuilder(context),
+ persistentFooterButtons:
+ applicationData.footerBuilder().widgets(controller),
body: EditForm.editForm(
key: _formKey,
pageController: controller,
primaryId: primaryId,
initialRow: initialRow,
));
+ //! === EndOfScaffold ===
+ }
+
+ /// Customize the page, e.g. modify the default widget list given by the model
+ void customize();
+
+ void dispose() {
+ controller.dispose();
+ super.dispose();
}
@override
controller =
RoleController(_formKey, this, 'change', context, applicationData);
controller.initialize();
+ customize();
}
@override
customString: customString, callback: callback);
});
}
+}
- void dispose() {
- controller.dispose();
- super.dispose();
+//! === EndOfGeneratedCode: Below you can change manually:
+
+class RoleChangePageStateCustomized extends RoleChangePageState {
+ RoleChangePageStateCustomized(int primaryId, ApplicationData applicationData,
+ Map initialRow)
+ : super(primaryId, applicationData, initialRow);
+
+ @override
+ void customize() {
+ // ToDo: write code if needed
}
}
import '../application_data.dart';
import 'role_controller.dart';
+//! === BeginOfGeneratedCode: Change only in areas marked as customized
+//! pageType: change
+
class RoleCreatePage extends StatefulWidget {
final ApplicationData applicationData;
final logger = Settings().logger;
+ //! === BeginOfCustomizedVars1 ===
+ //! === EndOfCustomizedVars1 ===
+ //! === BeginOfConstructor1 ===
RoleCreatePage(this.applicationData, {Key key}) : super(key: key);
+ //! === EndOfConstructor1 ===
+
@override
RoleCreatePageState createState() {
- final rc = RoleCreatePageState(applicationData);
+ //! === BeginOfCall ===
+ final rc = RoleCreatePageStateCustomized(applicationData);
+ //! === EndOfCall ===
/// for unittests:
applicationData.lastModuleState = rc;
}
}
-class RoleCreatePageState extends State<RoleCreatePage> implements RedrawPage {
+abstract class RoleCreatePageState extends State<RoleCreatePage>
+ implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
RoleController controller;
+ //! === BeginOfCustomizedVars2 ===
+ //! === EndOfCustomizedVars2 ===
+ //! === BeginOfConstructor2 ===
RoleCreatePageState(this.applicationData);
+ //! === EndOfConstructor2 ===
+
@override
Widget build(BuildContext context) {
controller?.beginOfBuild(context);
+ //! === BeginOfScaffold ===
return Scaffold(
- appBar: applicationData.appBarBuilder('Neue Rolle'),
+ appBar: applicationData.appBarBuilder(controller.page.title),
drawer: applicationData.drawerBuilder(context),
+ persistentFooterButtons:
+ applicationData.footerBuilder().widgets(controller),
body: EditForm.editForm(
key: _formKey,
pageController: controller,
configuration: applicationData.configuration,
));
+ //! === EndOfScaffold ===
}
+ /// Customize the page, e.g. modify the default widget list given by the model
+ void customize();
+
@override
void initState() {
super.initState();
controller =
RoleController(_formKey, this, 'create', context, applicationData);
controller.initialize();
+ customize();
}
@override
});
}
}
+
+//! === EndOfGeneratedCode: Below you can change manually:
+
+class RoleCreatePageStateCustomized extends RoleCreatePageState {
+ RoleCreatePageStateCustomized(ApplicationData applicationData)
+ : super(applicationData);
+
+ @override
+ void customize() {
+ // ToDo: write code if needed
+ }
+}
import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
import '../../model/page_model.dart';
import '../../widget/list_form.dart';
import '../application_data.dart';
import 'role_controller.dart';
+//! === BeginOfGeneratedCode: Change only in areas marked as customized
+//! pageType: change
+
class RoleListPage extends StatefulWidget {
final ApplicationData applicationData;
+ //! === BeginOfCustomizedVars1 ===
+ //! === EndOfCustomizedVars1 ===
+ //! === BeginOfConstructor1 ===
RoleListPage(this.applicationData, {Key key}) : super(key: key);
+ //! === EndOfConstructor1 ===
+
@override
RoleListPageState createState() {
- // RoleListPageState.setPageData(pageData);
- final rc = RoleListPageState(applicationData);
+ //! === BeginOfCall ===
+ final rc = RoleListPageStateCustomized(applicationData);
+ //! === EndOfCall ===
/// for unittests:
applicationData.lastModuleState = rc;
}
}
-class RoleListPageState extends State<RoleListPage> implements RedrawPage {
+abstract class RoleListPageState extends State<RoleListPage>
+ implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
Iterable<dynamic> rowsDeprecated;
RoleController controller;
+ //! === BeginOfCustomizedVars2 ===
+ //! === EndOfCustomizedVars2 ===
+ //! === BeginOfConstructor2 ===
RoleListPageState(this.applicationData);
+ //! === EndOfConstructor2 ===
+
@override
Widget build(BuildContext context) {
controller.beginOfBuild(context);
+
+ //! === BeginOfScaffold ===
return Scaffold(
- appBar: applicationData.appBarBuilder('Rollen'),
+ appBar: applicationData.appBarBuilder(controller.page.title),
drawer: applicationData.drawerBuilder(context),
+ persistentFooterButtons:
+ applicationData.footerBuilder().widgets(controller),
body: ListForm.listForm(
key: _formKey,
configuration: applicationData.configuration,
showEditIcon: true,
pageController: controller,
buttons: <Widget>[
- ButtonBar(alignment: MainAxisAlignment.center, children: [
- controller.searchButton(),
- RaisedButton(
- child: Text('Neue Rolle'),
- onPressed: () {
- controller.goTo(pageType: PageModelType.create);
- },
- ),
- ]),
- ],
+ ButtonBar(alignment: MainAxisAlignment.center,
+ children: View().modelsToWidgets(controller.page.sections[0].buttonBar, controller),
+ )],
filters: controller.modelList,
errorMessage:
applicationData.lastErrorMessage(controller.page.fullName()),
),
);
+ //! === EndOfScaffold ===
}
+ /// Customize the page, e.g. modify the default widget list given by the model
+ void customize();
+
@override
void initState() {
super.initState();
controller =
RoleController(_formKey, this, 'list', context, applicationData);
controller.initialize();
+ customize();
}
@override
});
}
}
+
+//! === EndOfGeneratedCode: Below you can change manually:
+
+class RoleListPageStateCustomized extends RoleListPageState {
+ RoleListPageStateCustomized(ApplicationData applicationData)
+ : super(applicationData);
+
+ @override
+ void customize() {
+ final button = controller.page.buttonByName('new');
+ button.onPressed = () {
+ controller.goTo(pageType: PageModelType.create);
+ };
+ controller.modelList.addModel(button.name, button);
+ }
+}
--- /dev/null
+import 'package:flutter/material.dart';
+
+import '../../helper/settings.dart';
+import '../../widget/edit_form.dart';
+import '../../widget/page_controller_bones.dart';
+import '../application_data.dart';
+import 'starter_controller.dart';
+
+class StarterChangePage extends StatefulWidget {
+ final ApplicationData applicationData;
+ final Map initialRow;
+ final logger = Settings().logger;
+ final int primaryId;
+
+ //StarterChangePageState lastState;
+
+ StarterChangePage(this.primaryId, this.applicationData, this.initialRow,
+ {Key key})
+ : super(key: key);
+
+ @override
+ StarterChangePageState createState() {
+ final rc = StarterChangePageState(primaryId, applicationData, initialRow);
+
+ /// for unittests:
+ applicationData.lastModuleState = rc;
+ return rc;
+ }
+}
+
+class StarterChangePageState extends State<StarterChangePage>
+ implements RedrawPage {
+ final ApplicationData applicationData;
+ final int primaryId;
+ final Map initialRow;
+ final GlobalKey<FormState> _formKey =
+ GlobalKey<FormState>(debugLabel: 'starter_change');
+
+ StarterController controller;
+
+ StarterChangePageState(this.primaryId, this.applicationData, this.initialRow);
+
+ @override
+ Widget build(BuildContext context) {
+ controller.beginOfBuild(context);
+ // controller.buildWidgetList() is called in editForm
+ return Scaffold(
+ appBar: applicationData.appBarBuilder('Startmenü ändern'),
+ drawer: applicationData.drawerBuilder(context),
+ body: EditForm.editForm(
+ key: _formKey,
+ pageController: controller,
+ configuration: applicationData.configuration,
+ primaryId: primaryId,
+ initialRow: initialRow,
+ ));
+ }
+
+ void dispose() {
+ controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ controller = StarterController(
+ _formKey,
+ this,
+ 'change',
+ context,
+ applicationData,
+ );
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
+}
--- /dev/null
+import 'package:flutter/material.dart';
+
+import '../../helper/settings.dart';
+import '../../model/standard/starter_model.dart';
+import '../../widget/page_controller_bones.dart';
+import '../application_data.dart';
+import 'starter_change_page.dart';
+
+class StarterController extends PageControllerBones {
+ /// Controller for a page named [pageName].
+ StarterController(GlobalKey<FormState> formKey, RedrawPage parent,
+ String pageName, BuildContext context, ApplicationData applicationData,
+ {Function redrawCallback})
+ : super(formKey, parent, StarterModel(Settings().logger), pageName,
+ context, applicationData, redrawCallback) {
+ moduleModel.parse();
+ }
+ @override
+ void startChange(int id, Map row) {
+ applicationData.pushCaller(this);
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => StarterChangePage(id, applicationData, row)));
+ }
+}
--- /dev/null
+import 'package:flutter/material.dart';
+
+import '../../helper/settings.dart';
+import '../../widget/edit_form.dart';
+import '../../widget/page_controller_bones.dart';
+import '../application_data.dart';
+import 'starter_controller.dart';
+
+class StarterCreatePage extends StatefulWidget {
+ final ApplicationData applicationData;
+ final logger = Settings().logger;
+
+ StarterCreatePage(this.applicationData, {Key key}) : super(key: key);
+
+ @override
+ StarterCreatePageState createState() {
+ final rc = StarterCreatePageState(applicationData);
+
+ /// for unittests:
+ applicationData.lastModuleState = rc;
+ return rc;
+ }
+}
+
+class StarterCreatePageState extends State<StarterCreatePage>
+ implements RedrawPage {
+ final ApplicationData applicationData;
+
+ final GlobalKey<FormState> _formKey =
+ GlobalKey<FormState>(debugLabel: 'starter_create');
+
+ StarterController controller;
+
+ StarterCreatePageState(this.applicationData);
+
+ @override
+ Widget build(BuildContext context) {
+ controller.beginOfBuild(context);
+ return Scaffold(
+ appBar: applicationData.appBarBuilder('Neues StartmenĂĽ'),
+ drawer: applicationData.drawerBuilder(context),
+ body: EditForm.editForm(
+ key: _formKey,
+ pageController: controller,
+ configuration: applicationData.configuration,
+ ));
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ StarterController(_formKey, this, 'create', context, applicationData);
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
+}
--- /dev/null
+import 'package:flutter/material.dart';
+
+import '../../model/page_model.dart';
+import '../../widget/list_form.dart';
+import '../../widget/page_controller_bones.dart';
+import '../application_data.dart';
+import 'starter_controller.dart';
+
+class StarterListPage extends StatefulWidget {
+ final ApplicationData applicationData;
+
+ StarterListPage(this.applicationData, {Key key}) : super(key: key);
+
+ @override
+ StarterListPageState createState() {
+ // StarterListPageState.setPageData(pageData);
+ final rc = StarterListPageState(applicationData);
+
+ /// for unittests:
+ applicationData.lastModuleState = rc;
+ return rc;
+ }
+}
+
+class StarterListPageState extends State<StarterListPage>
+ implements RedrawPage {
+ final ApplicationData applicationData;
+
+ final GlobalKey<FormState> _formKey =
+ GlobalKey<FormState>(debugLabel: 'starter_list');
+ Iterable<dynamic> rowsDeprecated;
+ StarterController controller;
+
+ StarterListPageState(this.applicationData);
+
+ @override
+ Widget build(BuildContext context) {
+ controller.beginOfBuild(context);
+ return Scaffold(
+ appBar: applicationData.appBarBuilder('Programmpunkte'),
+ drawer: applicationData.drawerBuilder(context),
+ body: ListForm.listForm(
+ key: _formKey,
+ configuration: applicationData.configuration,
+ titles: ListForm.stringsToTitles(controller.page.tableTitles),
+ columnNames: controller.page.tableColumns ?? [],
+ rows: controller.listRows ?? [],
+ showEditIcon: true,
+ pageController: controller,
+ buttons: <Widget>[
+ ButtonBar(alignment: MainAxisAlignment.center, children: [
+ controller.searchButton(),
+ RaisedButton(
+ child: Text('Neuer Programmpunkt'),
+ onPressed: () {
+ controller.goTo(pageType: PageModelType.create);
+ },
+ ),
+ ]),
+ ],
+ filters: controller.modelList,
+ errorMessage:
+ applicationData.lastErrorMessage(controller.page.fullName()),
+ ),
+ persistentFooterButtons:
+ applicationData.footerBuilder().widgets(controller));
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ StarterController(_formKey, this, 'list', context, applicationData);
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
+}
import 'user_controller.dart';
import 'user_password_page.dart';
+//! === BeginOfGeneratedCode: Below you can change manually:
+//! pageType: change
+
class UserChangePage extends StatefulWidget {
final ApplicationData applicationData;
final Map initialRow;
final logger = Settings().logger;
final int primaryId;
- //UserChangePageState lastState;
-
+ //! === BeginOfCustomizedVars1 ===
+ //! === EndOfCustomizedVars1 ===
+ //! === BeginOfConstructor1 ===
UserChangePage(this.primaryId, this.applicationData, this.initialRow,
{Key key})
: super(key: key);
+ //! === EndOfConstructor1 ===
+
@override
UserChangePageState createState() {
- final rc = UserChangePageState(primaryId, applicationData, initialRow);
+ //! === BeginOfCall ===
+ final rc =
+ UserChangePageStateCustomized(primaryId, applicationData, initialRow);
+ //! === EndOfCall ===
/// for unittests:
applicationData.lastModuleState = rc;
}
}
-class UserChangePageState extends State<UserChangePage> implements RedrawPage {
+abstract class UserChangePageState extends State<UserChangePage>
+ implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final Map initialRow;
final GlobalKey<FormState> _formKey =
- GlobalKey<FormState>(debugLabel: 'user_change');
+ GlobalKey<FormState>(debugLabel: 'user_change');
UserController controller;
+ //! === BeginOfCustomizedVars2 ===
+ //! === EndOfCustomizedVars2 ===
+ //! === BeginOfConstructor2 ===
UserChangePageState(this.primaryId, this.applicationData, this.initialRow);
+ //! === EndOfConstructor2 ===
+
@override
Widget build(BuildContext context) {
controller.beginOfBuild(context);
+ //! === BeginOfScaffold ===
return Scaffold(
- appBar: applicationData.appBarBuilder('Benutzer ändern'),
+ appBar: applicationData.appBarBuilder(controller.page.title),
drawer: applicationData.drawerBuilder(context),
+ persistentFooterButtons:
+ applicationData.footerBuilder().widgets(controller),
body: EditForm.editForm(
key: _formKey,
pageController: controller,
primaryId: primaryId,
initialRow: initialRow,
));
+ //! === EndOfScaffold ===
}
- void customize() {
- ButtonModel button = controller.page.buttonByName('set_password');
- button?.onPressed = () {
- String userName = controller.page.fieldByName('user_name').value;
- applicationData.pushCaller(controller);
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => UserPasswordPage(
- primaryId, userName, applicationData, null)));
- };
- }
+ /// Customize the page, e.g. modify the default widget list given by the model
+ void customize();
void dispose() {
controller.dispose();
});
}
}
+
+//! === EndOfGeneratedCode: Below you can change manually:
+
+class UserChangePageStateCustomized extends UserChangePageState {
+ UserChangePageStateCustomized(int primaryId, ApplicationData applicationData,
+ Map initialRow)
+ : super(primaryId, applicationData, initialRow);
+
+ @override
+ void customize() {
+ ButtonModel button = controller.page.buttonByName('set_password');
+ button?.onPressed = () {
+ String userName = controller.page.fieldByName('user_name').value;
+ applicationData.pushCaller(controller);
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => UserPasswordPage(
+ primaryId, userName, applicationData, null)));
+ };
+ }
+}
import '../application_data.dart';
import 'user_controller.dart';
+//! === BeginOfGeneratedCode: Below you can change manually:
+//! pageType: change
+
class UserCreatePage extends StatefulWidget {
final ApplicationData applicationData;
final logger = Settings().logger;
+ //! === BeginOfCustomizedVars1 ===
+ //! === EndOfCustomizedVars1 ===
+ //! === BeginOfConstructor1 ===
UserCreatePage(this.applicationData, {Key key}) : super(key: key);
+ //! === EndOfConstructor1 ===
+
@override
UserCreatePageState createState() {
- final rc = UserCreatePageState(applicationData);
+ //! === BeginOfCall ===
+ final rc = UserCreatePageStateCustomized(applicationData);
+ //! === EndOfCall ===
/// for unittests:
applicationData.lastModuleState = rc;
}
}
-class UserCreatePageState extends State<UserCreatePage> implements RedrawPage {
+abstract class UserCreatePageState extends State<UserCreatePage>
+ implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
UserController controller;
+ //! === BeginOfCustomizedVars2 ===
+ //! === EndOfCustomizedVars2 ===
+ //! === BeginOfConstructor2 ===
UserCreatePageState(this.applicationData);
+ //! === EndOfConstructor2 ===
+
@override
Widget build(BuildContext context) {
- controller.beginOfBuild(context);
+ controller?.beginOfBuild(context);
+ //! === BeginOfScaffold ===
return Scaffold(
- appBar: applicationData.appBarBuilder('Neuer Benutzer'),
+ appBar: applicationData.appBarBuilder('Neue Rolle'),
drawer: applicationData.drawerBuilder(context),
+ persistentFooterButtons:
+ applicationData.footerBuilder().widgets(controller),
body: EditForm.editForm(
key: _formKey,
pageController: controller,
configuration: applicationData.configuration,
));
+ //! === EndOfScaffold ===
}
+ /// Customize the page, e.g. modify the default widget list given by the model
+ void customize();
+
@override
void initState() {
super.initState();
controller =
UserController(_formKey, this, 'create', context, applicationData);
controller.initialize();
+ customize();
}
@override
});
}
}
+
+//! === EndOfGeneratedCode: Below you can change manually:
+
+class UserCreatePageStateCustomized extends UserCreatePageState {
+ UserCreatePageStateCustomized(ApplicationData applicationData)
+ : super(applicationData);
+
+ @override
+ void customize() {
+ // ToDo: write code if needed
+ }
+}
import '../application_data.dart';
import 'user_controller.dart';
+//! === BeginOfGeneratedCode: Below you can change manually:
+//! pageType: change
+
class UserListPage extends StatefulWidget {
final ApplicationData applicationData;
+ //! === BeginOfCustomizedVars1 ===
+ //! === EndOfCustomizedVars1 ===
+ //! === BeginOfConstructor1 ===
UserListPage(this.applicationData, {Key key}) : super(key: key);
+ //! === EndOfConstructor1 ===
+
@override
UserListPageState createState() {
- // UserListPageState.setPageData(pageData);
- final rc = UserListPageState(applicationData);
+ //! === BeginOfCall ===
+ final rc = UserListPageStateCustomized(applicationData);
+ //! === EndOfCall ===
/// for unittests:
applicationData.lastModuleState = rc;
}
}
-class UserListPageState extends State<UserListPage> implements RedrawPage {
+abstract class UserListPageState extends State<UserListPage>
+ implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
Iterable<dynamic> rowsDeprecated;
UserController controller;
+ //! === BeginOfCustomizedVars2 ===
+ //! === EndOfCustomizedVars2 ===
+ //! === BeginOfConstructor2 ===
UserListPageState(this.applicationData);
+ //! === EndOfConstructor2 ===
+
@override
Widget build(BuildContext context) {
controller.beginOfBuild(context);
+
+ //! === BeginOfScaffold ===
return Scaffold(
- appBar: applicationData.appBarBuilder('Benutzer'),
+ appBar: applicationData.appBarBuilder('Rollen'),
drawer: applicationData.drawerBuilder(context),
+ persistentFooterButtons:
+ applicationData.footerBuilder().widgets(controller),
body: ListForm.listForm(
key: _formKey,
configuration: applicationData.configuration,
applicationData.lastErrorMessage(controller.page.fullName()),
),
);
+ //! === EndOfScaffold ===
}
+ /// Customize the page, e.g. modify the default widget list given by the model
+ void customize();
+
@override
void initState() {
super.initState();
controller =
UserController(_formKey, this, 'list', context, applicationData);
controller.initialize();
+ customize();
}
@override
});
}
}
+
+//! === EndOfGeneratedCode: Below you can change manually:
+
+class UserListPageStateCustomized extends UserListPageState {
+ UserListPageStateCustomized(ApplicationData applicationData)
+ : super(applicationData);
+
+ @override
+ void customize() {
+ // ToDo: write code if needed
+ }
+}
import 'hash.dart';
import 'user_controller.dart';
+// === BeginOfGeneratedCode: Do not change manually
class UserLoginPage extends StatefulWidget {
final ApplicationData applicationData;
final logger = Settings().logger;
@override
UserLoginPageState createState() {
- final rc = UserLoginPageState(applicationData);
+ final rc = UserLoginPageStateCustomized(applicationData);
/// for unittests:
applicationData.lastModuleState = rc;
}
}
-class UserLoginPageState extends State<UserLoginPage> implements RedrawPage {
+abstract class UserLoginPageState extends State<UserLoginPage>
+ implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(debugLabel: 'user.login');
));
}
+ void customize();
+
+ void dispose() {
+ controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ UserController(_formKey, this, 'login', context, applicationData);
+ controller.initialize();
+ customize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
+}
+// === EndOfGeneratedCode: Do not change manually
+
+class UserLoginPageStateCustomized extends UserLoginPageState {
+ UserLoginPageStateCustomized(ApplicationData applicationData)
+ : super(applicationData);
void customize() {
ButtonModel button = controller.page.buttonByName('login');
button?.onPressed = () {
}
};
}
-
- void dispose() {
- controller.dispose();
- super.dispose();
- }
-
- @override
- void initState() {
- super.initState();
- controller =
- UserController(_formKey, this, 'login', context, applicationData);
- controller.initialize();
- customize();
- }
-
- @override
- void redraw(RedrawReason reason,
- {String customString, RedrawCallbackFunctionSimple callback}) {
- setState(() {
- controller.afterSetState(reason,
- customString: customString, callback: callback);
- });
- }
}
Future delete(
{@required String module, String sqlName, @required int id}) async {
sqlName ??= 'delete';
- await runRequest(module, sqlName, 'delete', body: '{":${module}_id":$id}',
- headers: jsonHeader);
+ await runRequest(module, sqlName, 'delete',
+ body: '{":${module}_id":$id}', headers: jsonHeader);
}
@override
sqlName ??= 'insert';
var rc = 0;
final data2 = data == null ? '{}' : convert.jsonEncode(data);
- final answer = await runRequest(
- module, sqlName, 'insert', body: data2, headers: jsonHeader);
+ final answer = await runRequest(module, sqlName, 'insert',
+ body: data2, headers: jsonHeader);
if (answer.isNotEmpty) {
final map = convert.jsonDecode(answer);
rc = map['id'];
sqlName ??= 'list';
Iterable<dynamic> rc;
final body = params == null ? '{}' : convert.jsonEncode(params);
- final answer = await runRequest(
- module, sqlName, 'list', body: body, headers: jsonHeader);
+ final answer = await runRequest(module, sqlName, 'list',
+ body: body, headers: jsonHeader);
if (answer.isNotEmpty) {
rc = convert.jsonDecode(answer);
}
converter.iconByName('build_outlined', logger)),
MenuItem(
'StartmenĂĽ',
- () => converter.pageByName('menu.list', settings.pageData),
+ () => converter.pageByName('starter.list', settings.pageData),
converter.iconByName('menu_open_outlined', logger)),
+ MenuItem(
+ 'Programmpunkte',
+ () => converter.pageByName('menu.list', settings.pageData),
+ converter.iconByName('radio_button_checked_outlined', logger)),
MenuItem('Demo', () => converter.pageByName('demo', settings.pageData),
converter.iconByName('article_outlined', logger)),
];
final list = MenuItem.menuItems(converter);
final rc = Card(
child: GridView.count(
- crossAxisCount: 2,
- crossAxisSpacing: 16.0,
- children: list
- .map((item) =>
- GridTile(
+ crossAxisCount: 2,
+ crossAxisSpacing: 16.0,
+ children: list
+ .map((item) => GridTile(
child: new InkResponse(
enableFeedback: true,
child: Card(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
children: list
- .map((item) =>
- ListTile(
- title: Text(item.title),
- onTap: () {
- // What happens after you tap the navigation item
- Navigator.push(
+ .map((item) => ListTile(
+ title: Text(item.title),
+ onTap: () {
+ // What happens after you tap the navigation item
+ Navigator.push(
context,
MaterialPageRoute(
builder: (context) => item.page()));
--- /dev/null
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/page_controller_bones.dart';
+import 'package:url_launcher/url_launcher.dart';
+
+class BFooter implements FooterBones {
+ List<Widget> widgets(PageControllerBones controller) {
+ final rc = [
+ Row(children: <Widget>[
+ InkWell(
+ child: Text('Impressum'),
+ onTap: () => launch('https://public.hamatoma.de'),
+ ),
+ SizedBox(
+ width: 100,
+ ),
+ InkWell(
+ child: Text('Datenschutz'),
+ onTap: () => launch('https://public.hamatoma.de'),
+ ),
+ SizedBox(
+ width: 150,
+ ),
+ Text('Hallo ${controller.applicationData.currentUserName}'),
+ ])
+ ];
+ // final rc2 = [
+ // GridView.count(crossAxisCount: 3, children: [
+ // Text('a'),
+ // Text('b'),
+ // Text('c'),
+ // ])
+ // ];
+ return rc;
+ }
+
+ /// Returns a method creating a footer.
+ static BFooter builder() => BFooter();
+}
import 'package:flutter_bones/flutter_bones.dart';
import 'package:flutter_bones/src/private/bappbar.dart';
import 'package:flutter_bones/src/private/bdrawer.dart';
+import 'package:flutter_bones/src/private/bfooter.dart';
class BSettings {
final BaseConfiguration configuration;
port: 58011,
host: 'localhost',
logger: logger);
- final applicationData = ApplicationData(BaseConfiguration(map, logger),
- BAppBar.builder, BonesDrawer.builder, persistence, logger);
+ final applicationData = ApplicationData(
+ BaseConfiguration(map, logger),
+ BAppBar.builder,
+ BonesDrawer.builder,
+ BFooter.builder,
+ persistence,
+ logger);
final rc = BSettings.internal(
BaseConfiguration(map, logger), applicationData, persistence, logger);
return lastInstance = rc;
final widgets = pageController.getWidgets();
final view = View();
final buttons =
- view.modelsToWidgets(pageController.page.buttons, pageController);
+ view.modelsToWidgets(pageController.page.sections[0].buttonBar, pageController);
return Form(
key: key,
child: Card(
/// Builds the SQL parameters of all members of the [widgets].
Map<String, String> buildSqlParams() {
final rc = <String, String>{};
- page.fields.forEach((element) {
- if (element.filterType != null) {
- dynamic value = element.value;
- DataType dataType = element.dataType;
- String name = element.name;
- if (element.filterType == FilterType.pattern) {
+ page.models.values.forEach((model) {
+ if (model is FieldModel && model.filterType != null) {
+ dynamic value = model.value;
+ DataType dataType = model.dataType;
+ String name = model.name;
+ if (model.filterType == FilterType.pattern) {
if (value == null || value.isEmpty) {
value = '%';
} else if (value is String) {
/// e.g. { 'role_name': 'admin', ...}
void buildModelList([Map initialRow]) {
modelList.clear();
- page.widgets.forEach((model) {
+ page.sections[0].children.forEach((model) {
if (initialRow != null && model is FieldModel) {
model.valueFromRow(initialRow);
}
completeModels(model);
modelList.addModel(name, model);
});
- page.fields.forEach((element) => prepareModel(element));
+ page.sections[0].children.forEach((element) {
+ if (element is FieldModel) {
+ prepareModel(element);
+ }
+ });
}
/// Completes the widgets asynchronously if needed.
}
/// Gets the data from the database using the [primaryId].
- fetchData(int primaryId) async {
+ void fetchData(int primaryId) async {
applicationData.persistence
.recordById(module: moduleModel.name, id: primaryId)
.then((row) {
- page.fields.forEach((model) {
- model.value = row[model.name];
+ page.models.values.forEach((model) {
+ if (model is FieldModel) {
+ model.value = row[model.name];
+ }
});
/// navigate to the page "change":
globalKey.currentState.save();
final params = modelList.buildSqlParams(this);
PageModelType pageType =
- moduleModel
- .pageByName(pageName)
- .pageModelType;
+ moduleModel.pageByName(pageName).pageModelType;
switch (pageType) {
case PageModelType.create:
applicationData.persistence
void initializeFields(Map initialRow) {
modelList.models.forEach((model) {
if (model is FieldModel && initialRow.containsKey(model.name)) {
- page
- .fieldByName(model.name)
- ?.value = initialRow[model.name];
+ page.fieldByName(model.name)?.value = initialRow[model.name];
}
});
}
{@required Key key,
@required List<Widget> fields,
@required List<Widget> buttons,
- @required BaseConfiguration configuration}) {
+ @required BaseConfiguration configuration,
+ List<Widget> intro}) {
final padding =
configuration.asFloat('form.card.padding', defaultValue: 16.0);
return Form(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
child: ListView(children: <Widget>[
+ ...intro ?? [],
...fields,
SizedBox(
height: configuration.asFloat(
return rc;
}
- /// Creates a list of buttons from a list of [controllers].
+ /// Creates a list of buttons from a list of [models].
List<Widget> buttonList(
- List<ButtonModel> buttonModels, PageControllerBones controller) {
+ List<ButtonModel> models, PageControllerBones controller) {
final rc = <Widget>[];
- for (var model in buttonModels) {
+ for (var model in models) {
rc.add(button(model, controller));
}
return rc;
return rc;
}
- /// Returns a form with the properties given by the [model]
+ /// Returns a form with the properties given by the [sectionModel]
/// [formKey] identifies the form. Used for form validation and saving.
Form simpleForm(
- {SectionModel model, PageControllerBones controller, Key formKey}) {
+ {SectionModel sectionModel, PageControllerBones controller, Key formKey}) {
assert(formKey != null);
final padding =
widgetConfiguration.asFloat('form.card.padding', defaultValue: 16.0);
- final children = modelsToWidgets(model.children, controller);
- final buttons = buttonList(model.buttons, controller);
+ final children = modelsToWidgets(sectionModel.children, controller);
+ final buttons = buttonList(sectionModel.buttonBar, controller);
final rc = Form(
key: formKey,
child: Card(
import 'package:dart_bones/dart_bones.dart';
-
-import 'src/model/module_model.dart';
-import 'src/model/standard/standard_modules.dart';
-import 'src/helper/string_helper.dart';
+import 'package:flutter_bones_tool/src/model/model_helper.dart';
+import 'package:flutter_bones_tool/src/model_tools.dart';
void main(List<String> argv) async {
final logger = MemoryLogger(LEVEL_FINE);
- final dbHelper = DbHelper(logger);
+ final ModelHelper modelHelper = ModelHelper();
+ final ModelTools modelTools = ModelTools(modelHelper, logger);
if (argv.isEmpty) {
argv = ['export-sql'];
}
- final mode = argv[0];
- argv.removeAt(0);
- final options = <String>[];
- argv = StringHelper.splitArgv(argv, options);
- switch (mode) {
- case 'export-sql':
- dbHelper.exportSql(argv, options);
- break;
- default:
- logger.error('unknown mode: $mode');
- break;
- }
+ modelTools.run(argv);
}
-class DbHelper {
- final BaseLogger logger;
-
- DbHelper(this.logger);
-
- void exportSql(List<String> args, List<String> options) {
- String directory;
- String value;
- for (var opt in options) {
- value = StringUtils.stringOption('directory', 'd', opt);
- if (value != null) {
- directory = value;
- }
- }
- directory ??= 'data';
- final dirDDL = FileSync.joinPaths(directory, 'ddl');
- final dirREST = FileSync.joinPaths(directory, 'rest');
- FileSync.ensureDirectory(dirDDL);
- FileSync.ensureDirectory(dirREST);
- if (args.isEmpty) {
- args = standardModules();
- }
- while (args.isNotEmpty) {
- final name = args[0];
- args.removeAt(0);
- ModuleModel module = standardModule(name, logger);
- if (module != null) {
- module.parse();
- var filename = FileSync.joinPaths(dirDDL, '$name.sql');
- FileSync.toFile(filename, module.exportSqlCreateTable());
- print('exported: $filename');
- filename = FileSync.joinPaths(dirREST, '$name.yaml');
- FileSync.toFile(filename, module.exportSqlBackend());
- print('exported: $filename');
- }
- }
- }
-
- void usage(String error) {
- print('''usage: dbhelper <mode> [<args>]
-<mode>:
- create-sql [<module>] [<opt>]
- <module>: 'role', 'user' ...
- <opt>:
- -d<dir> or --directory=<dir>:
- the base directory used for the exported files.
-Examples:
-dbhelper create-sql role role.sql -d/tmp
-dbhelper create-sql --directory=/opt/sql-data
-''');
- }
-}
--- /dev/null
+import 'dart:io';
+
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter_bones_tool/src/model/page_model.dart';
+
+import 'helper/string_helper.dart';
+import 'model/model_helper.dart';
+import 'model/module_model.dart';
+
+class ModelTools {
+ final BaseLogger logger;
+ final ModelHelper modelHelper;
+ ModelTools(this.modelHelper, this.logger);
+
+ /// Copies a range of [lines] defined by [start] and [end] markers into [buffer].
+ /// [includeStart]: true: the line containing [start] will be copied too.
+ /// [includeEnd]: true: the line containing [end] will be copied too.
+ /// [replacements]: null or a map with (key, replacement) pairs. All
+ /// occurrences of key in the copied lines will be replaced by the replacement.
+ /// Returns the count of copied lines.
+ int copyToBuffer(List<String> lines, StringBuffer buffer,
+ {String start,
+ bool includeStart = true,
+ String end,
+ bool includeEnd = true,
+ Map<String, String> replacements}) {
+ var mode = start == null ? 'copy' : 'ignore';
+ var count = 0;
+ for (var line in lines) {
+ if (includeStart && start != null && line.contains(start)) {
+ mode == 'copy';
+ }
+ if (!includeEnd && end != null && line.contains(end)) {
+ break;
+ }
+ if (mode == 'copy') {
+ if (replacements != null) {
+ for (var key in replacements.keys) {
+ line = line.replaceAll(key, replacements[key]);
+ }
+ }
+ buffer.write(line);
+ buffer.write('\n');
+ count++;
+ }
+ if (start != null && line.contains(start)) {
+ mode = 'copy';
+ }
+ if (end != null && line.contains(end)) {
+ break;
+ }
+ }
+ return count;
+ }
+
+ void exportSql(List<String> args, List<String> options) {
+ String directory;
+ String value;
+ for (var opt in options) {
+ value = StringUtils.stringOption('directory', 'd', opt);
+ if (value != null) {
+ directory = value;
+ continue;
+ }
+ logger.error('unknown option: $opt');
+ }
+ directory ??= 'data';
+ final dirDDL = FileSync.joinPaths(directory, 'ddl');
+ final dirREST = FileSync.joinPaths(directory, 'rest');
+ FileSync.ensureDirectory(dirDDL);
+ FileSync.ensureDirectory(dirREST);
+ if (args.isEmpty) {
+ args = modelHelper.moduleNames();
+ }
+ while (args.isNotEmpty) {
+ final name = args[0];
+ args.removeAt(0);
+ ModuleModel module = modelHelper.moduleByName(name, logger);
+ if (module != null) {
+ module.parse();
+ var filename = FileSync.joinPaths(dirDDL, '$name.sql');
+ FileSync.toFile(filename, module.exportSqlCreateTable());
+ print('exported: $filename');
+ filename = FileSync.joinPaths(dirREST, '$name.yaml');
+ FileSync.toFile(filename, module.exportSqlBackend());
+ print('exported: $filename');
+ }
+ }
+ }
+
+ void modifyModule(List<String> args, List<String> options) {
+ String baseDirectory;
+ String value;
+ for (var opt in options) {
+ value = StringUtils.stringOption('directory', 'd', opt);
+ if (value != null) {
+ baseDirectory = value;
+ continue;
+ }
+ logger.error('unknown option: $opt');
+ }
+ baseDirectory ??= 'lib/src/model';
+ if (args.isEmpty) {
+ args = modelHelper.moduleNames();
+ }
+ final regExprFilename = RegExp(r'_(\w+)_page\.dart');
+ for (var name in args) {
+ if (name == 'role') {
+ logger.log('module "role" ignored.');
+ }
+ final sourceDir = 'lib/src/page/$name';
+ logger.log('current directory: ${Directory.current}');
+ final files = Directory(sourceDir).listSync();
+ final pathSafe = FileSync.tempDirectory(
+ name +
+ '.' +
+ (DateTime.now().millisecondsSinceEpoch / 1000 % 86400)
+ .round()
+ .toString(),
+ subDirs: 'model_tools');
+ for (var file in files) {
+ final lines = FileSync.fileAsList(file.path);
+ final fnTemplate = file.path.replaceAll(name, 'role');
+ final templateLines = FileSync.fileAsList(fnTemplate);
+ if (templateLines.isEmpty) {
+ logger.log('ignoring ${file.path}: no template found');
+ continue;
+ }
+ final matcher = regExprFilename.firstMatch(file.path);
+ if (matcher == null) {
+ logger.error('cannot recognize page type: ${file.path}');
+ continue;
+ }
+ final pageType = StringUtils.stringToEnum<PageModelType>(
+ matcher.group(1), PageModelType.values);
+ modifyPage(
+ name,
+ pageType,
+ lines,
+ templateLines,
+ FileSync.joinPaths(baseDirectory, name, FileSync.nodeOf(file.path)),
+ false,
+ pathSafe);
+ }
+ }
+ }
+
+ void modifyPage(
+ String module,
+ PageModelType type,
+ List<String> lines,
+ List<String> templateLines,
+ String filename,
+ bool customizeConstructors,
+ String pathSafe) {
+ final moduleCapital = StringHelper.capitalize(module);
+ FileSync.ensureDirectory(FileSync.parentOf(filename, trailingSlash: false));
+ final buffer = StringBuffer();
+ var countTemplate = 0;
+ final replacements = <String, String>{
+ 'role': module,
+ 'Role': moduleCapital
+ };
+ var countOrigin = 0;
+ int ix;
+ if (!customizeConstructors) {
+ if (StringHelper.listIndexOf(lines, string: 'EndOfGeneratedCode') != null) {
+ countOrigin = copyToBuffer(lines, buffer,
+ end: 'BeginOfGeneratedCode', includeEnd: false);
+ } else {
+ countOrigin = copyToBuffer(templateLines, buffer,
+ end: 'BeginOfGeneratedCode',
+ includeEnd: false,
+ replacements: replacements);
+ }
+ countTemplate = copyToBuffer(templateLines, buffer,
+ start: 'BeginOfGeneratedCode',
+ end: 'EndOfGeneratedCode',
+ replacements: replacements);
+ countOrigin = copyToBuffer(lines, buffer,
+ start: 'EndOfGeneratedCode', includeStart: false);
+ ix = StringHelper.listIndexOf(lines, string: 'EndOfGeneratedCode');
+ // -3: possible empty lines at the end
+ if (ix == null || ix > lines.length - 3) {
+ countTemplate += copyToBuffer(templateLines, buffer,
+ start: 'EndOfGeneratedCode',
+ includeStart: false,
+ replacements: replacements);
+ }
+ } else {
+ //
+ }
+ FileSync.ensureDirectory(pathSafe);
+ final fnSafe = FileSync.joinPaths(pathSafe, FileSync.nodeOf(filename));
+ logger.log('saving to $fnSafe');
+ FileSync.toFile(fnSafe, lines.join('\n'));
+ logger.log('writing $filename lines: $countOrigin + $countTemplate');
+ FileSync.toFile(filename, buffer.toString());
+ }
+
+ void run(List<String> args) {
+ final mode = args[0];
+ final options = <String>[];
+ args = StringHelper.splitArgv(args.sublist(1), options);
+ switch (mode) {
+ case 'export-sql':
+ exportSql(args, options);
+ break;
+ case 'modify-module':
+ modifyModule(args, options);
+ break;
+ default:
+ logger.error('unknown mode: $mode');
+ break;
+ }
+ }
+
+ void usage(String error) {
+ print('''usage: main <mode> [<args>]
+<mode>:
+ create-sql [<module1> [<module2>...] [<opt>]
+ Generates the DDL ("create table...") statements and the yaml files
+ describing the insert... SQL statements.
+ <moduleN>: 'role', 'user' ...
+ <opt>:
+ -d<dir> or --directory=<dir>:
+ the base directory used for the exported files.
+ help
+ Display this usage messages.
+ modify-module [<module1> [<module2>...]
+ Modifies the files of the given modules to renew the generated code.
+Examples:
+main create-sql role user -d/tmp
+main create-sql --directory=/opt/sql-data
+main modify-pages role
+main modify-pages
+''');
+ }
+}
--- /dev/null
+../../../lib/src/page/
\ No newline at end of file
sdk: ">=2.11.0-234.0.dev <3.0.0"
dependencies:
- dart_bones: "^0.4.6"
+ dart_bones: "^0.4.7"
# The following adds the Cupertino Icons font to your application.
sdk: flutter
flutter_localizations:
sdk: flutter
- dart_bones: "^0.4.5"
+ dart_bones: "^0.4.7"
crypto: ^2.1.5
+ flutter_markdown: ^0.5.0
+ url_launcher: ^5.7.10
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
expect(options, equals([]));
});
});
+ group('StringList', (){
+ test('listIndexOf-string', (){
+ final list = <String>['a', 'bab', 'cAC'];
+ expect(StringHelper.listIndexOf(list, string: 'b'), equals(1));
+ expect(StringHelper.listIndexOf(list, string: 'a'), equals(0));
+ expect(StringHelper.listIndexOf(list, string: 'A'), equals(2));
+ expect(StringHelper.listIndexOf(list, string: 'x'), isNull);
+ expect(StringHelper.listIndexOf(null, string: 'x'), isNull);
+ });
+ test('listIndexOf-regEx', (){
+ final list = <String>['a', 'bab', 'cAC'];
+ expect(StringHelper.listIndexOf(list, pattern: r'...'), equals(1));
+ expect(StringHelper.listIndexOf(list, pattern: r'C$'), equals(2));
+ expect(StringHelper.listIndexOf(list, pattern: 'x'), isNull);
+ expect(StringHelper.listIndexOf(null, pattern: 'x'), isNull);
+
+ expect(StringHelper.listIndexOf(list, regExp: RegExp(r'a', caseSensitive: false)), equals(0));
+ expect(StringHelper.listIndexOf(list, regExp: RegExp(r'd')), isNull);
+ expect(StringHelper.listIndexOf(null, regExp: RegExp(r'd')), isNull);
+ });
+ });
}
final module = ModuleModel(map, logger);
module.parse();
final page = module.pageByName('list');
- page.addButton(ButtonModel.direct(
+ page.addModel(ButtonModel.direct(
null,
page,
'a',
ButtonModelType.store,
[],
logger));
- page.addButton(ButtonModel.direct(
+ page.addModel(ButtonModel.direct(
null,
page,
'a',
[],
logger));
page.buttonByName('unknown');
- page.addField(TextFieldModel.direct(
+ page.addModel(TextFieldModel.direct(
null,
page,
'n',
<String>[],
33,
logger));
- page.addField(TextFieldModel.direct(
+ page.addModel(TextFieldModel.direct(
null,
page,
'n',
expect(errors.length, equals(0));
final page = module.pageByName('change');
expect(page, isNotNull);
- expect(page.fields.length, equals(3));
+ expect(page.models.values.length, equals(3));
expect(page.hasField('user_id'), isTrue);
expect(page.hasField('user_name'), isTrue);
expect(page.hasField('user_role'), isTrue);
pageControllerBones = PageControllerBones(
null, null, UserModel(logger), 'list', null, applicationData);
applicationData =
- ApplicationData(configuration, null, null, persistence, logger);
+ ApplicationData(configuration, null, null, null, persistence, logger);
});
group('Basics', () {
test('basic', () async {
import 'package:dart_bones/dart_bones.dart';
import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/model/model_helper.dart';
import 'package:test/test.dart';
void main() {
'''));
});
test('standard_modules', () {
+ ModelHelper helper = ModelHelper();
logger.clear();
final dir = FileSync.tempDirectory('data', subDirs: 'unittest');
- for (var name in standardModules()) {
- final module = standardModule(name, logger);
+ for (var name in helper.moduleNames()) {
+ final module = helper.moduleByName(name, logger);
module.parse();
expect(logger.errors.isEmpty, isTrue);
final content = module.exportSqlBackend();
});
test('standard_modules-errors', () {
logger.clear();
- final module = standardModule('not-exists', logger);
+ final helper = ModelHelper();
+ final module = helper.moduleByName('not-exists', logger);
expect(module, isNull);
expect(logger.contains('unknown standard module: not-exists'), isTrue);
});
group('ModuleController', () {
test('basic', () {
ApplicationData appData = ApplicationData(BaseConfiguration({}, logger),
- (title) => null, (context) => null, persistence, logger);
+ (title) => null, (context) => null, () => null, persistence, logger);
final role = RoleCreatePage(appData);
if (appData.lastModuleState == null) {
role.createState();
expect(table, isNotNull);
var model = table.columnByName('test');
final page = PageModel(module, logger);
- page.addField(model);
+ page.addModel(model);
model.page = page;
expect(model, isNotNull);
model.parseFinish();
'Unzulässige Eingabe "5" in str');
model = table.columnByName('test2');
expect(model, isNotNull);
- page.addField(model);
+ page.addModel(model);
model.page = page;
model.parseFinish();
prepareModel(model);