From: Hamatoma Date: Sat, 29 Jan 2022 19:16:50 +0000 (+0100) Subject: I18N, Validators, Benchmarks, Scopes, Users X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=0491213a7a75fafaeca8dc2a600274a9933e423a;p=exhibition.git I18N, Validators, Benchmarks, Scopes, Users * I18N: I18N(): fix: null test * validators: ** new: isTime() ** fix: isInt(), isNat(): message if input is null * Benchmarks>: ** random_data: warnings removed * Structures changed to Scopes * Users: new attribute status * GlobalWidgets: new comboUsers() * new: assets/ * new: validator_test --- diff --git a/assets/white-16x16.png b/assets/white-16x16.png new file mode 100644 index 0000000..11d70f9 Binary files /dev/null and b/assets/white-16x16.png differ diff --git a/dart_tools/bin/i18n_text_parser.dart b/dart_tools/bin/i18n_text_parser.dart index bcfca05..c89607b 100644 --- a/dart_tools/bin/i18n_text_parser.dart +++ b/dart_tools/bin/i18n_text_parser.dart @@ -103,11 +103,13 @@ class I18nTextParser { List lines = []; int currentLineNo = 0; int currentIxLines = 0; - late RegExp regExpExcluded; + RegExp regExpExcluded = RegExp('^(Never°DEFined)\$'); + // ...........................1.............1.........2 final regExpModule = RegExp(r'''(\w+) = (I18N\(\)|i18n)\.module\(["'](.*?)['"]\);'''); final regExpDelimiter = RegExp(r'''["']'''); + // ..........1.............1..2..............................2 final regExpText = RegExp(r'(i18n|I18N\(\))\.(tr|ntr|trMulti|trArgs)\('); final regExpStringConstant = RegExp(r'''^\s*(r?)(["'])(.*?)\2'''); diff --git a/lib/base/i18n.dart b/lib/base/i18n.dart index 528f67f..503b9d9 100644 --- a/lib/base/i18n.dart +++ b/lib/base/i18n.dart @@ -12,10 +12,19 @@ class I18N { String locale = 'de_DE'; String loadedLocale = ''; final regExpTag = RegExp(r'<#\d+>$'); + factory I18N() { + if (instance == null) { + instance = I18N.internal(MemoryLogger()); + } return instance!; } + /** + * Constructor for initializing the global instance. + * + * @param logger: the logger used for error messages. + */ I18N.internal(this.logger) { instance = this; } diff --git a/lib/base/validators.dart b/lib/base/validators.dart index ad862af..97bae75 100644 --- a/lib/base/validators.dart +++ b/lib/base/validators.dart @@ -1,3 +1,5 @@ +import 'package:dart_bones/dart_bones.dart'; + import 'i18n.dart'; final i18n = I18N(); @@ -6,14 +8,22 @@ final _regExprEMailChar = RegExp(r'[\/ "!$%&()?;:,*<>|^°{}\[\]\\=]'); final _regExprEMailFormat = RegExp(r'^[^@]+@[^@]+\.[a-zA-Z]+$'); +final _regExprTime = RegExp(r'^(\d{1,2})(:(\d{1,2}))?$'); + +final _regExprNat = RegExp(r'^\d+$'); + /// Tests whether [input] is an correct email address. /// /// Returns null on success, the error message otherwise. String? isEmail(String? input) { String? rc; - if (input != null) { + if (input == null) { + rc = i18n.tr('null is not an email'); + } else { RegExpMatch? match = _regExprEMailChar.firstMatch(input); - if (match != null) { + if (countChar(input, '@') > 1) { + rc = i18n.tr('too many "@" in email address: ') + input; + } else if (match != null) { rc = i18n.trArgs('Illegal character "{0}" in email address', '!global', [match.group(0)!]); } else if (_regExprEMailFormat.firstMatch(input) == null) { @@ -26,7 +36,9 @@ String? isEmail(String? input) { /// Tests whether the [input] is a not negative integer. String? isInt(String? input) { String? rc; - if (input != null) { + if (input == null) { + rc = i18n.tr('null is not an integer'); + } else { final value = int.tryParse(input); if (value == null) { rc = i18n.trArgs('Not an integer: {0}', '!global', [input]); @@ -38,11 +50,11 @@ String? isInt(String? input) { /// Tests whether the [input] is a not negative integer. String? isNat(String? input) { String? rc; - if (input != null) { - final value = int.tryParse(input); - if (value == null) { - rc = i18n.trArgs('Not an integer: {0}', '!global', [input]); - } else if (value < 0) { + if (input == null) { + rc = i18n.tr('null is not a not negative integer'); + } else { + RegExpMatch? match = _regExprNat.firstMatch(input); + if (match == null) { rc = i18n.trArgs( 'Not negative integer expected, not: {0}', '!global', [input]); } @@ -50,6 +62,30 @@ String? isNat(String? input) { return rc; } +/// Tests whether the [input] is a time, e.g. "22:44". +String? isTime(String? input, {bool mayBeEmpty = false}) { + String? rc; + RegExpMatch? match; + if (input == null || input.isEmpty) { + if (!mayBeEmpty) { + rc = i18n.tr('Nothing is not a time'); + } + } else { + if ((match = _regExprTime.firstMatch(input)) == null) { + rc = i18n + .trArgs('Not a time: {0} Examples: 10 or 9:44 ', '!global', [input]); + } else if (int.parse(match!.group(1)!) >= 24) { + rc = i18n.trArgs('Wrong hour in: {0}: 0..23', '!global', [input]); + } else if (match.groupCount >= 3 && + match.group(3) != null && + int.parse(match.group(3)!) >= 60) { + rc = i18n + .trArgs('Wrong minutes in: {0} Expected 0..59', '!global', [input]); + } + } + return rc; +} + /// Tests whether the input is not empty. String? notEmpty(String? input) { final rc = input == null || input.isEmpty ? i18n.tr('Please fill in.') : null; diff --git a/lib/common/module_meta_data.dart b/lib/common/module_meta_data.dart new file mode 100644 index 0000000..692208b --- /dev/null +++ b/lib/common/module_meta_data.dart @@ -0,0 +1,491 @@ +import 'package:dart_bones/dart_bones.dart'; + +import '../base/defines.dart'; + +typedef MetaMenuItemBuilder = List Function( + PropertyMetaData propertyMetaData); + +/// Describes a button of a page. +class ButtonMetaData extends WidgetMetaData { + ButtonMetaData(String name) : super(name, WidgetType.button) { + //@ToDo + } +} + +class CopyDbFields extends FieldMetaData { + CopyDbFields(String name, {String options = ''}) + : super(name, options, dataType: DataType.undefined); +} + +/// Describes a field related to a database column. +class DbFieldMetaData extends WidgetMetaData { + PropertyMetaData? reference; + + DbFieldMetaData(String name, String reference) + : super(name, WidgetType.dbField) { + //@ToDo + } +} + +enum DisplayType { + checkbox, + combobox, + custom, + switchWidget, + text, +} + +/// Describes a field of the page. +class FieldMetaData extends WidgetMetaData { + DataType dataType; + DisplayType displayType; + final String options; + + FieldMetaData(String name, this.options, + {this.dataType = DataType.string, this.displayType = DisplayType.text}) + : super(name, WidgetType.field); +} + +/// Describes the list page, that displays an overview over all records of the +/// related table. +class ListPageMetaData extends PageMetaData { + final String tableHeaders; + final String tableColumns; + final String whereCondition; + final String orderBy; + final String selectItems; + final String joinItems; + final String widgetsBelowFilter; + final String toolTipAddButton; + + /// Constructor. + /// + /// [name] is the page name. It must be unique over all pages in the module. + /// + /// [fields]: the field in the filter section. + /// + /// [tableColumns]: a semicolon delimited list of table columns used in the + /// table displaying the filtered records. Example: 'user_id;user_name;role' + /// + /// [tableHeaders]: an auto delimited list of headers for the table. Example: + /// ';Id;Name;Role'. Auto delimited: the first char defines the delimiter. + /// + /// [globalComboBoxes]: If there are filter combo boxes that can be constructed + /// by "global methods" the should be listed here. + /// Example: 'comboRoles;comboUsers' + /// + /// [whereCondition]: the filter condition in the SQL statement. Example: + /// '(:text IS NULL OR user_name like :text OR user_displayname like :text)' + /// + /// [orderBy]: the default order by clause. Example: 'changed desc,user_id' + /// + /// [selectItems]: additional select entries. Must end with ','. Example: + /// '''(SELECT count(*) FROM sessions WHERE sessions.user_id=t0.user_id) as count, + /// t1.role_created as roledate,''' + /// + /// [joinItems]: additional joins. Convention: use table ids different from + /// the created joins (t1, t2, ...), use j1, j2 ... + /// Example: '''JOIN sessions j1 ON j1.user_id=t0.user_id + /// JOIN logins j2 ON j2.user_id=t0.user_id''' + /// + /// [widgetsBelowFilter]: additional widget + ListPageMetaData(String label, + {String name = '', + required List fields, + required this.tableColumns, + required this.tableHeaders, + String globalComboBoxes = '', + this.whereCondition = '', + this.orderBy = '', + this.selectItems = '', + this.joinItems = '', + this.widgetsBelowFilter = '', + this.toolTipAddButton = ''}) + : super(label, PageType.list, + name: name, fields: fields, globalComboBoxes: globalComboBoxes); +} + +/// Describes a mapping page, that allows assignments of many table entries +/// of the member table to one entry of a common table. +/// +/// Example: Common table is roles, member table is starters. Than the page +/// allows to assign some starters (menu items) to a role. +class MappingPageMetaData extends PageMetaData { + ModuleMetaData? commonModule; + ModuleMetaData? memberModule; + PropertyMetaData? commonProperty; + PropertyMetaData? memberProperty; + + /// Constructor. + /// + /// [name] is the page name. It must be unique over all pages in the module. + /// Default is a name derived from the page type. + /// + /// [commonModuleName]: the name of the module containing the common entries + /// of the relation. + /// + /// [memberModuleName]: the name of the module containing the member entries + /// that belongs to exactly one entry in the common module. + /// + /// [commonPropertyName]: the name of the property representing the common module. + /// + /// [memberPropertyName]: the name of the property representing the member module. + /// + /// Don't forget to initialize the [commonModule], [memberModule], + /// [commonProperty] and [memberProperty] in the overridden method [onInitialized]. + MappingPageMetaData(String label, {String name = ''}) + : super(label, PageType.mapping, name: name, fields: []); +} + +class MetaException extends FormatException {} + +/// Stores the meta data of a module. +class ModuleMetaData { + static final metaColumns = [ + 'createdAt', + 'createdBy', + 'changedAt', + 'changedBy', + 'deletedAt', + 'deletedBy' + ]; + + /// The module name, e.g. users + String moduleName = ''; + + /// The singular version of the module name, e.g. 'user' + String moduleNameSingular = ''; + + /// The related database table. + String tableName = ''; + + final bool needsSqlAll; + + /// If true the fields create, createdBy ... have the same ("short") column name + /// instead of prefix and name. + bool shortModifiedLabel = false; + List propertyList; + List pageList; + final Map properties = {}; + String columnPrefix = ''; + + ModuleMetaData(this.moduleName, this.propertyList, this.pageList, + {String tableName = '', + String moduleNameSingular = '', + String columnPrefix = '', + this.shortModifiedLabel = false, + this.needsSqlAll = false}) { + this.tableName = tableName.isEmpty ? moduleName.toLowerCase() : tableName; + if (moduleNameSingular.isEmpty) { + if (!moduleName.endsWith('s')) { + moduleNameSingular = moduleName; + } else { + final length = moduleName.length - 1; + moduleNameSingular = moduleName.substring(0, length); + } + } + this.columnPrefix = columnPrefix.isNotEmpty + ? columnPrefix + : this.moduleNameSingular.toLowerCase(); + + for (var item in propertyList) { + item.module = this; + properties[item.name] = item; + if (item.columnName.isEmpty) { + final prefix = shortModifiedLabel && metaColumns.contains(item.name) + ? '' + : (this.columnPrefix + '_'); + item.columnName = prefix + item.name.toLowerCase(); + } + } + for (var item in pageList) { + item.module = this; + } + } + + /// Returns a given [dataType] as string. + String dartType(DataType dataType) { + String rc; + switch (dataType) { + case DataType.bool: + rc = 'bool'; + break; + case DataType.currency: + rc = 'int'; + break; + case DataType.date: + case DataType.datetime: + rc = 'DateTime'; + break; + case DataType.float: + rc = 'double'; + break; + case DataType.int: + case DataType.nat: + case DataType.reference: + rc = 'int'; + break; + case DataType.string: + rc = 'String'; + break; + case DataType.undefined: + throw const FormatException('dartType(): data type is undefined'); + } + return rc; + } + + /// Calculates the column option of a column. + /// [property] specifies the meta data of the column. + String dbOptions(PropertyMetaData property) { + String rc = ''; + String options = property.options; + if (options.contains(':notnull:') || options.contains('primary')) { + rc += ' NOT NULL'; + } + if (options.contains('unique')) { + rc += ' UNIQUE'; + } + if (property.dataType == DataType.date || + property.dataType == DataType.datetime) { + rc += ' NULL'; + } + if (options.contains('primary')) { + rc += ' AUTO_INCREMENT'; + } + return rc.isEmpty ? '' : ' $rc'; + } + + /// Calculates the MySQL data type. + /// [dataType] specifies the data type. + /// [size] specifies the maximal size for a string type. Only relevant if + /// [dataType] == DataType.string. + String mySqlType(DataType dataType, int size) { + String rc; + switch (dataType) { + case DataType.bool: + rc = 'CHAR(1)'; + break; + case DataType.date: + rc = 'DATE'; + break; + case DataType.datetime: + rc = 'TIMESTAMP'; + break; + case DataType.float: + rc = 'FLOAT'; + break; + case DataType.currency: + rc = 'DECIMAL(12,2)'; + break; + case DataType.int: + rc = 'INT(10)'; + break; + case DataType.nat: + case DataType.reference: + rc = 'INT(10) UNSIGNED'; + break; + case DataType.string: + size = size == 0 ? 255 : size; + if (size <= 255) { + rc = 'VARCHAR($size)'; + } else if (size < 65535) { + rc = 'TEXT'; + } else { + rc = 'LARGE TEXT'; + } + break; + case DataType.undefined: + throw const FormatException('mySqlType(): data type is undefined'); + } + return rc; + } + + /// Will be called after the constructor. + /// + /// Override it if needed. + void onInitialized() { + for (var page in this.pageList) { + page.onInitialized(); + } + } + + /// Returns the meta data of a page given by its [name] or null if missing. + PageMetaData? pageByName(String name) { + PageMetaData? rc; + for (var item in pageList) { + if (item.name == name) { + rc = item; + break; + } + } + return rc; + } + + /// Returns the list of pages with a given [pageType]. May be empty. + List pagesByType(PageType pageType) { + final rc = []; + for (var item in pageList) { + if (item.pageType == pageType) { + rc.add(item); + break; + } + } + return rc; + } + + /// Returns the primary key of the relation. + PropertyMetaData? primaryOf() { + PropertyMetaData? rc; + for (var item in propertyList) { + if (item.options.contains('primary')) { + rc = item; + break; + } + } + return rc; + } + + /// Returns a property given by the [columnName]. + PropertyMetaData? propertyByColumnName(String columnName) { + PropertyMetaData? rc; + for (var field in propertyList) { + if (field.columnName == columnName) { + rc = field; + break; + } + } + return rc; + } + + /// Returns the meta data of a property given by its [name] or null if missing. + PropertyMetaData? propertyByName(String name) { + final rc = propertyList.singleWhere((element) => element.name == name, + orElse: null); + return rc; + } + + /// Returns the properties that are not in [metaColumns]. + /// : if the name of the property is [included] the property is always part of + /// the result. + Iterable standardColumns([String included = '']) { + final rc = propertyList.where( + (item) => item.name == included || !metaColumns.contains(item.name)); + return rc; + } +} + +class PageMetaData { + String name = ''; + final String label; + final PageType pageType; + late ModuleMetaData module; + final List fields; + final String globalComboBoxes; + + PageMetaData(this.label, this.pageType, + {this.name = '', required this.fields, this.globalComboBoxes = ''}) { + if (name.isEmpty) { + name = enumToString(pageType); + } + } + + /// Does things when the instance is inititialized. + /// + /// Must be called after the constructor. + void onInitialized() { + var newFields = []; + var toDelete = []; + for (var field in fields) { + if (field is CopyDbFields) { + String excluded = ''; + final start = field.options.indexOf('excluded='); + if (start >= 0) { + var end = field.options.indexOf(':', start); + if (end < 0) { + end = field.options.length; + } + excluded = ' ' + field.options.substring(start, end) + ' '; + } + for (var property in module.propertyList) { + if (excluded.contains(" ${property.name} ")) { + continue; + } + if (!property.hasOption(':hidden:')) { + newFields.add(property); + } + } + toDelete.add(field); + } + } + for (var field in toDelete) { + fields.remove(field); + } + fields.addAll(newFields); + } +} + +enum PageType { create, custom, delete, edit, list, mapping } + +/// Stores the meta data of a module property stored as column in a database. +class PropertyMetaData extends WidgetMetaData { + late ModuleMetaData module; + final String label; + + /// Relative width of the field in a 12 column form: 1 <= width <= 12 + int weight = 6; + + /// A colon delimited list of options, e.g. ':notnull:unique:'. + final String options; + final DisplayType displayType; + final DataType dataType; + MetaMenuItemBuilder? menuItemBuilder; + + /// The size if dataType is DataType.string. + final int size; + String columnName; + var validators = []; + + /// The foreign key if dataType is DataType.reference, e.g. 'users.user_id' + String? foreignKey; + + PropertyMetaData(String name, this.label, this.dataType, this.options, + {this.displayType = DisplayType.text, + this.columnName = '', + this.size = 0, + this.foreignKey, + int weight = 6, + List? validators}) + : super(name, WidgetType.property) { + this.weight = weight > 12 ? 12 : weight; + this.validators = validators ?? []; + } + + /// Returns whether a given [option] is set. + /// + /// [option] is a word delimited by ':', e.g. ":notnull:" + /// + /// Returns true, if [option] is part of [options], false otherwise. + bool hasOption(String option) { + return options.contains(option); + } +} + +class ReferenceProperty extends WidgetMetaData { + /// This attribute gets is real value after the construcctor of the module. + PropertyMetaData child = PropertyMetaData('dummy', '', DataType.bool, ''); + final String nameChild; + + ReferenceProperty({required this.nameChild}) + : super(nameChild + 'Ref', WidgetType.referenceProperty); +} + +/// Describes a widget used in the page. +/// Base class of all other widgets. +class WidgetMetaData { + final WidgetType widgetType; + final String name; + + WidgetMetaData(this.name, this.widgetType); +} + +enum WidgetType { button, field, dbField, property, referenceProperty } diff --git a/lib/common/random_data.dart b/lib/common/random_data.dart index ea628d6..3abfa28 100644 --- a/lib/common/random_data.dart +++ b/lib/common/random_data.dart @@ -1,25 +1,25 @@ class RandomData { - static final verbs = const [ + static const verbs = [ 'go', 'read', 'eat', 'jump', 'write', 'say', 'talk', 'pray', 'love', 'hate', 'join', 'select', 'walk', 'hear', 'type', // 15 'cry', 'cook', 'fill', 'bide', 'paint' ]; - static final adjectives = const [ + static const adjectives = [ 'high', 'low', 'hot', 'cold', 'wide', 'small', 'pretty', 'dirty', 'simple', 'rich', 'poor', 'full', 'empty', 'happy', 'angry', // 15 'strong', 'wise', 'dirty', 'silly', '' ]; - static final animals = const [ + static const animals = [ 'dog', 'cat', 'mouse', 'cow', 'unicorn', 'lion', 'tiger', 'sheep', 'bull', 'bison', 'bug', 'turtle', 'camel', 'spider', 'swan', // 15 'bunny', 'deer', 'hare', 'fox', 'pig' ]; - static final things = const [ + static const things = [ 'door', 'chair', 'wood', 'ink', 'floor', 'bed', 'bag', 'coat', 'house', 'palace', 'street', 'way', 'city', 'table', 'wall', // 15 'tree', 'gras', 'sky', 'hell', 'garden' ]; - static final colors = const [ + static const colors = [ 'red', 'blue', 'white', @@ -31,7 +31,7 @@ class RandomData { 'orange', 'pink' ]; - static final firstnames = const [ + static const firstnames = [ 'Adam', 'Alice', 'Bill', diff --git a/lib/meta/modules.dart b/lib/meta/modules.dart index 9334a33..ea69a72 100644 --- a/lib/meta/modules.dart +++ b/lib/meta/modules.dart @@ -3,10 +3,9 @@ import 'module_meta_data.dart'; import 'benchmarks_meta.dart'; import 'roles_meta.dart'; import 'rolestarter_meta.dart'; +import 'scopes_meta.dart'; import 'starters_meta.dart'; -import 'structures_meta.dart'; import 'users_meta.dart'; - /// Returns the meta data of the module given by [name]. /// Returns null if not found. ModuleMetaData? moduleByName(String name) { @@ -21,12 +20,12 @@ ModuleMetaData? moduleByName(String name) { case 'Rolestarter': rc = RoleStarterMeta(); break; + case 'Scopes': + rc = ScopesMeta(); + break; case 'Starters': rc = StartersMeta(); break; - case 'Structures': - rc = StructuresMeta(); - break; case 'Users': rc = UsersMeta(); break; @@ -35,15 +34,14 @@ ModuleMetaData? moduleByName(String name) { } return rc; } - /// Returns the module names as string list. List moduleNames() { return [ 'Benchmarks', 'Roles', 'Rolestarter', + 'Scopes', 'Starters', - 'Structures', 'Users', ]; } diff --git a/lib/meta/scopes_meta.dart b/lib/meta/scopes_meta.dart new file mode 100644 index 0000000..22d2697 --- /dev/null +++ b/lib/meta/scopes_meta.dart @@ -0,0 +1,64 @@ +import '../base/defines.dart'; +import '../base/i18n.dart'; +import 'module_meta_data.dart'; + +final i18n = I18N(); +final M = i18n.module("Scopes"); + +class ScopesMeta extends ModuleMetaData { + static ScopesMeta instance = ScopesMeta.internal(); + + factory ScopesMeta() { + return instance; + } + + ScopesMeta.internal() + : super('Scopes', [ + PropertyMetaData('id', i18n.tr('Id'), DataType.reference, ':primary:', + displayType: DisplayType.combobox), + PropertyMetaData( + 'scope', i18n.tr('Scope'), DataType.string, ':notnull:', + size: 64), + PropertyMetaData( + 'name', i18n.tr('Name', M), DataType.string, ':notnull:', + size: 64), + PropertyMetaData( + 'value', i18n.tr('Value', M), DataType.string, ':notnull:', + size: 32), + PropertyMetaData( + 'position', i18n.tr('Position', M), DataType.int, ''), + PropertyMetaData('createdAt', i18n.tr('Created at'), + DataType.datetime, ':hidden:'), + PropertyMetaData( + 'createdBy', i18n.tr('Created by'), DataType.string, ':hidden:', + size: 32), + PropertyMetaData('changedAt', i18n.tr('Changed at'), + DataType.datetime, ':hidden:'), + PropertyMetaData( + 'changedBy', i18n.tr('Changed by'), DataType.string, ':hidden:', + size: 32), + ], [ + PageMetaData('New Scope', PageType.create, + fields: [CopyDbFields('fields')]), + PageMetaData('Change Scope', PageType.edit, + fields: [CopyDbFields('fields')]), + PageMetaData('Delete Scope', PageType.delete, + fields: [CopyDbFields('fields')]), + ListPageMetaData( + 'Scopes Overview', + fields: [ + PropertyMetaData('text', i18n.tr('Text'), DataType.string, + ':where=!text IS NONE OR scope_name like !text OR scope_value like !text:', + size: 64), + ], + toolTipAddButton: i18n.tr('Add a scope item'), + tableColumns: + 'scope_id;scope_scope;scope_name;scope_value;scope_position', + tableHeaders: i18n.tr(';Id;Scope;Name;Value;Position'), + ), + ]); + @override + void onInitialized() { + super.onInitialized(); + } +} diff --git a/lib/meta/structures_meta.dart b/lib/meta/structures_meta.dart deleted file mode 100644 index 2f58149..0000000 --- a/lib/meta/structures_meta.dart +++ /dev/null @@ -1,62 +0,0 @@ -import '../base/defines.dart'; -import '../base/i18n.dart'; -import 'module_meta_data.dart'; - -final i18n = I18N(); -final M = i18n.module("Structures"); - -class StructuresMeta extends ModuleMetaData { - static StructuresMeta instance = StructuresMeta.internal(); - factory StructuresMeta() { - return instance; - } - StructuresMeta.internal() - : super('Structures', [ - PropertyMetaData('id', i18n.tr('Id'), DataType.reference, ':primary:', - displayType: DisplayType.combobox), - PropertyMetaData( - 'scope', i18n.tr('Scope'), DataType.string, ':notnull:', - size: 64), - PropertyMetaData( - 'name', i18n.tr('Name', M), DataType.string, ':notnull:', - size: 64), - PropertyMetaData( - 'value', i18n.tr('Value', M), DataType.string, ':notnull:', - size: 32), - PropertyMetaData( - 'position', i18n.tr('Position', M), DataType.int, ''), - PropertyMetaData('createdAt', i18n.tr('Created at'), - DataType.datetime, ':hidden:'), - PropertyMetaData( - 'createdBy', i18n.tr('Created by'), DataType.string, ':hidden:', - size: 32), - PropertyMetaData('changedAt', i18n.tr('Changed at'), - DataType.datetime, ':hidden:'), - PropertyMetaData( - 'changedBy', i18n.tr('Changed by'), DataType.string, ':hidden:', - size: 32), - ], [ - PageMetaData('New Structure', PageType.create, - fields: [CopyDbFields('fields')]), - PageMetaData('Change Structure', PageType.edit, - fields: [CopyDbFields('fields')]), - PageMetaData('Delete Structure', PageType.delete, - fields: [CopyDbFields('fields')]), - ListPageMetaData( - 'Structures Overview', - fields: [ - PropertyMetaData('text', i18n.tr('Text'), DataType.string, - ':where=!text IS NONE OR structure_name like !text OR structure_value like !text:', - size: 64), - ], - toolTipAddButton: i18n.tr('Add a structure item'), - tableColumns: - 'structure_id;structure_scope;structure_name;structure_value;structure_position', - tableHeaders: i18n.tr(';Id;Scope;Name;Value;Position'), - ), - ]); - @override - void onInitialized() { - super.onInitialized(); - } -} diff --git a/lib/meta/users_meta.dart b/lib/meta/users_meta.dart index 40c017d..db02cd4 100644 --- a/lib/meta/users_meta.dart +++ b/lib/meta/users_meta.dart @@ -27,6 +27,10 @@ class UsersMeta extends ModuleMetaData { 'role', i18n.tr('Role'), DataType.reference, ':notnull:', displayType: DisplayType.combobox, foreignKey: 'roles.role_id;role_name;role'), + PropertyMetaData( + 'status', i18n.tr('Status'), DataType.reference, ':notnull:', + displayType: DisplayType.combobox, + foreignKey: 'roles.role_id;role_name;role'), PropertyMetaData('createdAt', i18n.tr('Created at'), DataType.datetime, ':hidden:'), PropertyMetaData( diff --git a/lib/page/benchmarks/benchmark_data.dart b/lib/page/benchmarks/benchmark_data.dart index c693772..9f44af6 100644 --- a/lib/page/benchmarks/benchmark_data.dart +++ b/lib/page/benchmarks/benchmark_data.dart @@ -2,7 +2,6 @@ import '../../base/defines.dart'; import '../../base/helper.dart'; import '../../persistence/data_record.dart'; - class BenchmarkData extends DataRecord { int? id; String? lastName; @@ -16,6 +15,7 @@ class BenchmarkData extends DataRecord { String? createdBy; DateTime? changedAt; String? changedBy; + BenchmarkData( {this.id, this.lastName, @@ -29,9 +29,11 @@ class BenchmarkData extends DataRecord { this.createdBy, this.changedAt, this.changedBy}); + BenchmarkData.createFromMap(DataMap map) { fromMap(map); } + @override void fromMap(DataMap map) { id = map.containsKey('benchmark_id') @@ -126,7 +128,6 @@ class BenchmarkData extends DataRecord { } return rc; } - @override DataMap toMap({DataMap? map, bool clear = true}) { map ??= DataMap(); diff --git a/lib/page/benchmarks/create_benchmark_page.dart b/lib/page/benchmarks/create_benchmark_page.dart index 3933f0e..a0ebe41 100644 --- a/lib/page/benchmarks/create_benchmark_page.dart +++ b/lib/page/benchmarks/create_benchmark_page.dart @@ -28,6 +28,7 @@ class CreateBenchmarkPage extends StatefulWidget { class _CreateBenchmarkPageState extends CreateBenchmarkCustom { _CreateBenchmarkPageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _CreateBenchmarkPageState extends CreateBenchmarkCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/benchmarks/delete_benchmark_page.dart b/lib/page/benchmarks/delete_benchmark_page.dart index e11e701..a016da0 100644 --- a/lib/page/benchmarks/delete_benchmark_page.dart +++ b/lib/page/benchmarks/delete_benchmark_page.dart @@ -29,6 +29,7 @@ class DeleteBenchmarkPage extends StatefulWidget { class _DeleteBenchmarkPageState extends DeleteBenchmarkCustom { _DeleteBenchmarkPageState(int primaryKey) : super(primaryKey); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -59,4 +60,4 @@ class _DeleteBenchmarkPageState extends DeleteBenchmarkCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/benchmarks/edit_benchmark_page.dart b/lib/page/benchmarks/edit_benchmark_page.dart index 53f305c..ccc3c99 100644 --- a/lib/page/benchmarks/edit_benchmark_page.dart +++ b/lib/page/benchmarks/edit_benchmark_page.dart @@ -29,6 +29,7 @@ class EditBenchmarkPage extends StatefulWidget { class _EditBenchmarkPageState extends EditBenchmarkCustom { _EditBenchmarkPageState(int primaryKey) : super(primaryKey); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -59,4 +60,4 @@ class _EditBenchmarkPageState extends EditBenchmarkCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/benchmarks/list_benchmark_page.dart b/lib/page/benchmarks/list_benchmark_page.dart index 6a65fa0..9074c61 100644 --- a/lib/page/benchmarks/list_benchmark_page.dart +++ b/lib/page/benchmarks/list_benchmark_page.dart @@ -28,6 +28,7 @@ class ListBenchmarkPage extends StatefulWidget { class _ListBenchmarkPageState extends ListBenchmarkCustom { _ListBenchmarkPageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _ListBenchmarkPageState extends ListBenchmarkCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/page_manager.dart b/lib/page/page_manager.dart index c4d5ff0..7e0dc60 100644 --- a/lib/page/page_manager.dart +++ b/lib/page/page_manager.dart @@ -11,14 +11,14 @@ import 'roles/edit_role_page.dart'; import 'roles/list_role_page.dart'; import 'rolestarter/mapping_rolestarter_page.dart'; import 'rolestarter/list_rolestarter_page.dart'; +import 'scopes/create_scope_page.dart'; +import 'scopes/edit_scope_page.dart'; +import 'scopes/delete_scope_page.dart'; +import 'scopes/list_scope_page.dart'; import 'starters/create_starter_page.dart'; import 'starters/edit_starter_page.dart'; import 'starters/delete_starter_page.dart'; import 'starters/list_starter_page.dart'; -import 'structures/create_structure_page.dart'; -import 'structures/edit_structure_page.dart'; -import 'structures/delete_structure_page.dart'; -import 'structures/list_structure_page.dart'; import 'users/create_user_page.dart'; import 'users/edit_user_page.dart'; import 'users/delete_user_page.dart'; @@ -67,6 +67,18 @@ class PageManager { case '/RoleStarter/list': rc = ListRoleStarterPage(); break; + case '/Scopes/create': + rc = CreateScopePage(); + break; + case '/Scopes/edit': + rc = EditScopePage(arg1); + break; + case '/Scopes/delete': + rc = DeleteScopePage(arg1); + break; + case '/Scopes/list': + rc = ListScopePage(); + break; case '/Starters/create': rc = CreateStarterPage(); break; @@ -79,18 +91,6 @@ class PageManager { case '/Starters/list': rc = ListStarterPage(); break; - case '/Structures/create': - rc = CreateStructurePage(); - break; - case '/Structures/edit': - rc = EditStructurePage(arg1); - break; - case '/Structures/delete': - rc = DeleteStructurePage(arg1); - break; - case '/Structures/list': - rc = ListStructurePage(); - break; case '/Users/create': rc = CreateUserPage(); break; diff --git a/lib/page/roles/create_role_page.dart b/lib/page/roles/create_role_page.dart index 57426c9..237ab52 100644 --- a/lib/page/roles/create_role_page.dart +++ b/lib/page/roles/create_role_page.dart @@ -28,6 +28,7 @@ class CreateRolePage extends StatefulWidget { class _CreateRolePageState extends CreateRoleCustom { _CreateRolePageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _CreateRolePageState extends CreateRoleCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/roles/edit_role_page.dart b/lib/page/roles/edit_role_page.dart index c720ac8..b2abd65 100644 --- a/lib/page/roles/edit_role_page.dart +++ b/lib/page/roles/edit_role_page.dart @@ -29,6 +29,7 @@ class EditRolePage extends StatefulWidget { class _EditRolePageState extends EditRoleCustom { _EditRolePageState(int primaryKey) : super(primaryKey); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -59,4 +60,4 @@ class _EditRolePageState extends EditRoleCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/roles/list_role_page.dart b/lib/page/roles/list_role_page.dart index fee466d..491a3c1 100644 --- a/lib/page/roles/list_role_page.dart +++ b/lib/page/roles/list_role_page.dart @@ -28,6 +28,7 @@ class ListRolePage extends StatefulWidget { class _ListRolePageState extends ListRoleCustom { _ListRolePageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _ListRolePageState extends ListRoleCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/roles/role_data.dart b/lib/page/roles/role_data.dart index 317e9db..bd2c7ae 100644 --- a/lib/page/roles/role_data.dart +++ b/lib/page/roles/role_data.dart @@ -2,7 +2,6 @@ import '../../base/defines.dart'; import '../../base/helper.dart'; import '../../persistence/data_record.dart'; - class RoleData extends DataRecord { int? id; String? name; @@ -10,6 +9,7 @@ class RoleData extends DataRecord { String? createdBy; DateTime? changedAt; String? changedBy; + RoleData( {this.id, this.name, @@ -17,9 +17,11 @@ class RoleData extends DataRecord { this.createdBy, this.changedAt, this.changedBy}); + RoleData.createFromMap(DataMap map) { fromMap(map); } + @override void fromMap(DataMap map) { id = map.containsKey('role_id') @@ -78,7 +80,6 @@ class RoleData extends DataRecord { } return rc; } - @override DataMap toMap({DataMap? map, bool clear = true}) { map ??= DataMap(); diff --git a/lib/page/rolestarter/list_rolestarter_page.dart b/lib/page/rolestarter/list_rolestarter_page.dart index 0d1b5b9..8e218ca 100644 --- a/lib/page/rolestarter/list_rolestarter_page.dart +++ b/lib/page/rolestarter/list_rolestarter_page.dart @@ -28,6 +28,7 @@ class ListRoleStarterPage extends StatefulWidget { class _ListRoleStarterPageState extends ListRoleStarterCustom { _ListRoleStarterPageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _ListRoleStarterPageState extends ListRoleStarterCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/rolestarter/mapping_rolestarter_page.dart b/lib/page/rolestarter/mapping_rolestarter_page.dart index 4c97680..3db5408 100644 --- a/lib/page/rolestarter/mapping_rolestarter_page.dart +++ b/lib/page/rolestarter/mapping_rolestarter_page.dart @@ -28,6 +28,7 @@ class MappingRoleStarterPage extends StatefulWidget { class _MappingRoleStarterPageState extends MappingRoleStarterCustom { _MappingRoleStarterPageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _MappingRoleStarterPageState extends MappingRoleStarterCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/rolestarter/role_starter_data.dart b/lib/page/rolestarter/role_starter_data.dart index 2e761f3..682fca3 100644 --- a/lib/page/rolestarter/role_starter_data.dart +++ b/lib/page/rolestarter/role_starter_data.dart @@ -2,7 +2,6 @@ import '../../base/defines.dart'; import '../../base/helper.dart'; import '../../persistence/data_record.dart'; - class RoleStarterData extends DataRecord { int? id; int? role; @@ -12,6 +11,7 @@ class RoleStarterData extends DataRecord { String? createdBy; DateTime? changedAt; String? changedBy; + RoleStarterData( {this.id, this.role, @@ -21,9 +21,11 @@ class RoleStarterData extends DataRecord { this.createdBy, this.changedAt, this.changedBy}); + RoleStarterData.createFromMap(DataMap map) { fromMap(map); } + @override void fromMap(DataMap map) { id = map.containsKey('rolestarter_id') @@ -94,7 +96,6 @@ class RoleStarterData extends DataRecord { } return rc; } - @override DataMap toMap({DataMap? map, bool clear = true}) { map ??= DataMap(); diff --git a/lib/page/scopes/create_scope_custom.dart b/lib/page/scopes/create_scope_custom.dart new file mode 100644 index 0000000..7d71c17 --- /dev/null +++ b/lib/page/scopes/create_scope_custom.dart @@ -0,0 +1,166 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; +import '../../widget/widget_form.dart'; +import 'create_scope_page.dart'; + +final i18n = I18N(); + +class CreateScopeCustom extends State with MessageLine { + final globalData = GlobalData(); + late AttendedPage attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateScope'); + final scopeController = TextEditingController(); + final nameController = TextEditingController(); + final valueController = TextEditingController(); + final positionController = TextEditingController(); + + CreateScopeCustom(); + + @override + Widget build(BuildContext context) { + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('New Scope')), + drawer: globalData.drawerBuilder(context), + body: SafeArea(child: buildFrame())); + return rc; + } + + Widget buildFrame() { + final padding = GlobalThemeData.padding; + scopeController.text = _fieldData.scope; + nameController.text = _fieldData.name; + valueController.text = _fieldData.value; + positionController.text = asString(_fieldData.position); + final formItems = [ + FormItem( + TextFormField( + controller: scopeController, + decoration: InputDecoration(labelText: i18n.tr('Scope')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.scope = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: nameController, + decoration: InputDecoration(labelText: i18n.tr('Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.name = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: valueController, + decoration: InputDecoration(labelText: i18n.tr('Value')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.value = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: positionController, + decoration: InputDecoration(labelText: i18n.tr('Position')), + onSaved: (value) => _fieldData.position = + jsonToObject(value ?? '', dataType: DataType.int)), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => onVerifyAndStore(), + child: Text(i18n.tr('Save'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Scopes/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; + final rc = Form( + key: _formKey, + child: Card( + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage.pageStates.screenWidth, + padding: padding, + )))); + return rc; + } + + @override + void dispose() { + helperDummyUsage(DataType.int); + globalWidgetDummyUsage(); + scopeController.dispose(); + nameController.dispose(); + valueController.dispose(); + positionController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + } + + void onStore() { + final parameters = { + 'module': 'Scopes', + 'sql': 'insert', + }; + _fieldData.toMap(parameters); + globalData.restPersistence + .store(what: 'store', map: parameters) + .then((answer) { + if (answer.startsWith('id:')) { + final id = int.tryParse(answer.substring(3)); + if (id == null || id == 0) { + setError(i18n.tr('Saving data failed: $answer')); + setState(() => 1); + } else { + attendedPage.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Scopes/edit;$id'); + } + } + }); + } + + void onVerifyAndStore() { + if (_formKey.currentState != null && _formKey.currentState!.validate()) { + _formKey.currentState!.save(); + onStore(); + } + } +} + +class _FieldData { + String scope = ''; + String name = ''; + String value = ''; + int position = 0; + + void toMap(Map map) { + map[':scope'] = scope; + map[':name'] = name; + map[':value'] = value; + map[':position'] = asString(position, dbFormat: true); + map[':createdBy'] = GlobalData.loginUserName; + } +} diff --git a/lib/page/scopes/create_scope_page.dart b/lib/page/scopes/create_scope_page.dart new file mode 100644 index 0000000..790dcda --- /dev/null +++ b/lib/page/scopes/create_scope_page.dart @@ -0,0 +1,64 @@ +// DO NOT CHANGE. This file is created by the meta_tool! +import 'package:flutter/material.dart'; + +import '../../meta/scopes_meta.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import 'create_scope_custom.dart'; + +class CreateScopePage extends StatefulWidget { + final PageStates pageStates = PageStates(); + + CreateScopePage() : super(); + + @override + _CreateScopePageState createState() { + final rc = _CreateScopePageState(); + rc.attendedPage = AttendedPage( + this, + rc, + GlobalData(), + ScopesMeta.instance.pageByName('create')!, + ScopesMeta.instance, + pageStates, + (afterReload, rebuild) => + rc.reload(afterReload: afterReload, rebuild: rebuild)); + pageStates.attendedPage = rc.attendedPage; + return rc; + } +} + +class _CreateScopePageState extends CreateScopeCustom { + _CreateScopePageState() : super(); + + @override + void didChangeDependencies() { + final size = MediaQuery.of(context).size; + attendedPage.pageStates.screenWidth = size.width; + attendedPage.pageStates.screenHeight = size.height; + super.didChangeDependencies(); + } + + /// Renders the widget tree again. + /// + /// [afterReload] is a function used as parameter of setState(). + /// + /// If [rebuild] is true the state has been changed and didChangeDependencies() + /// will be called. + void reload({Function? afterReload, bool rebuild = false}) { + if (afterReload == null) { + if (rebuild) { + setState(() => didChangeDependencies()); + } else { + setState(() => 1); + } + } else { + setState(() { + afterReload(); + if (rebuild) { + didChangeDependencies(); + } + }); + } + } +} \ No newline at end of file diff --git a/lib/page/scopes/delete_scope_custom.dart b/lib/page/scopes/delete_scope_custom.dart new file mode 100644 index 0000000..f967199 --- /dev/null +++ b/lib/page/scopes/delete_scope_custom.dart @@ -0,0 +1,178 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../persistence/persistence.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; +import '../../widget/widget_form.dart'; +import 'delete_scope_page.dart'; + +final i18n = I18N(); + +class DeleteScopeCustom extends State with MessageLine { + final int primaryKey; + final globalData = GlobalData(); + late Future _futureDbData; + late AttendedPage attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'DeleteScope'); + final scopeController = TextEditingController(); + final nameController = TextEditingController(); + final valueController = TextEditingController(); + final positionController = TextEditingController(); + + DeleteScopeCustom(this.primaryKey); + + @override + Widget build(BuildContext context) { + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('Delete Scope')), + drawer: globalData.drawerBuilder(context), + body: SafeArea( + child: FutureBuilder( + future: _futureDbData, + builder: (context, snapshot) { + final rc = attendedPage.loadRecord(snapshot, (record) { + _fieldData.fromMap(record); + return buildFrame(); + }); + return rc; + }))); + return rc; + } + + Widget buildFrame() { + final padding = GlobalThemeData.padding; + scopeController.text = _fieldData.scope; + nameController.text = _fieldData.name; + valueController.text = _fieldData.value; + positionController.text = asString(_fieldData.position); + final formItems = [ + FormItem( + TextFormField( + controller: scopeController, + decoration: InputDecoration(labelText: i18n.tr('Scope')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.scope = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: nameController, + decoration: InputDecoration(labelText: i18n.tr('Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.name = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: valueController, + decoration: InputDecoration(labelText: i18n.tr('Value')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.value = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: positionController, + decoration: InputDecoration(labelText: i18n.tr('Position')), + onSaved: (value) => _fieldData.position = + jsonToObject(value ?? '', dataType: DataType.int)), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => onVerifyAndDelete(), + child: Text(i18n.tr('Delete'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Scopes/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; + final rc = Form( + key: _formKey, + child: Card( + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage.pageStates.screenWidth, + padding: padding, + )))); + return rc; + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + requestRecord(); + } + + @override + void dispose() { + helperDummyUsage(DataType.int); + globalWidgetDummyUsage(); + scopeController.dispose(); + nameController.dispose(); + valueController.dispose(); + positionController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + } + + void requestRecord() => _futureDbData = globalData.restPersistence.query( + what: 'query', + data: {'module': 'Scopes', 'sql': 'byId', ':id': primaryKey}); + + void onDelete() { + final parameters = { + 'module': 'Scopes', + 'sql': 'delete', + ':id': primaryKey + }; + globalData.restPersistence + .store(what: 'store', map: parameters) + .then((answer) { + globalData.navigate(context, '/Scopes/list'); + }); + } + + void onVerifyAndDelete() { + if (_formKey.currentState != null && _formKey.currentState!.validate()) { + _formKey.currentState!.save(); + onDelete(); + } + } +} + +class _FieldData { + String scope = ''; + String name = ''; + String value = ''; + int position = 0; + + void fromMap(Map map) { + scope = map['scope_scope']; + name = map['scope_name']; + value = map['scope_value']; + position = jsonToObject(map['scope_position'], dataType: DataType.int); + } +} diff --git a/lib/page/scopes/delete_scope_page.dart b/lib/page/scopes/delete_scope_page.dart new file mode 100644 index 0000000..d49cad1 --- /dev/null +++ b/lib/page/scopes/delete_scope_page.dart @@ -0,0 +1,65 @@ +// DO NOT CHANGE. This file is created by the meta_tool! +import 'package:flutter/material.dart'; + +import '../../meta/scopes_meta.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import 'delete_scope_custom.dart'; + +class DeleteScopePage extends StatefulWidget { + final int primaryKey; + final PageStates pageStates = PageStates(); + + DeleteScopePage(this.primaryKey) : super(); + + @override + _DeleteScopePageState createState() { + final rc = _DeleteScopePageState(this.primaryKey); + rc.attendedPage = AttendedPage( + this, + rc, + GlobalData(), + ScopesMeta.instance.pageByName('delete')!, + ScopesMeta.instance, + pageStates, + (afterReload, rebuild) => + rc.reload(afterReload: afterReload, rebuild: rebuild)); + pageStates.attendedPage = rc.attendedPage; + return rc; + } +} + +class _DeleteScopePageState extends DeleteScopeCustom { + _DeleteScopePageState(int primaryKey) : super(primaryKey); + + @override + void didChangeDependencies() { + final size = MediaQuery.of(context).size; + attendedPage.pageStates.screenWidth = size.width; + attendedPage.pageStates.screenHeight = size.height; + super.didChangeDependencies(); + } + + /// Renders the widget tree again. + /// + /// [afterReload] is a function used as parameter of setState(). + /// + /// If [rebuild] is true the state has been changed and didChangeDependencies() + /// will be called. + void reload({Function? afterReload, bool rebuild = false}) { + if (afterReload == null) { + if (rebuild) { + setState(() => didChangeDependencies()); + } else { + setState(() => 1); + } + } else { + setState(() { + afterReload(); + if (rebuild) { + didChangeDependencies(); + } + }); + } + } +} \ No newline at end of file diff --git a/lib/page/scopes/edit_scope_custom.dart b/lib/page/scopes/edit_scope_custom.dart new file mode 100644 index 0000000..9eef671 --- /dev/null +++ b/lib/page/scopes/edit_scope_custom.dart @@ -0,0 +1,190 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../persistence/persistence.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; +import '../../widget/widget_form.dart'; +import 'edit_scope_page.dart'; + +final i18n = I18N(); + +class EditScopeCustom extends State with MessageLine { + final int primaryKey; + final globalData = GlobalData(); + late Future _futureDbData; + late AttendedPage attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'EditScope'); + final scopeController = TextEditingController(); + final nameController = TextEditingController(); + final valueController = TextEditingController(); + final positionController = TextEditingController(); + + EditScopeCustom(this.primaryKey); + + @override + Widget build(BuildContext context) { + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('Change Scope')), + drawer: globalData.drawerBuilder(context), + body: SafeArea( + child: FutureBuilder( + future: _futureDbData, + builder: (context, snapshot) { + final rc = attendedPage.loadRecord(snapshot, (record) { + _fieldData.fromMap(record); + return buildFrame(); + }); + return rc; + }))); + return rc; + } + + Widget buildFrame() { + final padding = GlobalThemeData.padding; + scopeController.text = _fieldData.scope; + nameController.text = _fieldData.name; + valueController.text = _fieldData.value; + positionController.text = asString(_fieldData.position); + final formItems = [ + FormItem( + TextFormField( + controller: scopeController, + decoration: InputDecoration(labelText: i18n.tr('Scope')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.scope = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: nameController, + decoration: InputDecoration(labelText: i18n.tr('Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.name = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: valueController, + decoration: InputDecoration(labelText: i18n.tr('Value')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.value = value ?? ''), + weight: 6), + FormItem( + TextFormField( + controller: positionController, + decoration: InputDecoration(labelText: i18n.tr('Position')), + onSaved: (value) => _fieldData.position = + jsonToObject(value ?? '', dataType: DataType.int)), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => onVerifyAndStore(), + child: Text(i18n.tr('Save'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Scopes/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; + final rc = Form( + key: _formKey, + child: Card( + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage.pageStates.screenWidth, + padding: padding, + )))); + return rc; + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + requestRecord(); + } + + @override + void dispose() { + helperDummyUsage(DataType.int); + globalWidgetDummyUsage(); + scopeController.dispose(); + nameController.dispose(); + valueController.dispose(); + positionController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + } + + void requestRecord() => _futureDbData = globalData.restPersistence.query( + what: 'query', + data: {'module': 'Scopes', 'sql': 'byId', ':id': primaryKey}); + + void onStore() { + final parameters = { + 'module': 'Scopes', + 'sql': 'update', + ':id': primaryKey + }; + _fieldData.toMap(parameters); + globalData.restPersistence + .store(what: 'store', map: parameters) + .then((answer) { + requestRecord(); + attendedPage.pageStates.dbDataState.clear(); + setState(() => 1); + }); + } + + void onVerifyAndStore() { + if (_formKey.currentState != null && _formKey.currentState!.validate()) { + _formKey.currentState!.save(); + onStore(); + } + } +} + +class _FieldData { + String scope = ''; + String name = ''; + String value = ''; + int position = 0; + + void fromMap(Map map) { + scope = map['scope_scope']; + name = map['scope_name']; + value = map['scope_value']; + position = jsonToObject(map['scope_position'], dataType: DataType.int); + } + + void toMap(Map map) { + // please set outside: map[':id'] = primaryKey; + map[':scope'] = scope; + map[':name'] = name; + map[':value'] = value; + map[':position'] = asString(position, dbFormat: true); + map[':changedBy'] = GlobalData.loginUserName; + } +} diff --git a/lib/page/scopes/edit_scope_page.dart b/lib/page/scopes/edit_scope_page.dart new file mode 100644 index 0000000..a6c80d5 --- /dev/null +++ b/lib/page/scopes/edit_scope_page.dart @@ -0,0 +1,65 @@ +// DO NOT CHANGE. This file is created by the meta_tool! +import 'package:flutter/material.dart'; + +import '../../meta/scopes_meta.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import 'edit_scope_custom.dart'; + +class EditScopePage extends StatefulWidget { + final int primaryKey; + final PageStates pageStates = PageStates(); + + EditScopePage(this.primaryKey) : super(); + + @override + _EditScopePageState createState() { + final rc = _EditScopePageState(this.primaryKey); + rc.attendedPage = AttendedPage( + this, + rc, + GlobalData(), + ScopesMeta.instance.pageByName('edit')!, + ScopesMeta.instance, + pageStates, + (afterReload, rebuild) => + rc.reload(afterReload: afterReload, rebuild: rebuild)); + pageStates.attendedPage = rc.attendedPage; + return rc; + } +} + +class _EditScopePageState extends EditScopeCustom { + _EditScopePageState(int primaryKey) : super(primaryKey); + + @override + void didChangeDependencies() { + final size = MediaQuery.of(context).size; + attendedPage.pageStates.screenWidth = size.width; + attendedPage.pageStates.screenHeight = size.height; + super.didChangeDependencies(); + } + + /// Renders the widget tree again. + /// + /// [afterReload] is a function used as parameter of setState(). + /// + /// If [rebuild] is true the state has been changed and didChangeDependencies() + /// will be called. + void reload({Function? afterReload, bool rebuild = false}) { + if (afterReload == null) { + if (rebuild) { + setState(() => didChangeDependencies()); + } else { + setState(() => 1); + } + } else { + setState(() { + afterReload(); + if (rebuild) { + didChangeDependencies(); + } + }); + } + } +} \ No newline at end of file diff --git a/lib/page/scopes/list_scope_custom.dart b/lib/page/scopes/list_scope_custom.dart new file mode 100644 index 0000000..a3ba05a --- /dev/null +++ b/lib/page/scopes/list_scope_custom.dart @@ -0,0 +1,178 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/widget_form.dart'; +import '../../persistence/persistence.dart'; +import 'list_scope_page.dart'; + +final i18n = I18N(); + +class ListScopeCustom extends State { + final globalData = GlobalData(); + late Future _futureDbData; + late AttendedPage attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateScope'); + final textController = TextEditingController(); + + ListScopeCustom(); + + @override + Widget build(BuildContext context) { + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('Overview scopes')), + drawer: globalData.drawerBuilder(context), + floatingActionButton: FloatingActionButton( + onPressed: () { + globalData.navigate(context, '/Scopes/create'); + }, + child: const Icon(Icons.add), + tooltip: 'Add a scope item'), + body: SafeArea( + child: FutureBuilder( + future: _futureDbData, + builder: (context, snapshot) { + Widget rc; + if (snapshot.connectionState != ConnectionState.done) { + rc = const CircularProgressIndicator(); + } else { + if (snapshot.hasData) { + final rows = attendedPage.getRows( + dbData: snapshot.data!, + columnList: + 'scope_id;scope_scope;scope_name;scope_value;scope_position', + onDone: () => setState(() => 1), + routeEdit: '/Scopes/edit', + context: context); + rc = buildFrame( + totalCount: snapshot.data?.count ?? rows.length, rows: rows); + } else if (snapshot.hasError) { + rc = Text('Backend problem: ${snapshot.error}'); + } else { + rc = const CircularProgressIndicator(); + } + } + return rc; + }, + )), + ); + return rc; + } + + Widget buildFrame({required JsonList rows, required int totalCount}) { + final padding = GlobalThemeData.padding; + final formItems = [ + FormItem( + TextFormField( + controller: textController, + decoration: InputDecoration(labelText: i18n.tr('Text')), + onSaved: (value) => _fieldData.text = value ?? ''), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => search(), child: Text(i18n.tr('Search'))), + weight: 12, + gapAbove: padding), + ]; + final form = Form( + key: _formKey, + child: Card( + color: GlobalThemeData.formBackgroundColor, + elevation: GlobalThemeData.formElevation, + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid(formItems, + screenWidth: attendedPage.pageStates.screenWidth, + padding: padding)))); + final table = DataTable( + columns: [ + DataColumn( + label: Text(i18n.tr('Id')), + ), + DataColumn( + label: Text(i18n.tr('Scope')), + ), + DataColumn( + label: Text(i18n.tr('Name')), + ), + DataColumn( + label: Text(i18n.tr('Value')), + ), + DataColumn( + label: Text(i18n.tr('Position')), + ), + ], + rows: rows as List, + ); + Widget? tabBar = attendedPage.buildChipBar( + totalCount: totalCount, + offset: _fieldData.theOffset, + pageSize: _fieldData.thePageSize, + onTap: (offset) { + _fieldData.theOffset = offset; + requestRecords(); + setState(() => 1); + }); + final frameWidget = ListView(children: [ + form, + if (tabBar != null) tabBar, + SizedBox(height: padding), + SizedBox(width: double.infinity, child: table), + ]); + return frameWidget; + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + requestRecords(); + } + + @override + void dispose() { + helperDummyUsage(DataType.string); + globalWidgetDummyUsage(); + textController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + } + + void requestRecords() => + _futureDbData = globalData.restPersistence.query(what: 'query', data: { + 'module': 'Scopes', + 'sql': 'list', + 'offset': _fieldData.theOffset, + 'size': _fieldData.thePageSize, + ':text': _fieldData.text, + }); + + void search() { + attendedPage.pageStates.dbDataState.clear(); + if (_formKey.currentState != null && _formKey.currentState!.validate()) { + _formKey.currentState!.save(); + requestRecords(); + setState(() => 1); + } + } +} + +class _FieldData { + int thePageSize = 10; + int theOffset = 0; + String text = ''; +} diff --git a/lib/page/scopes/list_scope_page.dart b/lib/page/scopes/list_scope_page.dart new file mode 100644 index 0000000..0c5c506 --- /dev/null +++ b/lib/page/scopes/list_scope_page.dart @@ -0,0 +1,64 @@ +// DO NOT CHANGE. This file is created by the meta_tool! +import 'package:flutter/material.dart'; + +import '../../meta/scopes_meta.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import 'list_scope_custom.dart'; + +class ListScopePage extends StatefulWidget { + final PageStates pageStates = PageStates(); + + ListScopePage() : super(); + + @override + _ListScopePageState createState() { + final rc = _ListScopePageState(); + rc.attendedPage = AttendedPage( + this, + rc, + GlobalData(), + ScopesMeta.instance.pageByName('list')!, + ScopesMeta.instance, + pageStates, + (afterReload, rebuild) => + rc.reload(afterReload: afterReload, rebuild: rebuild)); + pageStates.attendedPage = rc.attendedPage; + return rc; + } +} + +class _ListScopePageState extends ListScopeCustom { + _ListScopePageState() : super(); + + @override + void didChangeDependencies() { + final size = MediaQuery.of(context).size; + attendedPage.pageStates.screenWidth = size.width; + attendedPage.pageStates.screenHeight = size.height; + super.didChangeDependencies(); + } + + /// Renders the widget tree again. + /// + /// [afterReload] is a function used as parameter of setState(). + /// + /// If [rebuild] is true the state has been changed and didChangeDependencies() + /// will be called. + void reload({Function? afterReload, bool rebuild = false}) { + if (afterReload == null) { + if (rebuild) { + setState(() => didChangeDependencies()); + } else { + setState(() => 1); + } + } else { + setState(() { + afterReload(); + if (rebuild) { + didChangeDependencies(); + } + }); + } + } +} \ No newline at end of file diff --git a/lib/page/scopes/scope_data.dart b/lib/page/scopes/scope_data.dart new file mode 100644 index 0000000..64fa61b --- /dev/null +++ b/lib/page/scopes/scope_data.dart @@ -0,0 +1,126 @@ +// DO NOT CHANGE. This file is created by the meta_tool +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../persistence/data_record.dart'; + +class ScopeData extends DataRecord { + int? id; + String? scope; + String? name; + String? value; + int? position; + DateTime? createdAt; + String? createdBy; + DateTime? changedAt; + String? changedBy; + + ScopeData( + {this.id, + this.scope, + this.name, + this.value, + this.position, + this.createdAt, + this.createdBy, + this.changedAt, + this.changedBy}); + + ScopeData.createFromMap(DataMap map) { + fromMap(map); + } + + @override + void fromMap(DataMap map) { + id = map.containsKey('scope_id') + ? fromString(map['scope_id'], dataType: DataType.reference) + : null; + scope = map.containsKey('scope_scope') + ? fromString(map['scope_scope'], dataType: DataType.string) + : null; + name = map.containsKey('scope_name') + ? fromString(map['scope_name'], dataType: DataType.string) + : null; + value = map.containsKey('scope_value') + ? fromString(map['scope_value'], dataType: DataType.string) + : null; + position = map.containsKey('scope_position') + ? fromString(map['scope_position'], dataType: DataType.int) + : null; + createdAt = map.containsKey('scope_createdat') + ? fromString(map['scope_createdat'], dataType: DataType.datetime) + : null; + createdBy = map.containsKey('scope_createdby') + ? fromString(map['scope_createdby'], dataType: DataType.string) + : null; + changedAt = map.containsKey('scope_changedat') + ? fromString(map['scope_changedat'], dataType: DataType.datetime) + : null; + changedBy = map.containsKey('scope_changedby') + ? fromString(map['scope_changedby'], dataType: DataType.string) + : null; + } + + @override + int keyOf() { + return id ?? 0; + } + + @override + String nameOfKey() { + return 'scope_id'; + } + + static DataType? dataTypeOf(String name) { + DataType? rc; + switch (name) { + case 'id': + rc = DataType.reference; + break; + case 'scope': + rc = DataType.string; + break; + case 'name': + rc = DataType.string; + break; + case 'value': + rc = DataType.string; + break; + case 'position': + rc = DataType.int; + break; + case 'createdAt': + rc = DataType.datetime; + break; + case 'createdBy': + rc = DataType.string; + break; + case 'changedAt': + rc = DataType.datetime; + break; + case 'changedBy': + rc = DataType.string; + break; + default: + break; + } + return rc; + } + + @override + DataMap toMap({DataMap? map, bool clear = true}) { + map ??= DataMap(); + if (clear) { + map.clear(); + } + map['scope_id'] = id; + map['scope_scope'] = scope; + map['scope_name'] = name; + map['scope_value'] = value; + map['scope_position'] = position; + map['scope_createdat'] = createdAt; + map['scope_createdby'] = createdBy; + map['scope_changedat'] = changedAt; + map['scope_changedby'] = changedBy; + return map; + } +} diff --git a/lib/page/starters/create_starter_page.dart b/lib/page/starters/create_starter_page.dart index 5834647..f32e54e 100644 --- a/lib/page/starters/create_starter_page.dart +++ b/lib/page/starters/create_starter_page.dart @@ -28,6 +28,7 @@ class CreateStarterPage extends StatefulWidget { class _CreateStarterPageState extends CreateStarterCustom { _CreateStarterPageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _CreateStarterPageState extends CreateStarterCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/starters/delete_starter_page.dart b/lib/page/starters/delete_starter_page.dart index 0d16fe3..9a944ed 100644 --- a/lib/page/starters/delete_starter_page.dart +++ b/lib/page/starters/delete_starter_page.dart @@ -29,6 +29,7 @@ class DeleteStarterPage extends StatefulWidget { class _DeleteStarterPageState extends DeleteStarterCustom { _DeleteStarterPageState(int primaryKey) : super(primaryKey); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -59,4 +60,4 @@ class _DeleteStarterPageState extends DeleteStarterCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/starters/edit_starter_page.dart b/lib/page/starters/edit_starter_page.dart index 2768e25..553d8dd 100644 --- a/lib/page/starters/edit_starter_page.dart +++ b/lib/page/starters/edit_starter_page.dart @@ -29,6 +29,7 @@ class EditStarterPage extends StatefulWidget { class _EditStarterPageState extends EditStarterCustom { _EditStarterPageState(int primaryKey) : super(primaryKey); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -59,4 +60,4 @@ class _EditStarterPageState extends EditStarterCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/starters/list_starter_page.dart b/lib/page/starters/list_starter_page.dart index 795a7d2..974a2e3 100644 --- a/lib/page/starters/list_starter_page.dart +++ b/lib/page/starters/list_starter_page.dart @@ -28,6 +28,7 @@ class ListStarterPage extends StatefulWidget { class _ListStarterPageState extends ListStarterCustom { _ListStarterPageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _ListStarterPageState extends ListStarterCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/starters/starter_data.dart b/lib/page/starters/starter_data.dart index 46c8085..37bffc1 100644 --- a/lib/page/starters/starter_data.dart +++ b/lib/page/starters/starter_data.dart @@ -2,7 +2,6 @@ import '../../base/defines.dart'; import '../../base/helper.dart'; import '../../persistence/data_record.dart'; - class StarterData extends DataRecord { int? id; String? name; @@ -12,6 +11,7 @@ class StarterData extends DataRecord { String? createdBy; DateTime? changedAt; String? changedBy; + StarterData( {this.id, this.name, @@ -21,9 +21,11 @@ class StarterData extends DataRecord { this.createdBy, this.changedAt, this.changedBy}); + StarterData.createFromMap(DataMap map) { fromMap(map); } + @override void fromMap(DataMap map) { id = map.containsKey('starter_id') @@ -94,7 +96,6 @@ class StarterData extends DataRecord { } return rc; } - @override DataMap toMap({DataMap? map, bool clear = true}) { map ??= DataMap(); diff --git a/lib/page/structures/create_structure_custom.dart b/lib/page/structures/create_structure_custom.dart deleted file mode 100644 index 13de279..0000000 --- a/lib/page/structures/create_structure_custom.dart +++ /dev/null @@ -1,165 +0,0 @@ -// This file is created by the meta_tool. But it can be customized. -// It will never overridden by the meta_tool. -import 'package:flutter/material.dart'; - -import '../../base/defines.dart'; -import '../../base/helper.dart'; -import '../../base/i18n.dart'; -import '../../base/validators.dart'; -import '../../services/global_widget.dart'; -import '../../setting/global_data.dart'; -import '../../widget/attended_page.dart'; -import '../../widget/message_line.dart'; -import '../../widget/widget_form.dart'; -import 'create_structure_page.dart'; - -final i18n = I18N(); - -class CreateStructureCustom extends State - with MessageLine { - final globalData = GlobalData(); - late AttendedPage attendedPage; - final _fieldData = _FieldData(); - final GlobalKey _formKey = - GlobalKey(debugLabel: 'CreateStructure'); - final scopeController = TextEditingController(); - final nameController = TextEditingController(); - final valueController = TextEditingController(); - final positionController = TextEditingController(); - CreateStructureCustom(); - @override - Widget build(BuildContext context) { - final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('New Structure')), - drawer: globalData.drawerBuilder(context), - body: SafeArea(child: buildFrame())); - return rc; - } - - Widget buildFrame() { - final padding = GlobalThemeData.padding; - scopeController.text = _fieldData.scope; - nameController.text = _fieldData.name; - valueController.text = _fieldData.value; - positionController.text = asString(_fieldData.position); - final formItems = [ - FormItem( - TextFormField( - controller: scopeController, - decoration: InputDecoration(labelText: i18n.tr('Scope')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.scope = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: nameController, - decoration: InputDecoration(labelText: i18n.tr('Name')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.name = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: valueController, - decoration: InputDecoration(labelText: i18n.tr('Value')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.value = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: positionController, - decoration: InputDecoration(labelText: i18n.tr('Position')), - onSaved: (value) => _fieldData.position = - jsonToObject(value ?? '', dataType: DataType.int)), - weight: 6), - FormItem( - ElevatedButton( - onPressed: () => onVerifyAndStore(), - child: Text(i18n.tr('Save'))), - weight: 8, - gapAbove: 2 * padding), - FormItem( - ElevatedButton( - onPressed: () { - attendedPage.pageStates.dbDataState.clear(); - globalData.navigate(context, '/Structures/list'); - }, - child: Text(i18n.tr('Cancel')), - ), - weight: 4) - ]; - final rc = Form( - key: _formKey, - child: Card( - margin: - EdgeInsets.symmetric(vertical: padding, horizontal: padding), - child: Padding( - padding: EdgeInsets.symmetric( - vertical: padding, horizontal: padding), - child: WidgetForm.flexibleGrid( - formItems, - screenWidth: attendedPage.pageStates.screenWidth, - padding: padding, - )))); - return rc; - } - - @override - void dispose() { - helperDummyUsage(DataType.int); - globalWidgetDummyUsage(); - scopeController.dispose(); - nameController.dispose(); - valueController.dispose(); - positionController.dispose(); - super.dispose(); - } - - @override - void initState() { - super.initState(); - } - - void onStore() { - final parameters = { - 'module': 'Structures', - 'sql': 'insert', - }; - _fieldData.toMap(parameters); - globalData.restPersistence - .store(what: 'store', map: parameters) - .then((answer) { - if (answer.startsWith('id:')) { - final id = int.tryParse(answer.substring(3)); - if (id == null || id == 0) { - setError(i18n.tr('Saving data failed: $answer')); - setState(() => 1); - } else { - attendedPage.pageStates.dbDataState.clear(); - globalData.navigate(context, '/Structures/edit;$id'); - } - } - }); - } - - void onVerifyAndStore() { - if (_formKey.currentState != null && _formKey.currentState!.validate()) { - _formKey.currentState!.save(); - onStore(); - } - } -} - -class _FieldData { - String scope = ''; - String name = ''; - String value = ''; - int position = 0; - - void toMap(Map map) { - map[':scope'] = scope; - map[':name'] = name; - map[':value'] = value; - map[':position'] = asString(position, dbFormat: true); - map[':createdBy'] = GlobalData.loginUserName; - } -} diff --git a/lib/page/structures/create_structure_page.dart b/lib/page/structures/create_structure_page.dart deleted file mode 100644 index ab007e1..0000000 --- a/lib/page/structures/create_structure_page.dart +++ /dev/null @@ -1,61 +0,0 @@ -// DO NOT CHANGE. This file is created by the meta_tool! -import 'package:flutter/material.dart'; - -import '../../meta/structures_meta.dart'; -import '../../setting/global_data.dart'; -import '../../widget/attended_page.dart'; -import 'create_structure_custom.dart'; - -class CreateStructurePage extends StatefulWidget { - final PageStates pageStates = PageStates(); - CreateStructurePage() : super(); - @override - _CreateStructurePageState createState() { - final rc = _CreateStructurePageState(); - rc.attendedPage = AttendedPage( - this, - rc, - GlobalData(), - StructuresMeta.instance.pageByName('create')!, - StructuresMeta.instance, - pageStates, - (afterReload, rebuild) => - rc.reload(afterReload: afterReload, rebuild: rebuild)); - pageStates.attendedPage = rc.attendedPage; - return rc; - } -} - -class _CreateStructurePageState extends CreateStructureCustom { - _CreateStructurePageState() : super(); - @override - void didChangeDependencies() { - final size = MediaQuery.of(context).size; - attendedPage.pageStates.screenWidth = size.width; - attendedPage.pageStates.screenHeight = size.height; - super.didChangeDependencies(); - } - - /// Renders the widget tree again. - /// - /// [afterReload] is a function used as parameter of setState(). - /// - /// If [rebuild] is true the state has been changed and didChangeDependencies() - /// will be called. - void reload({Function? afterReload, bool rebuild = false}) { - if (afterReload == null) { - if (rebuild) { - setState(() => didChangeDependencies()); - } else { - setState(() => 1); - } - } else { - setState(() { - afterReload(); - if (rebuild) { - didChangeDependencies(); - } - }); - } - } -} diff --git a/lib/page/structures/delete_structure_custom.dart b/lib/page/structures/delete_structure_custom.dart deleted file mode 100644 index 043bc26..0000000 --- a/lib/page/structures/delete_structure_custom.dart +++ /dev/null @@ -1,177 +0,0 @@ -// This file is created by the meta_tool. But it can be customized. -// It will never overridden by the meta_tool. -import 'package:flutter/material.dart'; - -import '../../base/defines.dart'; -import '../../base/helper.dart'; -import '../../base/i18n.dart'; -import '../../base/validators.dart'; -import '../../persistence/persistence.dart'; -import '../../services/global_widget.dart'; -import '../../setting/global_data.dart'; -import '../../widget/attended_page.dart'; -import '../../widget/message_line.dart'; -import '../../widget/widget_form.dart'; -import 'delete_structure_page.dart'; - -final i18n = I18N(); - -class DeleteStructureCustom extends State - with MessageLine { - final int primaryKey; - final globalData = GlobalData(); - late Future _futureDbData; - late AttendedPage attendedPage; - final _fieldData = _FieldData(); - final GlobalKey _formKey = - GlobalKey(debugLabel: 'DeleteStructure'); - final scopeController = TextEditingController(); - final nameController = TextEditingController(); - final valueController = TextEditingController(); - final positionController = TextEditingController(); - DeleteStructureCustom(this.primaryKey); - @override - Widget build(BuildContext context) { - final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Delete Structure')), - drawer: globalData.drawerBuilder(context), - body: SafeArea( - child: FutureBuilder( - future: _futureDbData, - builder: (context, snapshot) { - final rc = attendedPage.loadRecord(snapshot, (record) { - _fieldData.fromMap(record); - return buildFrame(); - }); - return rc; - }))); - return rc; - } - - Widget buildFrame() { - final padding = GlobalThemeData.padding; - scopeController.text = _fieldData.scope; - nameController.text = _fieldData.name; - valueController.text = _fieldData.value; - positionController.text = asString(_fieldData.position); - final formItems = [ - FormItem( - TextFormField( - controller: scopeController, - decoration: InputDecoration(labelText: i18n.tr('Scope')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.scope = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: nameController, - decoration: InputDecoration(labelText: i18n.tr('Name')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.name = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: valueController, - decoration: InputDecoration(labelText: i18n.tr('Value')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.value = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: positionController, - decoration: InputDecoration(labelText: i18n.tr('Position')), - onSaved: (value) => _fieldData.position = - jsonToObject(value ?? '', dataType: DataType.int)), - weight: 6), - FormItem( - ElevatedButton( - onPressed: () => onVerifyAndDelete(), - child: Text(i18n.tr('Delete'))), - weight: 8, - gapAbove: 2 * padding), - FormItem( - ElevatedButton( - onPressed: () { - attendedPage.pageStates.dbDataState.clear(); - globalData.navigate(context, '/Structures/list'); - }, - child: Text(i18n.tr('Cancel')), - ), - weight: 4) - ]; - final rc = Form( - key: _formKey, - child: Card( - margin: - EdgeInsets.symmetric(vertical: padding, horizontal: padding), - child: Padding( - padding: EdgeInsets.symmetric( - vertical: padding, horizontal: padding), - child: WidgetForm.flexibleGrid( - formItems, - screenWidth: attendedPage.pageStates.screenWidth, - padding: padding, - )))); - return rc; - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - requestRecord(); - } - - @override - void dispose() { - helperDummyUsage(DataType.int); - globalWidgetDummyUsage(); - scopeController.dispose(); - nameController.dispose(); - valueController.dispose(); - positionController.dispose(); - super.dispose(); - } - - @override - void initState() { - super.initState(); - } - - void requestRecord() => _futureDbData = globalData.restPersistence.query( - what: 'query', - data: {'module': 'Users', 'sql': 'byId', ':id': primaryKey}); - - void onDelete() { - final parameters = { - 'module': 'Structures', - 'sql': 'delete', - ':id': primaryKey - }; - globalData.restPersistence - .store(what: 'store', map: parameters) - .then((answer) { - globalData.navigate(context, '/Structures/list'); - }); - } - - void onVerifyAndDelete() { - if (_formKey.currentState != null && _formKey.currentState!.validate()) { - _formKey.currentState!.save(); - onDelete(); - } - } -} - -class _FieldData { - String scope = ''; - String name = ''; - String value = ''; - int position = 0; - - void fromMap(Map map) { - scope = map['structure_scope']; - name = map['structure_name']; - value = map['structure_value']; - position = jsonToObject(map['structure_position'], dataType: DataType.int); - } -} diff --git a/lib/page/structures/delete_structure_page.dart b/lib/page/structures/delete_structure_page.dart deleted file mode 100644 index dda5535..0000000 --- a/lib/page/structures/delete_structure_page.dart +++ /dev/null @@ -1,62 +0,0 @@ -// DO NOT CHANGE. This file is created by the meta_tool! -import 'package:flutter/material.dart'; - -import '../../meta/structures_meta.dart'; -import '../../setting/global_data.dart'; -import '../../widget/attended_page.dart'; -import 'delete_structure_custom.dart'; - -class DeleteStructurePage extends StatefulWidget { - final int primaryKey; - final PageStates pageStates = PageStates(); - DeleteStructurePage(this.primaryKey) : super(); - @override - _DeleteStructurePageState createState() { - final rc = _DeleteStructurePageState(this.primaryKey); - rc.attendedPage = AttendedPage( - this, - rc, - GlobalData(), - StructuresMeta.instance.pageByName('delete')!, - StructuresMeta.instance, - pageStates, - (afterReload, rebuild) => - rc.reload(afterReload: afterReload, rebuild: rebuild)); - pageStates.attendedPage = rc.attendedPage; - return rc; - } -} - -class _DeleteStructurePageState extends DeleteStructureCustom { - _DeleteStructurePageState(int primaryKey) : super(primaryKey); - @override - void didChangeDependencies() { - final size = MediaQuery.of(context).size; - attendedPage.pageStates.screenWidth = size.width; - attendedPage.pageStates.screenHeight = size.height; - super.didChangeDependencies(); - } - - /// Renders the widget tree again. - /// - /// [afterReload] is a function used as parameter of setState(). - /// - /// If [rebuild] is true the state has been changed and didChangeDependencies() - /// will be called. - void reload({Function? afterReload, bool rebuild = false}) { - if (afterReload == null) { - if (rebuild) { - setState(() => didChangeDependencies()); - } else { - setState(() => 1); - } - } else { - setState(() { - afterReload(); - if (rebuild) { - didChangeDependencies(); - } - }); - } - } -} diff --git a/lib/page/structures/edit_structure_custom.dart b/lib/page/structures/edit_structure_custom.dart deleted file mode 100644 index 309734d..0000000 --- a/lib/page/structures/edit_structure_custom.dart +++ /dev/null @@ -1,188 +0,0 @@ -// This file is created by the meta_tool. But it can be customized. -// It will never overridden by the meta_tool. -import 'package:flutter/material.dart'; - -import '../../base/defines.dart'; -import '../../base/helper.dart'; -import '../../base/i18n.dart'; -import '../../base/validators.dart'; -import '../../persistence/persistence.dart'; -import '../../services/global_widget.dart'; -import '../../setting/global_data.dart'; -import '../../widget/attended_page.dart'; -import '../../widget/message_line.dart'; -import '../../widget/widget_form.dart'; -import 'edit_structure_page.dart'; - -final i18n = I18N(); - -class EditStructureCustom extends State with MessageLine { - final int primaryKey; - final globalData = GlobalData(); - late Future _futureDbData; - late AttendedPage attendedPage; - final _fieldData = _FieldData(); - final GlobalKey _formKey = - GlobalKey(debugLabel: 'EditStructure'); - final scopeController = TextEditingController(); - final nameController = TextEditingController(); - final valueController = TextEditingController(); - final positionController = TextEditingController(); - EditStructureCustom(this.primaryKey); - @override - Widget build(BuildContext context) { - final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Change Structure')), - drawer: globalData.drawerBuilder(context), - body: SafeArea( - child: FutureBuilder( - future: _futureDbData, - builder: (context, snapshot) { - final rc = attendedPage.loadRecord(snapshot, (record) { - _fieldData.fromMap(record); - return buildFrame(); - }); - return rc; - }))); - return rc; - } - - Widget buildFrame() { - final padding = GlobalThemeData.padding; - scopeController.text = _fieldData.scope; - nameController.text = _fieldData.name; - valueController.text = _fieldData.value; - positionController.text = asString(_fieldData.position); - final formItems = [ - FormItem( - TextFormField( - controller: scopeController, - decoration: InputDecoration(labelText: i18n.tr('Scope')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.scope = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: nameController, - decoration: InputDecoration(labelText: i18n.tr('Name')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.name = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: valueController, - decoration: InputDecoration(labelText: i18n.tr('Value')), - validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.value = value ?? ''), - weight: 6), - FormItem( - TextFormField( - controller: positionController, - decoration: InputDecoration(labelText: i18n.tr('Position')), - onSaved: (value) => _fieldData.position = - jsonToObject(value ?? '', dataType: DataType.int)), - weight: 6), - FormItem( - ElevatedButton( - onPressed: () => onVerifyAndStore(), - child: Text(i18n.tr('Save'))), - weight: 8, - gapAbove: 2 * padding), - FormItem( - ElevatedButton( - onPressed: () { - attendedPage.pageStates.dbDataState.clear(); - globalData.navigate(context, '/Structures/list'); - }, - child: Text(i18n.tr('Cancel')), - ), - weight: 4) - ]; - final rc = Form( - key: _formKey, - child: Card( - margin: - EdgeInsets.symmetric(vertical: padding, horizontal: padding), - child: Padding( - padding: EdgeInsets.symmetric( - vertical: padding, horizontal: padding), - child: WidgetForm.flexibleGrid( - formItems, - screenWidth: attendedPage.pageStates.screenWidth, - padding: padding, - )))); - return rc; - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - requestRecord(); - } - - @override - void dispose() { - helperDummyUsage(DataType.int); - globalWidgetDummyUsage(); - scopeController.dispose(); - nameController.dispose(); - valueController.dispose(); - positionController.dispose(); - super.dispose(); - } - - @override - void initState() { - super.initState(); - } - - void requestRecord() => _futureDbData = globalData.restPersistence.query( - what: 'query', - data: {'module': 'Users', 'sql': 'byId', ':id': primaryKey}); - - void onStore() { - final parameters = { - 'module': 'Structures', - 'sql': 'update', - ':id': primaryKey - }; - _fieldData.toMap(parameters); - globalData.restPersistence - .store(what: 'store', map: parameters) - .then((answer) { - requestRecord(); - attendedPage.pageStates.dbDataState.clear(); - setState(() => 1); - }); - } - - void onVerifyAndStore() { - if (_formKey.currentState != null && _formKey.currentState!.validate()) { - _formKey.currentState!.save(); - onStore(); - } - } -} - -class _FieldData { - String scope = ''; - String name = ''; - String value = ''; - int position = 0; - - void fromMap(Map map) { - scope = map['structure_scope']; - name = map['structure_name']; - value = map['structure_value']; - position = jsonToObject(map['structure_position'], dataType: DataType.int); - } - - void toMap(Map map) { - // please set outside: map[':id'] = primaryKey; - map[':scope'] = scope; - map[':name'] = name; - map[':value'] = value; - map[':position'] = asString(position, dbFormat: true); - map[':changedBy'] = GlobalData.loginUserName; - } -} diff --git a/lib/page/structures/edit_structure_page.dart b/lib/page/structures/edit_structure_page.dart deleted file mode 100644 index 5c4ef5f..0000000 --- a/lib/page/structures/edit_structure_page.dart +++ /dev/null @@ -1,62 +0,0 @@ -// DO NOT CHANGE. This file is created by the meta_tool! -import 'package:flutter/material.dart'; - -import '../../meta/structures_meta.dart'; -import '../../setting/global_data.dart'; -import '../../widget/attended_page.dart'; -import 'edit_structure_custom.dart'; - -class EditStructurePage extends StatefulWidget { - final int primaryKey; - final PageStates pageStates = PageStates(); - EditStructurePage(this.primaryKey) : super(); - @override - _EditStructurePageState createState() { - final rc = _EditStructurePageState(this.primaryKey); - rc.attendedPage = AttendedPage( - this, - rc, - GlobalData(), - StructuresMeta.instance.pageByName('edit')!, - StructuresMeta.instance, - pageStates, - (afterReload, rebuild) => - rc.reload(afterReload: afterReload, rebuild: rebuild)); - pageStates.attendedPage = rc.attendedPage; - return rc; - } -} - -class _EditStructurePageState extends EditStructureCustom { - _EditStructurePageState(int primaryKey) : super(primaryKey); - @override - void didChangeDependencies() { - final size = MediaQuery.of(context).size; - attendedPage.pageStates.screenWidth = size.width; - attendedPage.pageStates.screenHeight = size.height; - super.didChangeDependencies(); - } - - /// Renders the widget tree again. - /// - /// [afterReload] is a function used as parameter of setState(). - /// - /// If [rebuild] is true the state has been changed and didChangeDependencies() - /// will be called. - void reload({Function? afterReload, bool rebuild = false}) { - if (afterReload == null) { - if (rebuild) { - setState(() => didChangeDependencies()); - } else { - setState(() => 1); - } - } else { - setState(() { - afterReload(); - if (rebuild) { - didChangeDependencies(); - } - }); - } - } -} diff --git a/lib/page/structures/list_structure_custom.dart b/lib/page/structures/list_structure_custom.dart deleted file mode 100644 index 4cec578..0000000 --- a/lib/page/structures/list_structure_custom.dart +++ /dev/null @@ -1,176 +0,0 @@ -// This file is created by the meta_tool. But it can be customized. -// It will never overridden by the meta_tool. -import 'package:flutter/material.dart'; - -import '../../base/defines.dart'; -import '../../base/helper.dart'; -import '../../base/i18n.dart'; -import '../../services/global_widget.dart'; -import '../../setting/global_data.dart'; -import '../../widget/attended_page.dart'; -import '../../widget/widget_form.dart'; -import '../../persistence/persistence.dart'; -import 'list_structure_page.dart'; - -final i18n = I18N(); - -class ListStructureCustom extends State { - final globalData = GlobalData(); - late Future _futureDbData; - late AttendedPage attendedPage; - final _fieldData = _FieldData(); - final GlobalKey _formKey = - GlobalKey(debugLabel: 'CreateStructure'); - final textController = TextEditingController(); - ListStructureCustom(); - @override - Widget build(BuildContext context) { - final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Overview structures')), - drawer: globalData.drawerBuilder(context), - floatingActionButton: FloatingActionButton( - onPressed: () { - globalData.navigate(context, '/Structures/create'); - }, - child: const Icon(Icons.add), - tooltip: 'Add a structure item'), - body: SafeArea( - child: FutureBuilder( - future: _futureDbData, - builder: (context, snapshot) { - Widget rc; - if (snapshot.connectionState != ConnectionState.done) { - rc = const CircularProgressIndicator(); - } else { - if (snapshot.hasData) { - final rows = attendedPage.getRows( - dbData: snapshot.data!, - columnList: - 'structure_id;structure_scope;structure_name;structure_value;structure_position', - onDone: () => setState(() => 1), - routeEdit: '/Structures/edit', - context: context); - rc = buildFrame( - totalCount: snapshot.data?.count ?? rows.length, rows: rows); - } else if (snapshot.hasError) { - rc = Text('Backend problem: ${snapshot.error}'); - } else { - rc = const CircularProgressIndicator(); - } - } - return rc; - }, - )), - ); - return rc; - } - - Widget buildFrame({required JsonList rows, required int totalCount}) { - final padding = GlobalThemeData.padding; - final formItems = [ - FormItem( - TextFormField( - controller: textController, - decoration: InputDecoration(labelText: i18n.tr('Text')), - onSaved: (value) => _fieldData.text = value ?? ''), - weight: 6), - FormItem( - ElevatedButton( - onPressed: () => search(), child: Text(i18n.tr('Search'))), - weight: 12, - gapAbove: padding), - ]; - final form = Form( - key: _formKey, - child: Card( - color: GlobalThemeData.formBackgroundColor, - elevation: GlobalThemeData.formElevation, - margin: - EdgeInsets.symmetric(vertical: padding, horizontal: padding), - child: Padding( - padding: EdgeInsets.symmetric( - vertical: padding, horizontal: padding), - child: WidgetForm.flexibleGrid(formItems, - screenWidth: attendedPage.pageStates.screenWidth, - padding: padding)))); - final table = DataTable( - columns: [ - DataColumn( - label: Text(i18n.tr('Id')), - ), - DataColumn( - label: Text(i18n.tr('Scope')), - ), - DataColumn( - label: Text(i18n.tr('Name')), - ), - DataColumn( - label: Text(i18n.tr('Value')), - ), - DataColumn( - label: Text(i18n.tr('Position')), - ), - ], - rows: rows as List, - ); - Widget? tabBar = attendedPage.buildChipBar( - totalCount: totalCount, - offset: _fieldData.theOffset, - pageSize: _fieldData.thePageSize, - onTap: (offset) { - _fieldData.theOffset = offset; - requestRecords(); - setState(() => 1); - }); - final frameWidget = ListView(children: [ - form, - if (tabBar != null) tabBar, - SizedBox(height: padding), - SizedBox(width: double.infinity, child: table), - ]); - return frameWidget; - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - requestRecords(); - } - - @override - void dispose() { - helperDummyUsage(DataType.string); - globalWidgetDummyUsage(); - textController.dispose(); - super.dispose(); - } - - @override - void initState() { - super.initState(); - } - - void requestRecords() => - _futureDbData = globalData.restPersistence.query(what: 'query', data: { - 'module': 'Structures', - 'sql': 'list', - 'offset': _fieldData.theOffset, - 'size': _fieldData.thePageSize, - ':text': _fieldData.text, - }); - - void search() { - attendedPage.pageStates.dbDataState.clear(); - if (_formKey.currentState != null && _formKey.currentState!.validate()) { - _formKey.currentState!.save(); - requestRecords(); - setState(() => 1); - } - } -} - -class _FieldData { - int thePageSize = 10; - int theOffset = 0; - String text = ''; -} diff --git a/lib/page/structures/list_structure_page.dart b/lib/page/structures/list_structure_page.dart deleted file mode 100644 index 4b6d716..0000000 --- a/lib/page/structures/list_structure_page.dart +++ /dev/null @@ -1,61 +0,0 @@ -// DO NOT CHANGE. This file is created by the meta_tool! -import 'package:flutter/material.dart'; - -import '../../meta/structures_meta.dart'; -import '../../setting/global_data.dart'; -import '../../widget/attended_page.dart'; -import 'list_structure_custom.dart'; - -class ListStructurePage extends StatefulWidget { - final PageStates pageStates = PageStates(); - ListStructurePage() : super(); - @override - _ListStructurePageState createState() { - final rc = _ListStructurePageState(); - rc.attendedPage = AttendedPage( - this, - rc, - GlobalData(), - StructuresMeta.instance.pageByName('list')!, - StructuresMeta.instance, - pageStates, - (afterReload, rebuild) => - rc.reload(afterReload: afterReload, rebuild: rebuild)); - pageStates.attendedPage = rc.attendedPage; - return rc; - } -} - -class _ListStructurePageState extends ListStructureCustom { - _ListStructurePageState() : super(); - @override - void didChangeDependencies() { - final size = MediaQuery.of(context).size; - attendedPage.pageStates.screenWidth = size.width; - attendedPage.pageStates.screenHeight = size.height; - super.didChangeDependencies(); - } - - /// Renders the widget tree again. - /// - /// [afterReload] is a function used as parameter of setState(). - /// - /// If [rebuild] is true the state has been changed and didChangeDependencies() - /// will be called. - void reload({Function? afterReload, bool rebuild = false}) { - if (afterReload == null) { - if (rebuild) { - setState(() => didChangeDependencies()); - } else { - setState(() => 1); - } - } else { - setState(() { - afterReload(); - if (rebuild) { - didChangeDependencies(); - } - }); - } - } -} diff --git a/lib/page/structures/structure_data.dart b/lib/page/structures/structure_data.dart deleted file mode 100644 index c5d8586..0000000 --- a/lib/page/structures/structure_data.dart +++ /dev/null @@ -1,123 +0,0 @@ -// DO NOT CHANGE. This file is created by the meta_tool -import '../../base/defines.dart'; -import '../../base/helper.dart'; -import '../../persistence/data_record.dart'; - -class StructureData extends DataRecord { - int? id; - String? scope; - String? name; - String? value; - int? position; - DateTime? createdAt; - String? createdBy; - DateTime? changedAt; - String? changedBy; - StructureData( - {this.id, - this.scope, - this.name, - this.value, - this.position, - this.createdAt, - this.createdBy, - this.changedAt, - this.changedBy}); - StructureData.createFromMap(DataMap map) { - fromMap(map); - } - @override - void fromMap(DataMap map) { - id = map.containsKey('structure_id') - ? fromString(map['structure_id'], dataType: DataType.reference) - : null; - scope = map.containsKey('structure_scope') - ? fromString(map['structure_scope'], dataType: DataType.string) - : null; - name = map.containsKey('structure_name') - ? fromString(map['structure_name'], dataType: DataType.string) - : null; - value = map.containsKey('structure_value') - ? fromString(map['structure_value'], dataType: DataType.string) - : null; - position = map.containsKey('structure_position') - ? fromString(map['structure_position'], dataType: DataType.int) - : null; - createdAt = map.containsKey('structure_createdat') - ? fromString(map['structure_createdat'], dataType: DataType.datetime) - : null; - createdBy = map.containsKey('structure_createdby') - ? fromString(map['structure_createdby'], dataType: DataType.string) - : null; - changedAt = map.containsKey('structure_changedat') - ? fromString(map['structure_changedat'], dataType: DataType.datetime) - : null; - changedBy = map.containsKey('structure_changedby') - ? fromString(map['structure_changedby'], dataType: DataType.string) - : null; - } - - @override - int keyOf() { - return id ?? 0; - } - - @override - String nameOfKey() { - return 'structure_id'; - } - - static DataType? dataTypeOf(String name) { - DataType? rc; - switch (name) { - case 'id': - rc = DataType.reference; - break; - case 'scope': - rc = DataType.string; - break; - case 'name': - rc = DataType.string; - break; - case 'value': - rc = DataType.string; - break; - case 'position': - rc = DataType.int; - break; - case 'createdAt': - rc = DataType.datetime; - break; - case 'createdBy': - rc = DataType.string; - break; - case 'changedAt': - rc = DataType.datetime; - break; - case 'changedBy': - rc = DataType.string; - break; - default: - break; - } - return rc; - } - - @override - DataMap toMap({DataMap? map, bool clear = true}) { - map ??= DataMap(); - if (clear) { - map.clear(); - } - map['structure_id'] = id; - map['structure_scope'] = scope; - map['structure_name'] = name; - map['structure_value'] = value; - map['structure_position'] = position; - map['structure_createdat'] = createdAt; - map['structure_createdby'] = createdBy; - map['structure_changedat'] = changedAt; - map['structure_changedby'] = changedBy; - return map; - } -} diff --git a/lib/page/users/create_user_page.dart b/lib/page/users/create_user_page.dart index 9428ee7..4d6f4ad 100644 --- a/lib/page/users/create_user_page.dart +++ b/lib/page/users/create_user_page.dart @@ -28,6 +28,7 @@ class CreateUserPage extends StatefulWidget { class _CreateUserPageState extends CreateUserCustom { _CreateUserPageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _CreateUserPageState extends CreateUserCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/users/delete_user_page.dart b/lib/page/users/delete_user_page.dart index 5b62757..91c7968 100644 --- a/lib/page/users/delete_user_page.dart +++ b/lib/page/users/delete_user_page.dart @@ -29,6 +29,7 @@ class DeleteUserPage extends StatefulWidget { class _DeleteUserPageState extends DeleteUserCustom { _DeleteUserPageState(int primaryKey) : super(primaryKey); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -59,4 +60,4 @@ class _DeleteUserPageState extends DeleteUserCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/users/edit_user_page.dart b/lib/page/users/edit_user_page.dart index 18ae325..5378365 100644 --- a/lib/page/users/edit_user_page.dart +++ b/lib/page/users/edit_user_page.dart @@ -29,6 +29,7 @@ class EditUserPage extends StatefulWidget { class _EditUserPageState extends EditUserCustom { _EditUserPageState(int primaryKey) : super(primaryKey); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -59,4 +60,4 @@ class _EditUserPageState extends EditUserCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/users/list_user_page.dart b/lib/page/users/list_user_page.dart index b4f014c..a83638e 100644 --- a/lib/page/users/list_user_page.dart +++ b/lib/page/users/list_user_page.dart @@ -28,6 +28,7 @@ class ListUserPage extends StatefulWidget { class _ListUserPageState extends ListUserCustom { _ListUserPageState() : super(); + @override void didChangeDependencies() { final size = MediaQuery.of(context).size; @@ -58,4 +59,4 @@ class _ListUserPageState extends ListUserCustom { }); } } -} +} \ No newline at end of file diff --git a/lib/page/users/user_data.dart b/lib/page/users/user_data.dart index 61a9eea..7cac062 100644 --- a/lib/page/users/user_data.dart +++ b/lib/page/users/user_data.dart @@ -2,30 +2,34 @@ import '../../base/defines.dart'; import '../../base/helper.dart'; import '../../persistence/data_record.dart'; - class UserData extends DataRecord { int? id; String? name; String? displayName; String? email; int? role; + int? status; DateTime? createdAt; String? createdBy; DateTime? changedAt; String? changedBy; + UserData( {this.id, this.name, this.displayName, this.email, this.role, + this.status, this.createdAt, this.createdBy, this.changedAt, this.changedBy}); + UserData.createFromMap(DataMap map) { fromMap(map); } + @override void fromMap(DataMap map) { id = map.containsKey('user_id') @@ -43,6 +47,9 @@ class UserData extends DataRecord { role = map.containsKey('user_role') ? fromString(map['user_role'], dataType: DataType.reference) : null; + status = map.containsKey('user_status') + ? fromString(map['user_status'], dataType: DataType.reference) + : null; createdAt = map.containsKey('user_createdat') ? fromString(map['user_createdat'], dataType: DataType.datetime) : null; @@ -85,6 +92,9 @@ class UserData extends DataRecord { case 'role': rc = DataType.reference; break; + case 'status': + rc = DataType.reference; + break; case 'createdAt': rc = DataType.datetime; break; @@ -102,7 +112,6 @@ class UserData extends DataRecord { } return rc; } - @override DataMap toMap({DataMap? map, bool clear = true}) { map ??= DataMap(); @@ -114,6 +123,7 @@ class UserData extends DataRecord { map['user_displayname'] = displayName; map['user_email'] = email; map['user_role'] = role; + map['user_status'] = status; map['user_createdat'] = createdAt; map['user_createdby'] = createdBy; map['user_changedat'] = changedAt; diff --git a/lib/services/global_widget.dart b/lib/services/global_widget.dart index 8449761..c557efd 100644 --- a/lib/services/global_widget.dart +++ b/lib/services/global_widget.dart @@ -32,6 +32,32 @@ void comboRolesFromBackend( {'module': 'global', 'sql': 'comboRoles'}, onDone); } +/// Returns the combobox items filled with data of the table users. +/// +/// [textUndefined]: null: no additional entry. Otherwise: a additional entry is +/// inserted at position 0 with this text and the value 0. +/// +/// [attendedPage]: the context of the calling page. +/// +/// Returns a list of combobox items selecting a user. +List>? comboUsers( + String textUndefined, AttendedPage attendedPage) { + final rc = _combo('comboUsers.global', 'user_id', 'user_displayname', + textUndefined, attendedPage); + return rc; +} + +/// Requests the database data for combo boxes from the backend. +/// +/// [dbDataState]: Stores the request and the answer of the request. +/// +/// [onDone]: A method executed after arriving the response. +void comboUsersFromBackend( + {required AttendedPage attendedPage, required Function() onDone}) { + _requestData('comboUsers.global', attendedPage, + {'module': 'global', 'sql': 'comboActiveUsers'}, onDone); +} + /// This function is only used to avoid compiler warning "unused import" /// for generated code. void globalWidgetDummyUsage() { diff --git a/metatool/Compile b/metatool/Compile index 43dd5c8..00e3ff2 100755 --- a/metatool/Compile +++ b/metatool/Compile @@ -1,4 +1,4 @@ #! /bin/bash APP=meta_tool OUT=$(dirname $(pwd))/tools -/usr/bin/dart compile exe bin/$APP.dart -o $OUT/$APP +dart compile exe bin/$APP.dart -o $OUT/$APP diff --git a/test/i18n_text_parser_test.dart b/test/i18n_text_parser_test.dart index 435a75a..41978d5 100644 --- a/test/i18n_text_parser_test.dart +++ b/test/i18n_text_parser_test.dart @@ -72,9 +72,9 @@ msgstr "" content = fileSync.fileAsString(fn); expect(content.replaceAll(RegExp(r'Date: 2[-+\w2: ]+'), 'Date: *'), r'''# Texts of module Statistic, created by i18n_text_parser'); -# Copyright (C) 2021-2021 J. Hamatoma +# Copyright (C) 2021-2022 J. Hamatoma # License: CC0 1.0 Universal -# J. Hamatoma , 2021. +# J. Hamatoma , 2022. # #, fuzzy msgid "" @@ -104,9 +104,9 @@ msgstr[1] "" final content = fileSync.fileAsString(fn); expect(content.replaceAll(RegExp(r'Date: 2[-+\w2: ]+'), 'Date: *'), r'''# Texts of module Statistic, created by i18n_text_parser'); -# Copyright (C) 2021-2021 J. Hamatoma +# Copyright (C) 2021-2022 J. Hamatoma # License: CC0 1.0 Universal -# J. Hamatoma , 2021. +# J. Hamatoma , 2022. # #, fuzzy msgid "" diff --git a/test/validators_test.dart b/test/validators_test.dart new file mode 100644 index 0000000..a7c7a48 --- /dev/null +++ b/test/validators_test.dart @@ -0,0 +1,62 @@ +import 'package:dart_bones/dart_bones.dart'; +import 'package:exhibition/base/i18n.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../lib/base/validators.dart'; + +I18N i18n = I18N.internal(MemoryLogger()); + +void main() { + final logger = MemoryLogger(LEVEL_FINE); + i18n = I18N.internal(logger); + test('isEmail', () { + expect(isEmail('info@hamatoma.de'), isNull); + expect(isEmail('/info@hamatoma.de'), matches(RegExp('"/"'))); + expect(isEmail('info@hamatoma,de'), matches(RegExp('","'))); + expect(isEmail('info@hamatoma'), isNotNull); + expect(isEmail('x@info@hamatoma'), isNotNull); + expect(isEmail('x@info@hamatoma.de'), matches(RegExp('"@"'))); + }); + test('isInt', () { + expect(isInt('1234'), isNull); + expect(isInt('0'), isNull); + expect(isInt('-330'), isNull); + expect(isInt('+330'), isNull); + expect(isInt('.123'), isNotNull); + expect(isInt('3D'), isNotNull); + expect(isInt(''), isNotNull); + expect(isInt(null), isNotNull); + }); + test('isNat', () { + expect(isNat('1234'), isNull); + expect(isNat('0'), isNull); + expect(isNat('-330'), isNotNull); + expect(isNat('+330'), isNotNull); + expect(isNat('.123'), isNotNull); + expect(isNat('3D'), isNotNull); + expect(isNat(''), isNotNull); + expect(isNat(null), isNotNull); + }); + test('isTime', () { + expect(isTime('0'), isNull); + expect(isTime('1'), isNull); + expect(isTime('23'), isNull); + expect(isTime('24'), matches('24')); + expect(isTime('00:00'), isNull); + expect(isTime('00:59'), isNull); + expect(isTime('0:3'), isNull); + expect(isTime('0:39'), isNull); + expect(isTime('23:59'), isNull); + expect(isTime('23:59'), isNull); + expect(isTime(''), isNotNull); + expect(isTime(null), isNotNull); + expect(isTime(null, mayBeEmpty: true), isNull); + expect(isTime('', mayBeEmpty: true), isNull); + }); + test('notEmpty', () { + expect(notEmpty('0'), isNull); + expect(notEmpty('abc'), isNull); + expect(notEmpty(''), isNotNull); + expect(notEmpty(null), isNotNull); + }); +}