From eb315d375cb35cc5cf9930b623e36ad51585919b Mon Sep 17 00:00:00 2001 From: Hamatoma Date: Wed, 18 Nov 2020 05:51:21 +0100 Subject: [PATCH] daily work --- lib/src/helper/string_helper.dart | 150 +++++++-- lib/src/helper/url_helper.dart | 58 ++++ lib/src/model/all_db_fields_model.dart | 2 +- lib/src/model/button_model.dart | 2 +- lib/src/model/column_model.dart | 2 +- lib/src/model/empty_line_model.dart | 2 +- lib/src/model/field_model.dart | 2 +- lib/src/model/model_base.dart | 2 +- lib/src/model/model_helper.dart | 1 - lib/src/model/model_tool.dart | 314 ++++++++++++++++++ lib/src/model/module_model.dart | 2 +- lib/src/model/page_model.dart | 4 +- lib/src/model/section_model.dart | 6 +- .../model/standard/configuration_model.dart | 13 +- lib/src/model/standard/menu_model.dart | 13 +- lib/src/model/standard/role_model.dart | 2 +- lib/src/model/standard/starter_model.dart | 13 +- lib/src/model/standard/user_model.dart | 15 +- lib/src/model/table_model.dart | 2 +- lib/src/model/text_model.dart | 2 +- lib/src/page/application_data.dart | 2 +- .../configuration_change_page.dart | 69 +++- .../configuration_create_page.dart | 58 +++- .../configuration_list_page.dart | 83 +++-- lib/src/page/menu/menu_change_page.dart | 61 +++- lib/src/page/menu/menu_create_page.dart | 56 +++- lib/src/page/menu/menu_list_page.dart | 67 +++- lib/src/page/role/role_change_page.dart | 15 +- lib/src/page/role/role_create_page.dart | 18 +- lib/src/page/role/role_list_page.dart | 23 +- lib/src/page/starter/starter_change_page.dart | 57 +++- lib/src/page/starter/starter_create_page.dart | 55 ++- lib/src/page/starter/starter_list_page.dart | 99 ++++-- lib/src/page/user/user_change_page.dart | 17 +- lib/src/page/user/user_create_page.dart | 20 +- lib/src/page/user/user_list_page.dart | 34 +- lib/src/page/user/user_login_page.dart | 43 ++- lib/src/page/user/user_password_page.dart | 95 ++++-- lib/src/private/bfooter.dart | 38 +-- lib/src/widget/edit_form.dart | 4 +- lib/src/widget/view.dart | 4 +- model_tool/lib/main.dart | 5 +- model_tool/lib/src/model_tool_io.dart | 45 +++ model_tool/lib/src/model_tools.dart | 239 ------------- model_tool/pubspec.yaml | 6 + model_tool/test/model_tool_test.dart | 17 + pubspec.yaml | 5 +- test/helpers/string_helper_test.dart | 141 +++++++- test/model/db_model_test.dart | 2 +- test/model/model_test.dart | 2 +- test/tool/tool_test.dart | 227 ++++++++++++- 51 files changed, 1651 insertions(+), 563 deletions(-) create mode 100644 lib/src/helper/url_helper.dart create mode 100644 lib/src/model/model_tool.dart create mode 100644 model_tool/lib/src/model_tool_io.dart delete mode 100644 model_tool/lib/src/model_tools.dart create mode 100644 model_tool/test/model_tool_test.dart diff --git a/lib/src/helper/string_helper.dart b/lib/src/helper/string_helper.dart index b0ced96..1473e04 100644 --- a/lib/src/helper/string_helper.dart +++ b/lib/src/helper/string_helper.dart @@ -3,11 +3,105 @@ import 'package:intl/intl.dart'; import '../model/model_types.dart'; +typedef LineConverter = String Function(String input); + class StringHelper { static final regExpTrue = RegExp(r'^(true|yes|t)$', caseSensitive: false); static final regExpFalse = RegExp(r'^(false|no|f)$', caseSensitive: false); static const locale = 'de_DE'; + /// Copies a range of lines from [input] to the end of [output]. + /// The range is defined by a start and an end. + /// The start can be defined as [startString], [startRegExp] or [startPattern]. + /// The end can be defined as [endString], [endRegExp] or [endPattern]. + /// [startString] and [endString] are strings that are substrings of the start/end. + /// [startPattern] and [endPattern] are strings representing regular + /// expressions defining substrings in the start/end. + /// [includeStart]: true: the line containing the start will be copied too. + /// [includeEnd]: true: the line containing the end will be copied too. + /// [firstIndex] is the first index of [input] to process (searching and + /// copying). If [firstIndex] < 0: take it from the end, e.g. -1 means the + /// last line of [input]. + /// [lastIndexIncluded] is the last index to process (searching and copying). + /// If [lastIndexIncluded] < 0: index is relative to the end. + /// [lastIndexExcluded] is one below the last index to process (searching and copying). + /// If [lastIndexExcluded] < 0: index is relative to the end. + /// [converter]: null a callback function for modifying the copied lines, + /// e.g. (line) => line.toLowerCase() + /// Returns [output] (for chaining). + static List addRangeToList(List input, List output, + {int firstIndex, + int lastIndexExcluded, + lastIndexIncluded, + String startString, + RegExp startRegExp, + String startPattern, + bool includeStart = true, + String endString, + RegExp endRegExp, + String endPattern, + bool includeEnd = true, + LineConverter converter}) { + output ??= []; + if (input != null) { + var doCopy = + startString == null && startRegExp == null && startPattern == null; + firstIndex ??= 0; + if (firstIndex < 0) { + firstIndex = + (firstIndex = input.length + firstIndex) < 0 ? 0 : firstIndex; + } + if (lastIndexExcluded == null) { + lastIndexExcluded = lastIndexIncluded == null + ? input.length + : (lastIndexIncluded < 0 + ? input.length + lastIndexIncluded + : lastIndexIncluded) + + 1; + } + lastIndexExcluded = + lastIndexExcluded > input.length ? input.length : lastIndexExcluded; + if (startPattern != null) { + startRegExp = RegExp(startPattern); + } + if (endPattern != null) { + endRegExp = RegExp(endPattern); + } + var line; + while (firstIndex < lastIndexExcluded) { + line = input[firstIndex++]; + if (!doCopy && + includeStart && + (startString != null && line.contains(startString) || + startRegExp?.firstMatch(line) != null)) { + doCopy = true; + } + if (!includeEnd && + (endString != null && line.contains(endString) || + endRegExp != null && endRegExp.firstMatch(line) != null)) { + break; + } + if (doCopy) { + if (converter != null) { + line = converter(line); + } + output.add(line); + } + if (!doCopy && + (startString != null && line.contains(startString) || + startRegExp?.firstMatch(line) != null)) { + doCopy = true; + } + if (includeEnd && + (endString != null && line.contains(endString) || + endRegExp?.firstMatch(line) != null)) { + break; + } + } + } + return output; + } + /// Convert [value] into a string for storing in a database respecting [dataType]. static String asDatabaseString(dynamic value, DataType dataType) { if (value == null) { @@ -50,6 +144,12 @@ class StringHelper { 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; + } + /// 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 ...). @@ -128,28 +228,6 @@ class StringHelper { return rc; } - /// Replaces all placeholders defined by [syntaxPlaceholder] or [regExpPlaceholder] - /// in [source] and return this result. - /// [syntaxPlaceholder] or [regExpPlaceholder] must contain a single group - /// identifying the name of the placeholder. - /// Example: - /// replacePlaceholders('Hi ~user~', { "user": "joe"}, syntaxPlaceholder: r'~(\w+)~') - /// returns "Hi Joe". - static String replacePlaceholders( - String source, Map placeholders, - {String syntaxPlaceholder, RegExp regExpPlaceholder}) { - regExpPlaceholder ??= RegExp(syntaxPlaceholder); - final rc = - regExpPlaceholder.allMatches(source).fold(source, (string, match) { - final name = match.group(1); - final rc2 = placeholders.containsKey(name) - ? string.replaceFirst(match.group(0), placeholders[name]) - : string; - return rc2; - }); - 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. @@ -184,6 +262,28 @@ class StringHelper { return rc; } + /// Replaces all placeholders defined by [syntaxPlaceholder] or [regExpPlaceholder] + /// in [source] and return this result. + /// [syntaxPlaceholder] or [regExpPlaceholder] must contain a single group + /// identifying the name of the placeholder. + /// Example: + /// replacePlaceholders('Hi ~user~', { "user": "joe"}, syntaxPlaceholder: r'~(\w+)~') + /// returns "Hi Joe". + static String replacePlaceholders( + String source, Map placeholders, + {String syntaxPlaceholder, RegExp regExpPlaceholder}) { + regExpPlaceholder ??= RegExp(syntaxPlaceholder); + final rc = + regExpPlaceholder.allMatches(source).fold(source, (string, match) { + final name = match.group(1); + final rc2 = placeholders.containsKey(name) + ? string.replaceFirst(match.group(0), placeholders[name]) + : string; + return rc2; + }); + 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 @@ -199,10 +299,4 @@ class StringHelper { } 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; - } } diff --git a/lib/src/helper/url_helper.dart b/lib/src/helper/url_helper.dart new file mode 100644 index 0000000..4f5bd22 --- /dev/null +++ b/lib/src/helper/url_helper.dart @@ -0,0 +1,58 @@ +import 'package:dart_bones/dart_bones.dart'; + +class UrlHelper { + static final sep = '/'; + static final currentDirSep = '.' + sep; + + /// Joins parts to a combined path. + /// [first]: first part + /// [second]: second part + /// [third]: third part + static String joinPaths(String first, String second, [String third]) { + final rc = StringBuffer(first); + var last = first; + if (second.isNotEmpty) { + if (!first.endsWith(sep)) { + rc.write(sep); + } + if (second.startsWith(currentDirSep)) { + rc.write(second.substring(2)); + } else if (second.startsWith(sep)) { + rc.write(second.substring(1)); + } else { + rc.write(second); + } + last = second; + } + if (third != null && third.isNotEmpty) { + if (!last.endsWith(sep)) { + rc.write(sep); + } + if (third.startsWith(currentDirSep)) { + rc.write(third.substring(2)); + } else if (third.startsWith(sep)) { + rc.write(third.substring(1)); + } else { + rc.write(third); + } + } + return rc.toString(); + } + + /// Returns the filename of the [path] without path. + /// Example: base('abc/def.txt') == 'def.txt' + static String nodeOf(String path) { + final ix = path.lastIndexOf(sep); + final rc = ix < 0 ? path : path.substring(ix + 1); + return rc; + } + + /// Returns the parent directory of the [path]. + /// Example: dirname('abc/def.txt') == 'abc/' + /// [trailingSlash]: if false the trailing slash will not be part of the result + static String parentOf(String path, {bool trailingSlash: true}) { + final ix = path.lastIndexOf(sep); + final rc = ix < 0 ? '' : path.substring(0, ix + (trailingSlash ? 1 : 0)); + return rc; + } +} diff --git a/lib/src/model/all_db_fields_model.dart b/lib/src/model/all_db_fields_model.dart index 9e8506a..4848fa4 100644 --- a/lib/src/model/all_db_fields_model.dart +++ b/lib/src/model/all_db_fields_model.dart @@ -16,7 +16,7 @@ class AllDbFieldsModel extends WidgetModel { AllDbFieldsModel(SectionModel section, PageModel page, BaseLogger logger) : super(section, page, ModelTypeBones.allDbFields, null, logger); - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => '${section.name}.$name'; diff --git a/lib/src/model/button_model.dart b/lib/src/model/button_model.dart index 55bf4d6..f4aa3d1 100644 --- a/lib/src/model/button_model.dart +++ b/lib/src/model/button_model.dart @@ -41,7 +41,7 @@ class ButtonModel extends WidgetModel { return stringBuffer; } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => '${section?.name}.$name'; diff --git a/lib/src/model/column_model.dart b/lib/src/model/column_model.dart index 6c73f4b..6c5a33f 100644 --- a/lib/src/model/column_model.dart +++ b/lib/src/model/column_model.dart @@ -58,7 +58,7 @@ class ColumnModel extends ComboBaseModel { return stringBuffer; } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => '${table.name}.$name'; diff --git a/lib/src/model/empty_line_model.dart b/lib/src/model/empty_line_model.dart index 9bfa2c4..5bc1b0f 100644 --- a/lib/src/model/empty_line_model.dart +++ b/lib/src/model/empty_line_model.dart @@ -19,7 +19,7 @@ class EmptyLineModel extends WidgetModel { return stringBuffer; } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => '${section.name}.$name'; diff --git a/lib/src/model/field_model.dart b/lib/src/model/field_model.dart index af820d0..3070ca3 100644 --- a/lib/src/model/field_model.dart +++ b/lib/src/model/field_model.dart @@ -173,7 +173,7 @@ abstract class FieldModel extends WidgetModel { } } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => '${page.name}.$name'; diff --git a/lib/src/model/model_base.dart b/lib/src/model/model_base.dart index 9a4efbd..2b3de51 100644 --- a/lib/src/model/model_base.dart +++ b/lib/src/model/model_base.dart @@ -43,7 +43,7 @@ abstract class ModelBase { }); } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. String fullName(); /// Tests whether a given [option] is part of [options]. diff --git a/lib/src/model/model_helper.dart b/lib/src/model/model_helper.dart index 4ccd334..85c190e 100644 --- a/lib/src/model/model_helper.dart +++ b/lib/src/model/model_helper.dart @@ -36,5 +36,4 @@ class ModelHelper { /// Returns the names of the modules. List moduleNames() => ['configuration', 'menu', 'role', 'starter', 'user']; - } diff --git a/lib/src/model/model_tool.dart b/lib/src/model/model_tool.dart new file mode 100644 index 0000000..17271d7 --- /dev/null +++ b/lib/src/model/model_tool.dart @@ -0,0 +1,314 @@ +import 'package:dart_bones/dart_bones.dart'; + +import '../helper/string_helper.dart'; +import '../helper/url_helper.dart'; +import 'model_helper.dart'; +import 'module_model.dart'; +import 'page_model.dart'; + +/// Implements tools for development of flutter_bones applications. +/// This class is is "web friendly", it does not depend directly on package:io. +abstract class ModelTool { + final BaseLogger logger; + final ModelHelper modelHelper; + ModelTool(this.modelHelper, this.logger); + + /// Ensures that the [directory] exists. If not it will be created. + void ensureDirectory(String directory); + + void exportSql(List args, List 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 = UrlHelper.joinPaths(directory, 'ddl'); + final dirREST = UrlHelper.joinPaths(directory, 'rest'); + ensureDirectory(dirDDL); + 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 = UrlHelper.joinPaths(dirDDL, '$name.sql'); + writeFile(filename, module.exportSqlCreateTable()); + print('exported: $filename'); + filename = UrlHelper.joinPaths(dirREST, '$name.yaml'); + writeFile(filename, module.exportSqlBackend()); + print('exported: $filename'); + } + } + } + + void modifyModule(List args, List options) { + String baseDirectory; + String value; + PageModelType handledPageType; + bool overwriteConstructor = false; + for (var opt in options) { + value = StringUtils.stringOption('directory', 'd', opt); + if (value != null) { + baseDirectory = value; + continue; + } + value = StringUtils.stringOption('directory', 'd', opt); + if (value != null) { + handledPageType = StringUtils.stringToEnum( + value, PageModelType.values); + if (handledPageType == null) { + logger.error('unknown page type $value in $opt'); + logger.error('aborting command'); + throw FormatException('invalid option $opt'); + break; + } + continue; + } + var boolValue = + StringUtils.boolOption('overwrite-constructors', 'c', opt); + if (boolValue != Bool.UNDEF) { + overwriteConstructor = boolValue == Bool.TRUE; + continue; + } + logger.error('unknown option: $opt'); + } + baseDirectory ??= 'lib/src/model'; + if (args.isEmpty) { + args = modelHelper.moduleNames(); + } + final regExpPageType = + RegExp(r'const ([a-z]+)([A-Z][a-z]+)PageType = PageModelType\.(\w+)'); + for (var name in args) { + if (name == 'role') { + logger.log('module "role" ignored.'); + } + final sourceDir = 'lib/src/page/$name'; + final files = pathOfDirectory(sourceDir); + final pathSafe = safeDirectory(name); + for (var file in files) { + if (file.endsWith('_controller.dart')) { + continue; + } + final lines = readFile(file); + PageModelType pageType; + RegExpMatch matcher; + final ix = + StringHelper.listIndexOf(lines, string: 'PageType = PageModelType'); + if (ix == null) { + logger.log('missing pageType hint in $file'); + continue; + } else { + matcher = regExpPageType.firstMatch(lines[ix]); + if (matcher == null) { + logger.error('cannot recognize page type: ${lines[ix]} in $file'); + continue; + } + } + final moduleCapital = StringHelper.capitalize(matcher.group(1)); + final pageNameCapital = matcher.group(2); + final pageTypeLower = matcher.group(3); + pageType = StringUtils.stringToEnum( + pageTypeLower, PageModelType.values); + if (pageType == null) { + logger.error('cannot recognize page type: ${lines[ix]} in $file'); + continue; + } + if (handledPageType != null && pageType != handledPageType) { + continue; + } + final fnTemplate = UrlHelper.joinPaths( + UrlHelper.parentOf(file).replaceAll(name, 'role'), + 'role_${StringUtils.enumToString(pageType)}_page.dart'); + final templateLines = readFile(fnTemplate); + if (templateLines.isEmpty) { + logger.log('ignoring ${file}: no template found'); + continue; + } + final pageTypeCapital = StringHelper.capitalize(pageTypeLower); + final classFragment = 'Role$pageTypeCapital'; + final converter = (String line) => line + .replaceAll('Role${pageTypeCapital}Page', + '$moduleCapital${pageNameCapital}Page') + .replaceAll('RoleController', '${moduleCapital}Controller') + .replaceAll( + 'role$pageNameCapital', '$name$pageNameCapital'); + modifyPage( + name, + pageType, + lines, + templateLines, + converter, + UrlHelper.joinPaths(baseDirectory, name, UrlHelper.nodeOf(file)), + overwriteConstructor, + pathSafe); + } + } + } + + void modifyPage( + String module, + PageModelType type, + List lines, + List templateLines, + Function(String) converter, + String filename, + bool overwriteConstructors, + String pathSafe) { + final moduleCapital = StringHelper.capitalize(module); + ensureDirectory(UrlHelper.parentOf(filename, trailingSlash: false)); + final output = []; + int ix; + if (overwriteConstructors) { + if (StringHelper.listIndexOf(lines, string: 'EndOfGeneratedCode') != + null) { + StringHelper.addRangeToList(lines, output, + endString: 'BeginOfGeneratedCode', includeEnd: false); + } else { + StringHelper.addRangeToList(templateLines, output, + endString: 'BeginOfGeneratedCode', + includeEnd: false, + converter: converter); + } + StringHelper.addRangeToList(templateLines, output, + startString: 'BeginOfGeneratedCode', + endString: 'EndOfGeneratedCode', + converter: converter); + StringHelper.addRangeToList(lines, output, + startString: 'EndOfGeneratedCode', includeStart: false); + ix = StringHelper.listIndexOf(lines, string: 'EndOfGeneratedCode'); + // -3: possible empty lines at the end + if (ix == null || ix > lines.length - 3) { + StringHelper.addRangeToList(templateLines, output, + startString: 'EndOfGeneratedCode', + includeStart: false, + converter: converter); + } + } else { + StringHelper.addRangeToList(lines, output, + endString: 'BeginOfGeneratedCode', includeEnd: false); + StringHelper.addRangeToList(templateLines, output, + startString: 'BeginOfGeneratedCode', + endString: 'BeginOfCustomizedVars1', + converter: converter); + StringHelper.addRangeToList(lines, output, + startString: 'BeginOfCustomizedVars1', + includeStart: false, + endString: 'EndOfCustomizedVars1', + includeEnd: false); + StringHelper.addRangeToList(templateLines, output, + startString: 'EndOfCustomizedVars1', + endString: 'BeginOfConstructor1', + converter: converter); + StringHelper.addRangeToList(lines, output, + startString: 'BeginOfConstructor1', + includeStart: false, + endString: 'EndOfConstructor1', + includeEnd: false); + StringHelper.addRangeToList(templateLines, output, + startString: 'EndOfConstructor1', + endString: 'BeginOfCall', + converter: converter); + StringHelper.addRangeToList(lines, output, + startString: 'BeginOfCall', + includeStart: false, + endString: 'EndOfCall', + includeEnd: false); + StringHelper.addRangeToList(templateLines, output, + startString: 'EndOfCall', + endString: 'BeginOfCustomizedVars2', + converter: converter); + StringHelper.addRangeToList(lines, output, + startString: 'BeginOfCustomizedVars2', + includeStart: false, + endString: 'EndOfCustomizedVars2', + includeEnd: false); + StringHelper.addRangeToList(templateLines, output, + startString: 'EndOfCustomizedVars2', + endString: 'BeginOfConstructor2', + converter: converter); + StringHelper.addRangeToList(lines, output, + startString: 'BeginOfConstructor2', + includeStart: false, + endString: 'EndOfConstructor2', + includeEnd: false); + StringHelper.addRangeToList(templateLines, output, + startString: 'EndOfConstructor2', + endString: 'EndOfGeneratedCode', + converter: converter); + StringHelper.addRangeToList(lines, output, + startString: 'EndOfGeneratedCode', includeStart: false); + } + ensureDirectory(pathSafe); + final fnSafe = UrlHelper.joinPaths(pathSafe, UrlHelper.nodeOf(filename)); + logger.log('saving to $fnSafe'); + writeFile(fnSafe, lines.join('\n')); + logger.log('writing $filename lines: ${output.length}'); + writeFile(filename, output.join('\n')); + } + + List pathOfDirectory(String path); + + /// Reads a [file] into a list of lines. + List readFile(String file); + + void run(List args) { + final mode = args[0]; + final options = []; + 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; + } + } + + /// Returns the unique name derived from [name] of a directory to save files. + String safeDirectory(String name); + + void usage(String error) { + print('''usage: main [] +: + create-sql [ [...] [] + Generates the DDL ("create table...") statements and the yaml files + describing the insert... SQL statements. + : 'role', 'user' ... + : + -d or --directory=: + the base directory used for the exported files. + help + Display this usage messages. + modify-module [ [...] [] + Modifies the files of the given modules to renew the generated code. + : + --page-type= + Modify only files with this type: 'create', 'change', 'list', 'custom' + --override-constructors + Parts of the constructors will be taken from the template. + Can destroy customized code! Needed if there are changed customized areas. +Examples: +main create-sql role user -d/tmp +main create-sql --directory=/opt/sql-data +main modify-pages role --customize-constructors +main modify-pages --page-type=list +'''); + } + + /// Writes a [content] to a file named [filename]. + void writeFile(String filename, String content); +} diff --git a/lib/src/model/module_model.dart b/lib/src/model/module_model.dart index ac8d7b8..6f28bea 100644 --- a/lib/src/model/module_model.dart +++ b/lib/src/model/module_model.dart @@ -297,7 +297,7 @@ modules: buffer.write('\n WHERE ${table.name}_id=:${table.name}_id;"\n'); } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => name; diff --git a/lib/src/model/page_model.dart b/lib/src/model/page_model.dart index 01bb896..2c93ec1 100644 --- a/lib/src/model/page_model.dart +++ b/lib/src/model/page_model.dart @@ -73,7 +73,7 @@ class PageModel extends ModelBase { return rc; } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => '${module.name}.$name'; @@ -97,7 +97,7 @@ class PageModel extends ModelBase { return rc; } - /// Parses the [map]and stores the data in the instance. + /// Parses the [map] and stores the data in the instance. void parse(Map map) { super.parseBase(map, nameLabel: 'page', required: true); if (name == null) { diff --git a/lib/src/model/section_model.dart b/lib/src/model/section_model.dart index e44c4c7..45f020e 100644 --- a/lib/src/model/section_model.dart +++ b/lib/src/model/section_model.dart @@ -35,7 +35,7 @@ class SectionModel extends WidgetModel { return stringBuffer; } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => section == null ? '${page.name}.$name' : '${section.name}.$name'; @@ -84,7 +84,7 @@ class SectionModel extends WidgetModel { 'Section: unknown "modelType" ${child["modelType"]} in ${fullName()}'); break; } - if (model != null){ + if (model != null) { model.parse(child); } } @@ -102,7 +102,7 @@ class SectionModel extends WidgetModel { 'sectionType', map, SectionModelType.values); checkSuperfluousAttributes( map, - 'buttons children fields modelType section options sectionType' + 'buttonBar children fields modelType section options sectionType' .split(' ')); checkOptionsByRegExpr(regExprOptions); diff --git a/lib/src/model/standard/configuration_model.dart b/lib/src/model/standard/configuration_model.dart index 5377270..eb20373 100644 --- a/lib/src/model/standard/configuration_model.dart +++ b/lib/src/model/standard/configuration_model.dart @@ -119,7 +119,16 @@ class ConfigurationModel extends ModuleModel { 'modelType': 'textField', 'filterType': 'pattern', }, - ] + ], + 'buttonBar': [ + { + 'modelType': 'button', + 'buttonType': 'custom', + 'name': 'new', + 'label': 'Neue Konfiguration', + 'toolTip': 'Erzeugen einer neuen Konfiguration' + }, + ], } ] }, @@ -128,7 +137,7 @@ class ConfigurationModel extends ModuleModel { ConfigurationModel(BaseLogger logger) : super(yamlMap, logger); - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => name; diff --git a/lib/src/model/standard/menu_model.dart b/lib/src/model/standard/menu_model.dart index e3c7687..10c6054 100644 --- a/lib/src/model/standard/menu_model.dart +++ b/lib/src/model/standard/menu_model.dart @@ -61,7 +61,16 @@ class MenuModel extends ModuleModel { { 'modelType': 'allDbFields', }, - ] + ], + 'buttonBar': [ + { + 'modelType': 'button', + 'buttonType': 'custom', + 'name': 'new', + 'label': 'Neues Startmenü', + 'toolTip': 'Erzeugen eines neuen Startmenüs' + }, + ], } ] }, @@ -92,7 +101,7 @@ class MenuModel extends ModuleModel { MenuModel(BaseLogger logger) : super(mapMenu, logger); - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => name; diff --git a/lib/src/model/standard/role_model.dart b/lib/src/model/standard/role_model.dart index 6cb2a39..1001014 100644 --- a/lib/src/model/standard/role_model.dart +++ b/lib/src/model/standard/role_model.dart @@ -103,7 +103,7 @@ class RoleModel extends ModuleModel { ] }; - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => name; diff --git a/lib/src/model/standard/starter_model.dart b/lib/src/model/standard/starter_model.dart index eb090c3..b8a8efd 100644 --- a/lib/src/model/standard/starter_model.dart +++ b/lib/src/model/standard/starter_model.dart @@ -83,7 +83,16 @@ class StarterModel extends ModuleModel { 'toolTip': 'Filter bezüglich des Namens der anzuzeigenden Einträge: Joker "*" (beliebiger String) ist erlaubt.' }, - ] + ], + 'buttonBar': [ + { + 'modelType': 'button', + 'buttonType': 'custom', + 'name': 'new', + 'label': 'Neuer Programmpunkt', + 'toolTip': 'Erzeugen eines neuen Programmpunkts' + }, + ], } ] }, @@ -92,7 +101,7 @@ class StarterModel extends ModuleModel { StarterModel(BaseLogger logger) : super(mapStarter, logger); - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => name; diff --git a/lib/src/model/standard/user_model.dart b/lib/src/model/standard/user_model.dart index 23c6423..14ffdaa 100644 --- a/lib/src/model/standard/user_model.dart +++ b/lib/src/model/standard/user_model.dart @@ -153,7 +153,16 @@ class UserModel extends ModuleModel { 'toolTip': 'Filter bezüglich der Rolle der anzuzeigenden Einträge. "-" bedeutet keine Einschränkung', } - ] + ], + 'buttonBar': [ + { + 'modelType': 'button', + 'buttonType': 'custom', + 'name': 'new', + 'label': 'Neuer Benutzer', + 'toolTip': 'Erzeugen eines neuen Benutzers' + }, + ], } ] }, @@ -179,6 +188,8 @@ class UserModel extends ModuleModel { 'options': 'password', 'validators': 'required', }, + ], + 'buttonBar': [ { 'modelType': 'button', 'buttonType': 'custom', @@ -194,7 +205,7 @@ class UserModel extends ModuleModel { UserModel(BaseLogger logger) : super(mapUser, logger); - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => name; diff --git a/lib/src/model/table_model.dart b/lib/src/model/table_model.dart index a77cabb..c8dc063 100644 --- a/lib/src/model/table_model.dart +++ b/lib/src/model/table_model.dart @@ -67,7 +67,7 @@ class TableModel extends ModelBase { return stringBuffer; } - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => '${module.name}.$name'; diff --git a/lib/src/model/text_model.dart b/lib/src/model/text_model.dart index bc5104c..5d8925f 100644 --- a/lib/src/model/text_model.dart +++ b/lib/src/model/text_model.dart @@ -13,7 +13,7 @@ class TextModel extends WidgetModel { TextModel(SectionModel section, PageModel page, BaseLogger logger) : super(section, page, ModelTypeBones.text, null, logger); - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => '${section.name}.$name'; diff --git a/lib/src/page/application_data.dart b/lib/src/page/application_data.dart index be00740..ecc97af 100644 --- a/lib/src/page/application_data.dart +++ b/lib/src/page/application_data.dart @@ -6,7 +6,7 @@ import '../persistence/persistence_cache.dart'; import '../widget/page_controller_bones.dart'; abstract class FooterBones { - List widgets(PageControllerBones controller); + Widget widget(PageControllerBones controller); } /// Data class for storing parameter to build a page. diff --git a/lib/src/page/configuration/configuration_change_page.dart b/lib/src/page/configuration/configuration_change_page.dart index e0867d0..d8848cf 100644 --- a/lib/src/page/configuration/configuration_change_page.dart +++ b/lib/src/page/configuration/configuration_change_page.dart @@ -3,25 +3,36 @@ import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'configuration_controller.dart'; +const configurationChangePageModule = 'configuration'; +const configurationChangePageName = 'change'; +const configurationChangePageType = PageModelType.change; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class ConfigurationChangePage extends StatefulWidget { final ApplicationData applicationData; final Map initialRow; final logger = Settings().logger; final int primaryId; - //ConfigurationChangePageState lastState; - + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === ConfigurationChangePage(this.primaryId, this.applicationData, this.initialRow, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override ConfigurationChangePageState createState() { + //! === BeginOfCall === final rc = - ConfigurationChangePageState(primaryId, applicationData, initialRow); + ConfigurationChangePageStateCustomized(primaryId, applicationData, initialRow); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -29,25 +40,31 @@ class ConfigurationChangePage extends StatefulWidget { } } -class ConfigurationChangePageState extends State +abstract class ConfigurationChangePageState extends State implements RedrawPage { final ApplicationData applicationData; final int primaryId; final Map initialRow; final GlobalKey _formKey = - GlobalKey(debugLabel: 'configuration_change'); + GlobalKey(debugLabel: '$configurationChangePageModule-$configurationChangePageName'); ConfigurationController controller; - ConfigurationChangePageState( - this.primaryId, this.applicationData, this.initialRow); + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === + ConfigurationChangePageState(this.primaryId, this.applicationData, this.initialRow); + + //! === EndOfConstructor2 === @override Widget build(BuildContext context) { - // controller.buildWidgetList() is called in editForm + controller.beginOfBuild(context); + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Konfiguration ändern'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, @@ -55,21 +72,27 @@ class ConfigurationChangePageState extends State primaryId: primaryId, initialRow: initialRow, )); + //! === EndOfScaffold === } - @override - void initState() { - super.initState(); - controller = ConfigurationController( - _formKey, this, 'change', context, applicationData); - controller.initialize(); - } + /// Customize the page, e.g. modify the default widget list given by the model + void customize(); + @override void dispose() { controller.dispose(); super.dispose(); } + @override + void initState() { + super.initState(); + controller = + ConfigurationController(_formKey, this, 'change', context, applicationData); + controller.initialize(); + customize(); + } + @override void redraw(RedrawReason reason, {String customString, RedrawCallbackFunctionSimple callback}) { @@ -79,3 +102,17 @@ class ConfigurationChangePageState extends State }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class ConfigurationChangePageStateCustomized + extends ConfigurationChangePageState { + ConfigurationChangePageStateCustomized( + int primaryId, ApplicationData applicationData, Map initialRow) + : super(primaryId, applicationData, initialRow); + + @override + void customize() { + // ToDo: write code if needed + } +} diff --git a/lib/src/page/configuration/configuration_create_page.dart b/lib/src/page/configuration/configuration_create_page.dart index 9d74df8..939a529 100644 --- a/lib/src/page/configuration/configuration_create_page.dart +++ b/lib/src/page/configuration/configuration_create_page.dart @@ -2,18 +2,31 @@ import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'configuration_controller.dart'; +const configurationCreatePageModule = 'configuration'; +const configurationCreatePageName = 'create'; +const configurationCreatePageType = PageModelType.create; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class ConfigurationCreatePage extends StatefulWidget { final ApplicationData applicationData; final logger = Settings().logger; + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === ConfigurationCreatePage(this.applicationData, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override ConfigurationCreatePageState createState() { - final rc = ConfigurationCreatePageState(applicationData); + //! === BeginOfCall === + final rc = ConfigurationCreatePageStateCustomized(applicationData); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -21,36 +34,54 @@ class ConfigurationCreatePage extends StatefulWidget { } } -class ConfigurationCreatePageState extends State +abstract class ConfigurationCreatePageState extends State implements RedrawPage { final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'configuration_create'); + GlobalKey(debugLabel: '$configurationCreatePageModule-$configurationCreatePageName'); ConfigurationController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === ConfigurationCreatePageState(this.applicationData); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { - controller.beginOfBuild(context); + controller?.beginOfBuild(context); + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Neue Konfiguration'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(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 dispose() { + controller.dispose(); + super.dispose(); } @override void initState() { super.initState(); - controller = ConfigurationController( - _formKey, this, 'create', context, applicationData); + controller = + ConfigurationController(_formKey, this, configurationCreatePageName, context, applicationData); controller.initialize(); + customize(); } @override @@ -62,3 +93,16 @@ class ConfigurationCreatePageState extends State }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class ConfigurationCreatePageStateCustomized + extends ConfigurationCreatePageState { + ConfigurationCreatePageStateCustomized(ApplicationData applicationData) + : super(applicationData); + + @override + void customize() { + // ToDo: write code if needed + } +} diff --git a/lib/src/page/configuration/configuration_list_page.dart b/lib/src/page/configuration/configuration_list_page.dart index 64913f8..b2ab898 100644 --- a/lib/src/page/configuration/configuration_list_page.dart +++ b/lib/src/page/configuration/configuration_list_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bones/src/widget/view.dart'; import '../../model/page_model.dart'; import '../../widget/list_form.dart'; @@ -6,15 +7,26 @@ import '../../widget/page_controller_bones.dart'; import '../application_data.dart'; import 'configuration_controller.dart'; +const configurationListPageModule = 'configuration'; +const configurationListPageName = 'list'; +const configurationListPageType = PageModelType.list; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class ConfigurationListPage extends StatefulWidget { final ApplicationData applicationData; + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === ConfigurationListPage(this.applicationData, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override ConfigurationListPageState createState() { - // ConfigurationListPageState.setPageData(pageData); - final rc = ConfigurationListPageState(applicationData); + //! === BeginOfCall === + final rc = ConfigurationListPageStateCustomized(applicationData); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -22,23 +34,31 @@ class ConfigurationListPage extends StatefulWidget { } } -class ConfigurationListPageState extends State +abstract class ConfigurationListPageState extends State implements RedrawPage { final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'configuration_list'); + GlobalKey(debugLabel: '$configurationListPageModule-$configurationListPageName'); Iterable rowsDeprecated; ConfigurationController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === ConfigurationListPageState(this.applicationData); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { controller.beginOfBuild(context); + + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Konfigurationen'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: ListForm.listForm( key: _formKey, configuration: applicationData.configuration, @@ -48,44 +68,30 @@ class ConfigurationListPageState extends State showEditIcon: true, pageController: controller, buttons: [ - ButtonBar(alignment: MainAxisAlignment.center, children: [ - controller.searchButton(), - RaisedButton( - child: Text('Neue Konfiguration'), - onPressed: () { - controller.goTo(pageType: PageModelType.create); - }, - ), - ]), + ButtonBar( + alignment: MainAxisAlignment.spaceBetween, + 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 = ConfigurationController( - _formKey, this, 'list', context, applicationData, redrawCallback: - (RedrawReason reason, - {String customString, RedrawCallbackFunctionSimple callback}) { - switch (reason) { - case RedrawReason.fetchList: - controller.buildRows(); - break; - case RedrawReason.callback: - callback(RedrawReason.custom, customString: customString); - setState(() {}); - break; - default: - setState(() {}); - break; - } - }); + controller = + ConfigurationController(_formKey, this, configurationListPageName, context, applicationData); controller.initialize(); + customize(); } @override @@ -97,3 +103,18 @@ class ConfigurationListPageState extends State }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class ConfigurationListPageStateCustomized extends ConfigurationListPageState { + ConfigurationListPageStateCustomized(ApplicationData applicationData) + : super(applicationData); + + @override + void customize() { + final button = controller.page.buttonByName('new'); + button.onPressed = () { + controller.goTo(pageType: PageModelType.create); + }; + } +} diff --git a/lib/src/page/menu/menu_change_page.dart b/lib/src/page/menu/menu_change_page.dart index b259137..6eeebab 100644 --- a/lib/src/page/menu/menu_change_page.dart +++ b/lib/src/page/menu/menu_change_page.dart @@ -3,24 +3,36 @@ import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'menu_controller.dart'; +const menuChangePageModule = 'menu'; +const menuChangePageName = 'change'; +const menuChangePageType = PageModelType.change; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class MenuChangePage extends StatefulWidget { final ApplicationData applicationData; final Map initialRow; final logger = Settings().logger; final int primaryId; - //MenuChangePageState lastState; - + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === MenuChangePage(this.primaryId, this.applicationData, this.initialRow, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override MenuChangePageState createState() { - final rc = MenuChangePageState(primaryId, applicationData, initialRow); + //! === BeginOfCall === + final rc = + MenuChangePageStateCustomized(primaryId, applicationData, initialRow); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -28,24 +40,31 @@ class MenuChangePage extends StatefulWidget { } } -class MenuChangePageState extends State implements RedrawPage { +abstract class MenuChangePageState extends State + implements RedrawPage { final ApplicationData applicationData; final int primaryId; final Map initialRow; final GlobalKey _formKey = - GlobalKey(debugLabel: 'menu_change'); + GlobalKey(debugLabel: '$menuChangePageModule-$menuChangePageName'); MenuController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === MenuChangePageState(this.primaryId, this.applicationData, this.initialRow); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { controller.beginOfBuild(context); - // controller.buildWidgetList() is called in editForm + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Startmenü ändern'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, @@ -53,8 +72,13 @@ class MenuChangePageState extends State implements RedrawPage { primaryId: primaryId, initialRow: initialRow, )); + //! === EndOfScaffold === } + /// Customize the page, e.g. modify the default widget list given by the model + void customize(); + + @override void dispose() { controller.dispose(); super.dispose(); @@ -63,14 +87,10 @@ class MenuChangePageState extends State implements RedrawPage { @override void initState() { super.initState(); - controller = MenuController( - _formKey, - this, - 'change', - context, - applicationData, - ); + controller = + MenuController(_formKey, this, 'change', context, applicationData); controller.initialize(); + customize(); } @override @@ -82,3 +102,16 @@ class MenuChangePageState extends State implements RedrawPage { }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class MenuChangePageStateCustomized extends MenuChangePageState { + MenuChangePageStateCustomized( + int primaryId, ApplicationData applicationData, Map initialRow) + : super(primaryId, applicationData, initialRow); + + @override + void customize() { + // ToDo: write code if needed + } +} diff --git a/lib/src/page/menu/menu_create_page.dart b/lib/src/page/menu/menu_create_page.dart index f9cbcd0..9f8fcad 100644 --- a/lib/src/page/menu/menu_create_page.dart +++ b/lib/src/page/menu/menu_create_page.dart @@ -3,18 +3,31 @@ import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'menu_controller.dart'; +const menuCreatePageModule = 'menu'; +const menuCreatePageName = 'create'; +const menuCreatePageType = PageModelType.create; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class MenuCreatePage extends StatefulWidget { final ApplicationData applicationData; final logger = Settings().logger; + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === MenuCreatePage(this.applicationData, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override MenuCreatePageState createState() { - final rc = MenuCreatePageState(applicationData); + //! === BeginOfCall === + final rc = MenuCreatePageStateCustomized(applicationData); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -22,35 +35,54 @@ class MenuCreatePage extends StatefulWidget { } } -class MenuCreatePageState extends State implements RedrawPage { +abstract class MenuCreatePageState extends State + implements RedrawPage { final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'menu_create'); + GlobalKey(debugLabel: '$menuCreatePageModule-$menuCreatePageName'); MenuController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === MenuCreatePageState(this.applicationData); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { - controller.beginOfBuild(context); + controller?.beginOfBuild(context); + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Neues Startmenü'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(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 dispose() { + controller.dispose(); + super.dispose(); } @override void initState() { super.initState(); controller = - MenuController(_formKey, this, 'create', context, applicationData); + MenuController(_formKey, this, menuCreatePageName, context, applicationData); controller.initialize(); + customize(); } @override @@ -62,3 +94,15 @@ class MenuCreatePageState extends State implements RedrawPage { }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class MenuCreatePageStateCustomized extends MenuCreatePageState { + MenuCreatePageStateCustomized(ApplicationData applicationData) + : super(applicationData); + + @override + void customize() { + // ToDo: write code if needed + } +} diff --git a/lib/src/page/menu/menu_list_page.dart b/lib/src/page/menu/menu_list_page.dart index b7bdf00..6bf709a 100644 --- a/lib/src/page/menu/menu_list_page.dart +++ b/lib/src/page/menu/menu_list_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bones/flutter_bones.dart'; import '../../model/page_model.dart'; import '../../widget/list_form.dart'; @@ -6,15 +7,26 @@ import '../../widget/page_controller_bones.dart'; import '../application_data.dart'; import 'menu_controller.dart'; +const menuListPageModule = 'menu'; +const menuListPageName = 'list'; +const menuListPageType = PageModelType.list; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class MenuListPage extends StatefulWidget { final ApplicationData applicationData; + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === MenuListPage(this.applicationData, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override MenuListPageState createState() { - // MenuListPageState.setPageData(pageData); - final rc = MenuListPageState(applicationData); + //! === BeginOfCall === + final rc = MenuListPageStateCustomized(applicationData); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -22,22 +34,31 @@ class MenuListPage extends StatefulWidget { } } -class MenuListPageState extends State implements RedrawPage { +abstract class MenuListPageState extends State + implements RedrawPage { final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'menu_list'); + GlobalKey(debugLabel: '$menuListPageModule-$menuListPageName'); Iterable rowsDeprecated; MenuController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === MenuListPageState(this.applicationData); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { controller.beginOfBuild(context); + + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Startmenüs'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: ListForm.listForm( key: _formKey, configuration: applicationData.configuration, @@ -47,29 +68,30 @@ class MenuListPageState extends State implements RedrawPage { showEditIcon: true, pageController: controller, buttons: [ - ButtonBar(alignment: MainAxisAlignment.center, children: [ - controller.searchButton(), - RaisedButton( - child: Text('Neues Startmenü'), - onPressed: () { - controller.goTo(pageType: PageModelType.create); - }, - ), - ]), + ButtonBar( + alignment: MainAxisAlignment.spaceBetween, + 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 = - MenuController(_formKey, this, 'list', context, applicationData); + MenuController(_formKey, this, menuListPageName, context, applicationData); controller.initialize(); + customize(); } @override @@ -81,3 +103,18 @@ class MenuListPageState extends State implements RedrawPage { }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class MenuListPageStateCustomized extends MenuListPageState { + MenuListPageStateCustomized(ApplicationData applicationData) + : super(applicationData); + + @override + void customize() { + final button = controller.page.buttonByName('new'); + button.onPressed = () { + controller.goTo(pageType: PageModelType.create); + }; + } +} diff --git a/lib/src/page/role/role_change_page.dart b/lib/src/page/role/role_change_page.dart index 73b942a..cb75dd9 100644 --- a/lib/src/page/role/role_change_page.dart +++ b/lib/src/page/role/role_change_page.dart @@ -4,10 +4,13 @@ import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; import '../application_data.dart'; +import '../../model/page_model.dart'; import 'role_controller.dart'; +const roleChangePageModule = 'role'; +const roleChangePageName = 'create'; +const roleChangePageType = PageModelType.create; //! === BeginOfGeneratedCode: Change only in areas marked as customized -//! pageType: change class RoleChangePage extends StatefulWidget { final ApplicationData applicationData; @@ -43,7 +46,7 @@ abstract class RoleChangePageState extends State final int primaryId; final Map initialRow; final GlobalKey _formKey = - GlobalKey(debugLabel: 'role_change'); + GlobalKey(debugLabel: '$roleChangePageModule-$roleChangePageName'); RoleController controller; @@ -61,8 +64,7 @@ abstract class RoleChangePageState extends State return Scaffold( appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), - persistentFooterButtons: - applicationData.footerBuilder().widgets(controller), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, @@ -76,6 +78,7 @@ abstract class RoleChangePageState extends State /// Customize the page, e.g. modify the default widget list given by the model void customize(); + @override void dispose() { controller.dispose(); super.dispose(); @@ -103,8 +106,8 @@ abstract class RoleChangePageState extends State //! === EndOfGeneratedCode: Below you can change manually: class RoleChangePageStateCustomized extends RoleChangePageState { - RoleChangePageStateCustomized(int primaryId, ApplicationData applicationData, - Map initialRow) + RoleChangePageStateCustomized( + int primaryId, ApplicationData applicationData, Map initialRow) : super(primaryId, applicationData, initialRow); @override diff --git a/lib/src/page/role/role_create_page.dart b/lib/src/page/role/role_create_page.dart index ed578ac..13fe1f2 100644 --- a/lib/src/page/role/role_create_page.dart +++ b/lib/src/page/role/role_create_page.dart @@ -3,11 +3,14 @@ import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'role_controller.dart'; +const roleCreatePageModule = 'role'; +const roleCreatePageName = 'create'; +const roleCreatePageType = PageModelType.create; //! === BeginOfGeneratedCode: Change only in areas marked as customized -//! pageType: change class RoleCreatePage extends StatefulWidget { final ApplicationData applicationData; @@ -37,7 +40,7 @@ abstract class RoleCreatePageState extends State final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'role_create'); + GlobalKey(debugLabel: '$roleCreatePageModule-$roleCreatePageName'); RoleController controller; @@ -55,8 +58,7 @@ abstract class RoleCreatePageState extends State return Scaffold( appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), - persistentFooterButtons: - applicationData.footerBuilder().widgets(controller), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, @@ -68,11 +70,17 @@ abstract class RoleCreatePageState extends State /// Customize the page, e.g. modify the default widget list given by the model void customize(); + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + @override void initState() { super.initState(); controller = - RoleController(_formKey, this, 'create', context, applicationData); + RoleController(_formKey, this, roleCreatePageName, context, applicationData); controller.initialize(); customize(); } diff --git a/lib/src/page/role/role_list_page.dart b/lib/src/page/role/role_list_page.dart index 77af1b7..313f207 100644 --- a/lib/src/page/role/role_list_page.dart +++ b/lib/src/page/role/role_list_page.dart @@ -1,14 +1,16 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bones/flutter_bones.dart'; import '../../model/page_model.dart'; import '../../widget/list_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../widget/view.dart'; import '../application_data.dart'; import 'role_controller.dart'; +const roleListPageModule = 'role'; +const roleListPageName = 'list'; +const roleListPageType = PageModelType.list; //! === BeginOfGeneratedCode: Change only in areas marked as customized -//! pageType: change class RoleListPage extends StatefulWidget { final ApplicationData applicationData; @@ -37,7 +39,7 @@ abstract class RoleListPageState extends State final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'role_list'); + GlobalKey(debugLabel: '$roleListPageModule-$roleListPageName'); Iterable rowsDeprecated; RoleController controller; @@ -56,8 +58,7 @@ abstract class RoleListPageState extends State return Scaffold( appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), - persistentFooterButtons: - applicationData.footerBuilder().widgets(controller), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: ListForm.listForm( key: _formKey, configuration: applicationData.configuration, @@ -67,9 +68,12 @@ abstract class RoleListPageState extends State showEditIcon: true, pageController: controller, buttons: [ - ButtonBar(alignment: MainAxisAlignment.center, - children: View().modelsToWidgets(controller.page.sections[0].buttonBar, controller), - )], + ButtonBar( + alignment: MainAxisAlignment.spaceBetween, + children: View().modelsToWidgets( + controller.page.sections[0].buttonBar, controller), + ) + ], filters: controller.modelList, errorMessage: applicationData.lastErrorMessage(controller.page.fullName()), @@ -85,7 +89,7 @@ abstract class RoleListPageState extends State void initState() { super.initState(); controller = - RoleController(_formKey, this, 'list', context, applicationData); + RoleController(_formKey, this, roleListPageName, context, applicationData); controller.initialize(); customize(); } @@ -112,6 +116,5 @@ class RoleListPageStateCustomized extends RoleListPageState { button.onPressed = () { controller.goTo(pageType: PageModelType.create); }; - controller.modelList.addModel(button.name, button); } } diff --git a/lib/src/page/starter/starter_change_page.dart b/lib/src/page/starter/starter_change_page.dart index 453c516..ea8001f 100644 --- a/lib/src/page/starter/starter_change_page.dart +++ b/lib/src/page/starter/starter_change_page.dart @@ -3,24 +3,36 @@ import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'starter_controller.dart'; +const starterChangePageModule = 'starter'; +const starterChangePageName = 'change'; +const starterChangePageType = PageModelType.change; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class StarterChangePage extends StatefulWidget { final ApplicationData applicationData; final Map initialRow; final logger = Settings().logger; final int primaryId; - //StarterChangePageState lastState; - + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === StarterChangePage(this.primaryId, this.applicationData, this.initialRow, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override StarterChangePageState createState() { - final rc = StarterChangePageState(primaryId, applicationData, initialRow); + //! === BeginOfCall === + final rc = + StarterChangePageStateCustomized(primaryId, applicationData, initialRow); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -28,7 +40,7 @@ class StarterChangePage extends StatefulWidget { } } -class StarterChangePageState extends State +abstract class StarterChangePageState extends State implements RedrawPage { final ApplicationData applicationData; final int primaryId; @@ -38,15 +50,21 @@ class StarterChangePageState extends State StarterController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === StarterChangePageState(this.primaryId, this.applicationData, this.initialRow); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { controller.beginOfBuild(context); - // controller.buildWidgetList() is called in editForm + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Startmenü ändern'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, @@ -54,8 +72,12 @@ class StarterChangePageState extends State 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(); @@ -64,14 +86,10 @@ class StarterChangePageState extends State @override void initState() { super.initState(); - controller = StarterController( - _formKey, - this, - 'change', - context, - applicationData, - ); + controller = + StarterController(_formKey, this, 'change', context, applicationData); controller.initialize(); + customize(); } @override @@ -83,3 +101,16 @@ class StarterChangePageState extends State }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class StarterChangePageStateCustomized extends StarterChangePageState { + StarterChangePageStateCustomized( + int primaryId, ApplicationData applicationData, Map initialRow) + : super(primaryId, applicationData, initialRow); + + @override + void customize() { + // ToDo: write code if needed + } +} diff --git a/lib/src/page/starter/starter_create_page.dart b/lib/src/page/starter/starter_create_page.dart index eab2be4..3c47cb3 100644 --- a/lib/src/page/starter/starter_create_page.dart +++ b/lib/src/page/starter/starter_create_page.dart @@ -3,18 +3,31 @@ import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'starter_controller.dart'; +const starterCreatePageModule = 'starter'; +const starterCreatePageName = 'create'; +const starterCreatePageType = PageModelType.create; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class StarterCreatePage extends StatefulWidget { final ApplicationData applicationData; final logger = Settings().logger; + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === StarterCreatePage(this.applicationData, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override StarterCreatePageState createState() { - final rc = StarterCreatePageState(applicationData); + //! === BeginOfCall === + final rc = StarterCreatePageStateCustomized(applicationData); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -22,36 +35,54 @@ class StarterCreatePage extends StatefulWidget { } } -class StarterCreatePageState extends State +abstract class StarterCreatePageState extends State implements RedrawPage { final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'starter_create'); + GlobalKey(debugLabel: '$starterCreatePageModule-$starterCreatePageName'); StarterController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === StarterCreatePageState(this.applicationData); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { - controller.beginOfBuild(context); + controller?.beginOfBuild(context); + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Neues Startmenü'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(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 dispose() { + controller.dispose(); + super.dispose(); } @override void initState() { super.initState(); controller = - StarterController(_formKey, this, 'create', context, applicationData); + StarterController(_formKey, this, starterCreatePageName, context, applicationData); controller.initialize(); + customize(); } @override @@ -63,3 +94,15 @@ class StarterCreatePageState extends State }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class StarterCreatePageStateCustomized extends StarterCreatePageState { + StarterCreatePageStateCustomized(ApplicationData applicationData) + : super(applicationData); + + @override + void customize() { + // ToDo: write code if needed + } +} diff --git a/lib/src/page/starter/starter_list_page.dart b/lib/src/page/starter/starter_list_page.dart index 20e0f06..41d00ed 100644 --- a/lib/src/page/starter/starter_list_page.dart +++ b/lib/src/page/starter/starter_list_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bones/flutter_bones.dart'; import '../../model/page_model.dart'; import '../../widget/list_form.dart'; @@ -6,15 +7,26 @@ import '../../widget/page_controller_bones.dart'; import '../application_data.dart'; import 'starter_controller.dart'; +const starterListPageModule = 'starter'; +const starterListPageName = 'list'; +const starterListPageType = PageModelType.list; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class StarterListPage extends StatefulWidget { final ApplicationData applicationData; + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === StarterListPage(this.applicationData, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override StarterListPageState createState() { - // StarterListPageState.setPageData(pageData); - final rc = StarterListPageState(applicationData); + //! === BeginOfCall === + final rc = StarterListPageStateCustomized(applicationData); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -22,56 +34,64 @@ class StarterListPage extends StatefulWidget { } } -class StarterListPageState extends State +abstract class StarterListPageState extends State implements RedrawPage { final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'starter_list'); + GlobalKey(debugLabel: '$starterListPageModule-$starterListPageName'); Iterable rowsDeprecated; StarterController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === StarterListPageState(this.applicationData); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { controller.beginOfBuild(context); + + //! === BeginOfScaffold === 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: [ - 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)); + appBar: applicationData.appBarBuilder(controller.page.title), + drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), + 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: [ + ButtonBar( + alignment: MainAxisAlignment.spaceBetween, + 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 = - StarterController(_formKey, this, 'list', context, applicationData); + StarterController(_formKey, this, starterListPageName, context, applicationData); controller.initialize(); + customize(); } @override @@ -83,3 +103,18 @@ class StarterListPageState extends State }); } } + +//! === EndOfGeneratedCode: Below you can change manually: + +class StarterListPageStateCustomized extends StarterListPageState { + StarterListPageStateCustomized(ApplicationData applicationData) + : super(applicationData); + + @override + void customize() { + final button = controller.page.buttonByName('new'); + button.onPressed = () { + controller.goTo(pageType: PageModelType.create); + }; + } +} diff --git a/lib/src/page/user/user_change_page.dart b/lib/src/page/user/user_change_page.dart index e60bea7..984fcb2 100644 --- a/lib/src/page/user/user_change_page.dart +++ b/lib/src/page/user/user_change_page.dart @@ -4,12 +4,15 @@ import '../../helper/settings.dart'; import '../../model/button_model.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'user_controller.dart'; import 'user_password_page.dart'; -//! === BeginOfGeneratedCode: Below you can change manually: -//! pageType: change +const userChangePageModule = 'user'; +const userChangePageName = 'change'; +const userChangePageType = PageModelType.change; +//! === BeginOfGeneratedCode: Change only in areas marked as customized class UserChangePage extends StatefulWidget { final ApplicationData applicationData; @@ -45,7 +48,7 @@ abstract class UserChangePageState extends State final int primaryId; final Map initialRow; final GlobalKey _formKey = - GlobalKey(debugLabel: 'user_change'); + GlobalKey(debugLabel: '$userChangePageModule-$userChangePageName'); UserController controller; @@ -63,8 +66,7 @@ abstract class UserChangePageState extends State return Scaffold( appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), - persistentFooterButtons: - applicationData.footerBuilder().widgets(controller), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, @@ -78,6 +80,7 @@ abstract class UserChangePageState extends State /// Customize the page, e.g. modify the default widget list given by the model void customize(); + @override void dispose() { controller.dispose(); super.dispose(); @@ -105,8 +108,8 @@ abstract class UserChangePageState extends State //! === EndOfGeneratedCode: Below you can change manually: class UserChangePageStateCustomized extends UserChangePageState { - UserChangePageStateCustomized(int primaryId, ApplicationData applicationData, - Map initialRow) + UserChangePageStateCustomized( + int primaryId, ApplicationData applicationData, Map initialRow) : super(primaryId, applicationData, initialRow); @override diff --git a/lib/src/page/user/user_create_page.dart b/lib/src/page/user/user_create_page.dart index 09689a2..9dcb2ec 100644 --- a/lib/src/page/user/user_create_page.dart +++ b/lib/src/page/user/user_create_page.dart @@ -3,11 +3,14 @@ import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'user_controller.dart'; -//! === BeginOfGeneratedCode: Below you can change manually: -//! pageType: change +const userCreatePageModule = 'user'; +const userCreatePageName = 'create'; +const userCreatePageType = PageModelType.create; +//! === BeginOfGeneratedCode: Change only in areas marked as customized class UserCreatePage extends StatefulWidget { final ApplicationData applicationData; @@ -37,7 +40,7 @@ abstract class UserCreatePageState extends State final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'user_create'); + GlobalKey(debugLabel: '$userCreatePageModule-$userCreatePageName'); UserController controller; @@ -53,10 +56,9 @@ abstract class UserCreatePageState extends State 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), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, @@ -68,6 +70,12 @@ abstract class UserCreatePageState extends State /// Customize the page, e.g. modify the default widget list given by the model void customize(); + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + @override void initState() { super.initState(); diff --git a/lib/src/page/user/user_list_page.dart b/lib/src/page/user/user_list_page.dart index 16e6939..a537dc9 100644 --- a/lib/src/page/user/user_list_page.dart +++ b/lib/src/page/user/user_list_page.dart @@ -7,8 +7,10 @@ import '../../widget/page_controller_bones.dart'; import '../application_data.dart'; import 'user_controller.dart'; -//! === BeginOfGeneratedCode: Below you can change manually: -//! pageType: change +const userListPageModule = 'user'; +const userListPageName = 'list'; +const userListPageType = PageModelType.list; +//! === BeginOfGeneratedCode: Change only in areas marked as customized class UserListPage extends StatefulWidget { final ApplicationData applicationData; @@ -37,7 +39,7 @@ abstract class UserListPageState extends State final ApplicationData applicationData; final GlobalKey _formKey = - GlobalKey(debugLabel: 'user_list'); + GlobalKey(debugLabel: '$userListPageModule-$userListPageName'); Iterable rowsDeprecated; UserController controller; @@ -54,10 +56,9 @@ abstract class UserListPageState extends State //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Rollen'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), - persistentFooterButtons: - applicationData.footerBuilder().widgets(controller), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: ListForm.listForm( key: _formKey, configuration: applicationData.configuration, @@ -67,15 +68,11 @@ abstract class UserListPageState extends State showEditIcon: true, pageController: controller, buttons: [ - ButtonBar(alignment: MainAxisAlignment.center, children: [ - controller.searchButton(), - RaisedButton( - child: Text('Neuer Benutzer'), - onPressed: () { - controller.goTo(pageType: PageModelType.create); - }, - ), - ]), + ButtonBar( + alignment: MainAxisAlignment.spaceBetween, + children: View().modelsToWidgets( + controller.page.sections[0].buttonBar, controller), + ) ], filters: controller.modelList, errorMessage: @@ -92,7 +89,7 @@ abstract class UserListPageState extends State void initState() { super.initState(); controller = - UserController(_formKey, this, 'list', context, applicationData); + UserController(_formKey, this, userListPageName, context, applicationData); controller.initialize(); customize(); } @@ -115,6 +112,9 @@ class UserListPageStateCustomized extends UserListPageState { @override void customize() { - // ToDo: write code if needed + final button = controller.page.buttonByName('new'); + button.onPressed = () { + controller.goTo(pageType: PageModelType.create); + }; } } diff --git a/lib/src/page/user/user_login_page.dart b/lib/src/page/user/user_login_page.dart index abf3565..fd7d9d9 100644 --- a/lib/src/page/user/user_login_page.dart +++ b/lib/src/page/user/user_login_page.dart @@ -1,26 +1,35 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../../helper/settings.dart'; import '../../model/button_model.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'hash.dart'; import 'user_controller.dart'; -// === BeginOfGeneratedCode: Do not change manually +const userLoginPageModule = 'user'; +const userLoginPageName = 'login'; +const userLoginPageType = PageModelType.create; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class UserLoginPage extends StatefulWidget { final ApplicationData applicationData; final logger = Settings().logger; - //UserLoginPageState lastState; - + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === UserLoginPage(this.applicationData, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override UserLoginPageState createState() { + //! === BeginOfCall === final rc = UserLoginPageStateCustomized(applicationData); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -31,29 +40,39 @@ class UserLoginPage extends StatefulWidget { abstract class UserLoginPageState extends State implements RedrawPage { final ApplicationData applicationData; + final GlobalKey _formKey = - GlobalKey(debugLabel: 'user.login'); + GlobalKey(debugLabel: '$userLoginPageModule-$userLoginPageName'); UserController controller; + //! === BeginOfCustomizedVars2 === + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === UserLoginPageState(this.applicationData); + //! === EndOfConstructor2 === + @override Widget build(BuildContext context) { - controller.beginOfBuild(context); + controller?.beginOfBuild(context); + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Anmelden'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, configuration: applicationData.configuration, - primaryId: 0, )); + //! === EndOfScaffold === } + /// Customize the page, e.g. modify the default widget list given by the model void customize(); + @override void dispose() { controller.dispose(); super.dispose(); @@ -62,8 +81,8 @@ abstract class UserLoginPageState extends State @override void initState() { super.initState(); - controller = - UserController(_formKey, this, 'login', context, applicationData); + controller = UserController( + _formKey, this, userLoginPageName, context, applicationData); controller.initialize(); customize(); } @@ -77,7 +96,8 @@ abstract class UserLoginPageState extends State }); } } -// === EndOfGeneratedCode: Do not change manually + +//! === EndOfGeneratedCode: Below you can change manually: class UserLoginPageStateCustomized extends UserLoginPageState { UserLoginPageStateCustomized(ApplicationData applicationData) @@ -88,7 +108,6 @@ class UserLoginPageStateCustomized extends UserLoginPageState { if (_formKey.currentState.validate()) { _formKey.currentState.save(); final user = controller.page.fieldByName('user').value; - final params = { ':user': user, }; diff --git a/lib/src/page/user/user_password_page.dart b/lib/src/page/user/user_password_page.dart index cedfec3..950d232 100644 --- a/lib/src/page/user/user_password_page.dart +++ b/lib/src/page/user/user_password_page.dart @@ -4,27 +4,38 @@ import '../../helper/settings.dart'; import '../../model/button_model.dart'; import '../../widget/edit_form.dart'; import '../../widget/page_controller_bones.dart'; +import '../../model/page_model.dart'; import '../application_data.dart'; import 'hash.dart'; import 'user_controller.dart'; +const userPasswordPageModule = 'user'; +const userPasswordPageName = 'password'; +const userPasswordPageType = PageModelType.change; +//! === BeginOfGeneratedCode: Change only in areas marked as customized + class UserPasswordPage extends StatefulWidget { final ApplicationData applicationData; final Map initialRow; final logger = Settings().logger; final int primaryId; - final String userName; - - //UserPasswordPageState lastState; + //! === BeginOfCustomizedVars1 === + final String userName; + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === UserPasswordPage( this.primaryId, this.userName, this.applicationData, this.initialRow, {Key key}) : super(key: key); + //! === EndOfConstructor1 === + @override UserPasswordPageState createState() { - final rc = UserPasswordPageState(primaryId, this.userName, applicationData); + //! === BeginOfCall === + final rc = UserPasswordPageStateCustomized(primaryId, this.userName, applicationData, initialRow); + //! === EndOfCall === /// for unittests: applicationData.lastModuleState = rc; @@ -32,32 +43,77 @@ class UserPasswordPage extends StatefulWidget { } } -class UserPasswordPageState extends State +abstract class UserPasswordPageState extends State implements RedrawPage { final ApplicationData applicationData; final int primaryId; - final String userName; final GlobalKey _formKey = GlobalKey(debugLabel: 'user.password'); + final Map initialRow; UserController controller; - UserPasswordPageState(this.primaryId, this.userName, this.applicationData); + //! === BeginOfCustomizedVars2 === + final String userName; + //! === EndOfCustomizedVars2 === + //! === BeginOfConstructor2 === + UserPasswordPageState(this.primaryId, this.userName, this.applicationData, this.initialRow); + //! === EndOfConstructor2 === @override Widget build(BuildContext context) { controller.beginOfBuild(context); + //! === BeginOfScaffold === return Scaffold( - appBar: applicationData.appBarBuilder('Passwort ändern'), + appBar: applicationData.appBarBuilder(controller.page.title), drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), body: EditForm.editForm( key: _formKey, pageController: controller, configuration: applicationData.configuration, primaryId: primaryId, + initialRow: initialRow, )); + //! === EndOfScaffold === + } + + /// Customize the page, e.g. modify the default widget list given by the model + void customize(); + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + controller = + UserController(_formKey, this, userPasswordPageName, context, applicationData); + controller.initialize(); + customize(); + } + + @override + void redraw(RedrawReason reason, + {String customString, RedrawCallbackFunctionSimple callback}) { + setState(() { + controller.afterSetState(reason, + customString: customString, callback: callback); + }); } +} +//! === EndOfGeneratedCode: Below you can change manually: + +class UserPasswordPageStateCustomized extends UserPasswordPageState { + UserPasswordPageStateCustomized( + int primaryId, String userName, ApplicationData applicationData, Map initialRow) + : super(primaryId, userName, applicationData, initialRow); + + @override void customize() { controller.placeholders['user'] = userName; ButtonModel button = controller.page.buttonByName('store'); @@ -85,27 +141,4 @@ class UserPasswordPageState extends State } }; } - - void dispose() { - controller.dispose(); - super.dispose(); - } - - @override - void initState() { - super.initState(); - controller = - UserController(_formKey, this, 'password', context, applicationData); - controller.initialize(); - customize(); - } - - @override - void redraw(RedrawReason reason, - {String customString, RedrawCallbackFunctionSimple callback}) { - setState(() { - controller.afterSetState(reason, - customString: customString, callback: callback); - }); - } } diff --git a/lib/src/private/bfooter.dart b/lib/src/private/bfooter.dart index c13753b..e21df02 100644 --- a/lib/src/private/bfooter.dart +++ b/lib/src/private/bfooter.dart @@ -4,26 +4,24 @@ import 'package:flutter_bones/src/widget/page_controller_bones.dart'; import 'package:url_launcher/url_launcher.dart'; class BFooter implements FooterBones { - List widgets(PageControllerBones controller) { - final rc = [ - Row(children: [ - 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}'), - ]) - ]; + Widget widget(PageControllerBones controller) { + final rc = ButtonBar(alignment: MainAxisAlignment.spaceBetween, children: [ + 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'), diff --git a/lib/src/widget/edit_form.dart b/lib/src/widget/edit_form.dart index 292b72c..ec50521 100644 --- a/lib/src/widget/edit_form.dart +++ b/lib/src/widget/edit_form.dart @@ -24,8 +24,8 @@ class EditForm { pageController.buildModelList(initialRow); final widgets = pageController.getWidgets(); final view = View(); - final buttons = - view.modelsToWidgets(pageController.page.sections[0].buttonBar, pageController); + final buttons = view.modelsToWidgets( + pageController.page.sections[0].buttonBar, pageController); return Form( key: key, child: Card( diff --git a/lib/src/widget/view.dart b/lib/src/widget/view.dart index 446b36a..f76f408 100644 --- a/lib/src/widget/view.dart +++ b/lib/src/widget/view.dart @@ -279,7 +279,9 @@ class View { /// Returns a form with the properties given by the [sectionModel] /// [formKey] identifies the form. Used for form validation and saving. Form simpleForm( - {SectionModel sectionModel, PageControllerBones controller, Key formKey}) { + {SectionModel sectionModel, + PageControllerBones controller, + Key formKey}) { assert(formKey != null); final padding = widgetConfiguration.asFloat('form.card.padding', defaultValue: 16.0); diff --git a/model_tool/lib/main.dart b/model_tool/lib/main.dart index c67d095..b3331a5 100644 --- a/model_tool/lib/main.dart +++ b/model_tool/lib/main.dart @@ -1,11 +1,12 @@ import 'package:dart_bones/dart_bones.dart'; import 'package:flutter_bones_tool/src/model/model_helper.dart'; -import 'package:flutter_bones_tool/src/model_tools.dart'; +import 'package:flutter_bones_tool/src/model/model_tool.dart'; +import 'package:flutter_bones_tool/src/model_tool_io.dart'; void main(List argv) async { final logger = MemoryLogger(LEVEL_FINE); final ModelHelper modelHelper = ModelHelper(); - final ModelTools modelTools = ModelTools(modelHelper, logger); + final ModelTool modelTools = ModelToolIo(modelHelper, logger); if (argv.isEmpty) { argv = ['export-sql']; } diff --git a/model_tool/lib/src/model_tool_io.dart b/model_tool/lib/src/model_tool_io.dart new file mode 100644 index 0000000..cbc744d --- /dev/null +++ b/model_tool/lib/src/model_tool_io.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:dart_bones/dart_bones.dart'; +import 'package:flutter_bones_tool/src/model/model_helper.dart'; +import 'package:flutter_bones_tool/src/model/model_tool.dart'; + +/// Completes the ModelTool with io specific functionality. +class ModelToolIo extends ModelTool { + ModelToolIo(ModelHelper modelHelper, BaseLogger logger) + : super(modelHelper, logger); + + @override + void ensureDirectory(String path) { + FileSync.ensureDirectory(path); + } + + @override + List pathOfDirectory(String path) { + final rc = Directory(path).listSync().map((entry) => entry.path).toList(); + return rc; + } + + @override + readFile(String file) { + final rc = FileSync.fileAsList(file); + return rc; + } + + @override + String safeDirectory(String name) { + final rc = FileSync.tempDirectory( + name + + '.' + + (DateTime.now().millisecondsSinceEpoch / 1000 % 86400) + .round() + .toString(), + subDirs: 'model_tools'); + return rc; + } + + @override + void writeFile(String filename, String content) { + FileSync.toFile(filename, content); + } +} diff --git a/model_tool/lib/src/model_tools.dart b/model_tool/lib/src/model_tools.dart deleted file mode 100644 index 8fb97f6..0000000 --- a/model_tool/lib/src/model_tools.dart +++ /dev/null @@ -1,239 +0,0 @@ -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 lines, StringBuffer buffer, - {String start, - bool includeStart = true, - String end, - bool includeEnd = true, - Map 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 args, List 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 args, List 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( - 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 lines, - List 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 = { - '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 args) { - final mode = args[0]; - final options = []; - 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 [] -: - create-sql [ [...] [] - Generates the DDL ("create table...") statements and the yaml files - describing the insert... SQL statements. - : 'role', 'user' ... - : - -d or --directory=: - the base directory used for the exported files. - help - Display this usage messages. - modify-module [ [...] - 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 -'''); - } -} diff --git a/model_tool/pubspec.yaml b/model_tool/pubspec.yaml index 25684ba..c4dacc3 100644 --- a/model_tool/pubspec.yaml +++ b/model_tool/pubspec.yaml @@ -29,6 +29,12 @@ dependencies: # cupertino_icons: ^1.0.0 dev_dependencies: + pedantic: ^1.8.0 + test: ^1.6.0 + mockito: ^4.1.1 + test_coverage: ^0.4.2 + flutter_test: + sdk: flutter # flutter_test: # sdk: flutter diff --git a/model_tool/test/model_tool_test.dart b/model_tool/test/model_tool_test.dart new file mode 100644 index 0000000..3e554a2 --- /dev/null +++ b/model_tool/test/model_tool_test.dart @@ -0,0 +1,17 @@ +import 'package:flutter_bones_tool/src/model/model_helper.dart'; +import 'package:flutter_bones_tool/src/model_tool_io.dart'; +import 'package:test/test.dart'; +import 'package:dart_bones/dart_bones.dart'; + +void main() { + final logger = MemoryLogger(LEVEL_FINE); + group('modify-modules', () { + test('modify-modules-std', () { + logger.clear(); + final helper = ModelHelper(); + final tool = ModelToolIo(helper, logger); + String target = FileSync.tempDirectory('module_tool_test'); + tool.modifyModule(['user'], ['--directory=$target']); + }); + }); +} diff --git a/pubspec.yaml b/pubspec.yaml index fd62faa..be6d207 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,13 +35,12 @@ dependencies: # cupertino_icons: ^1.0.0 dev_dependencies: - flutter_test: - sdk: flutter pedantic: ^1.8.0 test: ^1.6.0 mockito: ^4.1.1 test_coverage: ^0.4.2 - + flutter_test: + sdk: flutter # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/helpers/string_helper_test.dart b/test/helpers/string_helper_test.dart index e33d284..41d8e1b 100644 --- a/test/helpers/string_helper_test.dart +++ b/test/helpers/string_helper_test.dart @@ -49,7 +49,7 @@ void main() { expect( StringHelper.replacePlaceholders( 'a: ~aa~ b: ~b c: ~c~ ~d~', {'aa': 'x', 'b': 'y', 'c': 'zz'}, - syntaxPlaceholder: r'~(\w+)~'), + syntaxPlaceholder: r'~(\w+)~'), equals('a: x b: ~b c: zz ~d~')); }); }); @@ -142,8 +142,8 @@ void main() { expect(options, equals([])); }); }); - group('StringList', (){ - test('listIndexOf-string', (){ + group('StringList', () { + test('listIndexOf-string', () { final list = ['a', 'bab', 'cAC']; expect(StringHelper.listIndexOf(list, string: 'b'), equals(1)); expect(StringHelper.listIndexOf(list, string: 'a'), equals(0)); @@ -151,16 +151,147 @@ void main() { expect(StringHelper.listIndexOf(list, string: 'x'), isNull); expect(StringHelper.listIndexOf(null, string: 'x'), isNull); }); - test('listIndexOf-regEx', (){ + test('listIndexOf-regEx', () { final list = ['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'a', caseSensitive: false)), + equals(0)); expect(StringHelper.listIndexOf(list, regExp: RegExp(r'd')), isNull); expect(StringHelper.listIndexOf(null, regExp: RegExp(r'd')), isNull); }); }); + group('addRangeToList', () { + test('addRangeToList-String', () { + List output; + final list = ['a', '-- bab', 'cAC', '123']; + expect(StringHelper.addRangeToList(list, null, endString: 'b').join('\n'), + equals('''a +-- bab''')); + expect( + StringHelper.addRangeToList(list, output, + endString: 'b', includeEnd: false) + .join('\n'), + equals('''a''')); + expect( + StringHelper.addRangeToList(list, output, startString: 'C') + .join('\n'), + equals('''cAC +123''')); + expect( + StringHelper.addRangeToList(list, output, + startString: 'C', includeStart: false) + .join('\n'), + equals('''123''')); + expect( + StringHelper.addRangeToList(list, output, + startString: 'b', endString: '2') + .join('\n'), + equals('''-- bab +cAC +123''')); + expect( + StringHelper.addRangeToList(list, output, + startString: 'b', + includeStart: false, + endString: '2', + includeEnd: false) + .join('\n'), + equals('''cAC''')); + }); + test('addRangeToList-regExp', () { + List output; + final list = ['a', '-- bab', 'cAC', '123']; + expect( + StringHelper.addRangeToList(list, null, endPattern: 'b').join('\n'), + equals('''a +-- bab''')); + expect( + StringHelper.addRangeToList(list, output, + endPattern: 'b', includeEnd: false) + .join('\n'), + equals('''a''')); + expect( + StringHelper.addRangeToList(list, output, startPattern: 'C') + .join('\n'), + equals('''cAC +123''')); + expect( + StringHelper.addRangeToList(list, output, + startPattern: '[C]', includeStart: false) + .join('\n'), + equals('''123''')); + expect( + StringHelper.addRangeToList(list, output, + startPattern: 'b', endPattern: '2') + .join('\n'), + equals('''-- bab +cAC +123''')); + expect( + StringHelper.addRangeToList(list, output, + startPattern: '[b]', + includeStart: false, + endPattern: r'\d', + includeEnd: false) + .join('\n'), + equals('''cAC''')); + }); + test('addRangeToList-firstIndex', () { + List output; + final list = ['a', '-- bab', 'cAC', '123AC']; + expect( + StringHelper.addRangeToList(list, null, endString: 'a', firstIndex: 1) + .join('\n'), + equals('''-- bab''')); + expect( + StringHelper.addRangeToList(list, output, + firstIndex: -1, startString: 'A') + .join('\n'), + equals('''123AC''')); + }); + test('addRangeToList-lastIndexIncluded', () { + List output; + final list = ['a1', 'a2', 'a3', 'a4']; + expect( + StringHelper.addRangeToList(list, null, + startString: 'a2', lastIndexIncluded: 2) + .join('\n'), + equals('a2\na3')); + expect( + StringHelper.addRangeToList(list, output, + lastIndexIncluded: -2, startString: 'a3') + .join('\n'), + equals('a3')); + }); + test('addRangeToList-lastIndexExcluded', () { + List output; + final list = ['a1', 'a2', 'a3', 'a4']; + expect( + StringHelper.addRangeToList(list, null, + startString: 'a2', lastIndexExcluded: 2) + .join('\n'), + equals('a2')); + expect( + StringHelper.addRangeToList(list, output, + lastIndexExcluded: -2, startString: 'a3') + .join('\n'), + equals('')); + }); + test('addRangeToList-converter', () { + List output; + final list = ['a1', 'a2', 'a3', 'a4']; + expect( + StringHelper.addRangeToList(list, null, + startRegExp: RegExp('[2-3]'), + endRegExp: RegExp(r'[3-4]'), + converter: (input) => input.toUpperCase()).join('\n'), + equals('A2\nA3')); + }); + }); } diff --git a/test/model/db_model_test.dart b/test/model/db_model_test.dart index 8331bb0..0950f96 100644 --- a/test/model/db_model_test.dart +++ b/test/model/db_model_test.dart @@ -273,7 +273,7 @@ Map cloneOfMap(Map map) { class Demo1 extends ModuleModel { Demo1(Map map, BaseLogger logger) : super(map, logger); - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => name; } diff --git a/test/model/model_test.dart b/test/model/model_test.dart index 2d630ec..5f14f51 100644 --- a/test/model/model_test.dart +++ b/test/model/model_test.dart @@ -677,7 +677,7 @@ Map cloneOfMap(Map map) { class Demo1 extends ModuleModel { Demo1(Map map, BaseLogger logger) : super(map, logger); - /// Returns the name including the names of the parent + /// Returns the name including the names of the parents. @override String fullName() => name; } diff --git a/test/tool/tool_test.dart b/test/tool/tool_test.dart index 881d0d3..cc616e4 100644 --- a/test/tool/tool_test.dart +++ b/test/tool/tool_test.dart @@ -1,8 +1,13 @@ +import 'dart:io'; + 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'; +import '../../lib/src/model/model_helper.dart' as mh; +import '../../lib/src/model/model_tool.dart'; + void main() { final logger = MemoryLogger(LEVEL_FINE); group('sql', () { @@ -67,7 +72,7 @@ modules: ''')); }); test('standard_modules', () { - ModelHelper helper = ModelHelper(); + final helper = mh.ModelHelper(); logger.clear(); final dir = FileSync.tempDirectory('data', subDirs: 'unittest'); for (var name in helper.moduleNames()) { @@ -80,10 +85,228 @@ modules: }); test('standard_modules-errors', () { logger.clear(); - final helper = ModelHelper(); + final helper = mh.ModelHelper(); final module = helper.moduleByName('not-exists', logger); expect(module, isNull); expect(logger.contains('unknown standard module: not-exists'), isTrue); }); }); + group('modify-modules', () { + test('modify-modules-std', () { + logger.clear(); + final helper = mh.ModelHelper(); + final tool = ModelToolIo(helper, logger); + String target = FileSync.tempDirectory('model_tool_test'); + tool.modifyModule([], ['--directory=$target']); + expect(logger.errors.length, equals(0)); + expect(tool.fileCache['/tmp/model_tool_test/user/user_change_page.dart'], + equals(bodyUserChangePage)); + expect( + tool.fileCache['/tmp/model_tool_test/user/user_create_page.dart'] + .length, + equals(2756)); + expect( + tool.fileCache['/tmp/model_tool_test/user/user_list_page.dart'] + .length, + equals(3455)); + expect( + tool.fileCache['/tmp/model_tool_test/configuration/configuration_create_page.dart'] + .length, + equals(2885)); + expect( + tool.fileCache['/tmp/model_tool_test/configuration/configuration_change_page.dart'] + .length, + equals(3285)); + expect( + tool.fileCache['/tmp/model_tool_test/configuration/configuration_list_page.dart'] + .length, + equals(3583)); + }); + test('modify-modules-overwrite-constructors', () { + logger.clear(); + final helper = mh.ModelHelper(); + final tool = ModelToolIo(helper, logger); + String target = FileSync.tempDirectory('model_tool_test'); + tool.modifyModule( + ['user'], ['--directory=$target', '--overwrite-constructors']); + expect(logger.errors.length, equals(0)); + expect(tool.fileCache['/tmp/model_tool_test/user/user_change_page.dart'], + equals(bodyUserChangePage)); + expect( + tool.fileCache['/tmp/model_tool_test/user/user_create_page.dart'] + .length, + equals(2756)); + expect( + tool.fileCache['/tmp/model_tool_test/user/user_list_page.dart'] + .length, + equals(3455)); + }); + }); +} + +final bodyUserChangePage = '''import 'package:flutter/material.dart'; + +import '../../helper/settings.dart'; +import '../../model/button_model.dart'; +import '../../widget/edit_form.dart'; +import '../../widget/page_controller_bones.dart'; +import '../application_data.dart'; +import 'user_controller.dart'; +import 'user_password_page.dart'; + +//! === BeginOfGeneratedCode: Change only in areas marked as customized +//! pageType: change + +class UserChangePage extends StatefulWidget { + final ApplicationData applicationData; + final Map initialRow; + final logger = Settings().logger; + final int primaryId; + + //! === BeginOfCustomizedVars1 === + //! === EndOfCustomizedVars1 === + //! === BeginOfConstructor1 === + UserChangePage(this.primaryId, this.applicationData, this.initialRow, + {Key key}) + : super(key: key); + + //! === EndOfConstructor1 === + + @override + UserChangePageState createState() { + //! === BeginOfCall === + final rc = + UserChangePageStateCustomized(primaryId, applicationData, initialRow); + //! === EndOfCall === + + /// for unittests: + applicationData.lastModuleState = rc; + return rc; + } +} + +abstract class UserChangePageState extends State + implements RedrawPage { + final ApplicationData applicationData; + final int primaryId; + final Map initialRow; + final GlobalKey _formKey = + GlobalKey(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(controller.page.title), + drawer: applicationData.drawerBuilder(context), + bottomNavigationBar: applicationData.footerBuilder().widget(controller), + body: EditForm.editForm( + key: _formKey, + pageController: controller, + configuration: applicationData.configuration, + 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 + void initState() { + super.initState(); + controller = + UserController(_formKey, this, 'change', context, applicationData); + controller.initialize(); + customize(); + } + + @override + void redraw(RedrawReason reason, + {String customString, RedrawCallbackFunctionSimple callback}) { + setState(() { + controller.afterSetState(reason, + customString: customString, callback: callback); + }); + } +} + +//! === 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))); + }; + } +}'''; + +class ModelToolIo extends ModelTool { + ModelToolIo(mh.ModelHelper modelHelper, BaseLogger logger) + : super(modelHelper, logger); + + final fileCache = {}; + @override + void ensureDirectory(String path) { + FileSync.ensureDirectory(path); + } + + @override + List pathOfDirectory(String path) { + final rc = Directory(path).listSync().map((entry) => entry.path).toList(); + return rc; + } + + @override + readFile(String file) { + final rc = FileSync.fileAsList(file); + return rc; + } + + @override + String safeDirectory(String name) { + final rc = FileSync.tempDirectory( + name + + '.' + + 12345.0 + // (DateTime.now().millisecondsSinceEpoch / 1000 % 86400) + .round() + .toString(), + subDirs: 'model_tools'); + return rc; + } + + @override + void writeFile(String filename, String content) { + fileCache[filename] = content; + FileSync.toFile(filename, content); + } } -- 2.39.5