- name: list
type: list
sql: "SELECT * from configuration
- WHERE configuration_name like :configuration_name AND configuration_scope like :configuration_scope AND configuration_scope like :configuration_scope;"
+ WHERE configuration_property like :configuration_property AND configuration_scope like :configuration_scope;"
- name: list
type: list
sql: "SELECT * from user
- WHERE user_name like :user_name AND user_role like :user_role AND user_role like :user_role;"
+ WHERE user_name like :user_name AND (:user_role is null or user_role=:user_role);"
import 'package:flutter/material.dart';
import 'src/helper/settings.dart';
+import 'src/page/demo_page.dart';
import 'src/page/login_page.dart';
import 'src/page/role/role_create_page.dart';
import 'src/page/role/role_list_page.dart';
+import 'src/page/user/user_create_page.dart';
+import 'src/page/user/user_list_page.dart';
import 'src/private/bsettings.dart';
class BoneApp extends StatefulWidget {
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
- initialRoute: '/role/list',
+ initialRoute: '/configuration/list',
onGenerateRoute: _getRoute,
);
}
MaterialPageRoute route;
StatefulWidget page;
switch (settings.name) {
+ case '/demo':
+ page = DemoPage(BSettings.lastInstance.pageData);
+ break;
case '/role/list':
page = RoleListPage(BSettings.lastInstance.pageData);
break;
case '/role/create':
page = RoleCreatePage(BSettings.lastInstance.pageData);
break;
- /*
case '/user/list':
page = UserListPage(BSettings.lastInstance.pageData);
break;
case '/user/create':
page = UserCreatePage(BSettings.lastInstance.pageData);
break;
+ /*
case '/configuration/list':
page = ConfigurationListPage(BSettings.lastInstance.pageData);
break;
import 'package:dart_bones/dart_bones.dart';
import 'package:intl/intl.dart';
+
import '../model/model_types.dart';
class StringHelper {
- static final regExpTrue = RegExp(r'^(true|yes)$', caseSensitive: false);
- static final regExpFalse = RegExp(r'^(false|no)$', caseSensitive: false);
+ static final regExpTrue = RegExp(r'^(true|yes|t)$', caseSensitive: false);
+ static final regExpFalse = RegExp(r'^(false|no|f)$', caseSensitive: false);
static const locale = 'de_DE';
+ /// Convert [value] into a string for storing in a database respecting [dataType].
+ static String asDatabaseString(dynamic value, DataType dataType) {
+ if (value == null) {
+ value = 'NULL';
+ } else {
+ switch (dataType) {
+ case DataType.dateTime:
+ value = DateFormat('yyyy-MM-dd HH:mm:ss').format(value);
+ break;
+ case DataType.date:
+ value = DateFormat('yyyy-MM-dd').format(value);
+ break;
+ case DataType.bool:
+ value = value ? 'T' : 'F';
+ break;
+ default:
+ value = value.toString();
+ break;
+ }
+ }
+ return value;
+ }
+
/// Converts any [data] to a string.
- /// [withSeconds]: only used for DateTime data: true: seconds will be shown
- /// [sortable]: only used for DateTime data: true: the date is sortable (year first)
+ /// [withSeconds]: only used for DateTime data: true: seconds will be shown.
+ /// [sortable]: only used for DateTime data: true: the date is sortable (year first).
+ /// [nullString]: is the result if [data] is null
static String asString(dynamic data,
- {bool withSeconds = true, bool sortable = true}) {
+ {bool withSeconds = true, bool sortable = true, String nullString}) {
String rc;
- if (data is String) {
+ if (data == null) {
+ rc = nullString;
+ } else if (data is String) {
rc = data;
} else if (data is DateTime) {
rc = dateTimeToString(data, withSeconds: withSeconds, sortable: sortable);
}
return rc;
}
-
- /// Convert [value] into a string for storing in a database respecting [dataType].
- static String asDatabaseString(dynamic value, DataType dataType) {
- if (value == null) {
- value = 'NULL';
- } else {
- switch (dataType) {
- case DataType.dateTime:
- value = DateFormat('yyyy-MM-dd HH:mm:ss').format(value);
- break;
- case DataType.date:
- value = DateFormat('yyyy-MM-dd').format(value);
- break;
- case DataType.bool:
- value = value ? 'T' : 'F';
- break;
- default:
- value = value.toString();
- break;
- }
- }
- return value;
- }
}
if (col.hasOption('doStore') ||
(!col.hasOption('hidden') &&
(!isCreatePage || !col.hasOption('primary')))) {
- final field = DbReferenceModel.direct(section, page, col, logger);
+ final field = DbReferenceModel.fromColumn(section, page, col, logger);
page.addField(field);
page.widgets.add(field);
}
import 'package:dart_bones/dart_bones.dart';
import 'package:meta/meta.dart';
+
import 'model_base.dart';
import 'model_types.dart';
import 'table_model.dart';
import 'widget_model.dart';
+import 'combo_base_model.dart';
/// Describes a column of a database table.
-class ColumnModel extends WidgetModel {
+class ColumnModel extends ComboBaseModel {
static final regExprOptions = RegExp(
r'^(undef|readonly|disabled|doStore|hidden|null|notnull|password|primary|required|unique)$');
- String name;
- String label;
- String toolTip;
- DataType dataType;
+ static final regExprListDbOption =
+ RegExp(r'^\w+\.\w+;\w+ \w+(?:;(:? ?:\w+=[^ ]*?)+)?$');
int size;
int rows;
- List<String> options;
final TableModel table;
final Map<String, dynamic> map;
String foreignKey;
/// A constructor used in the parser.
ColumnModel(this.table, this.map, BaseLogger logger)
- : super(null, null, WidgetModelType.column, logger);
+ : super(null, null, map, WidgetModelType.column, logger);
/// A constructor for columns created by the program.
- ColumnModel.raw(
- {@required this.name,
+ ColumnModel.direct(
+ {@required String name,
@required this.table,
- @required this.label,
- @required this.dataType,
- @required this.options,
+ @required String label,
+ @required DataType dataType,
+ @required List<String> options,
+ String toolTip,
+ String listOption,
+ ComboboxListType listType,
this.size,
this.map,
+ List<String> texts,
+ List<dynamic> values,
BaseLogger logger})
- : super(null, null, WidgetModelType.column, logger);
+ : super.direct(section: null, page: null,
+ map: null,
+ name: name, label: label, toolTip: toolTip, texts: texts, values: values,
+ listOption: listOption, listType: listType, options: options,
+ widgetType: WidgetModelType.column, logger: logger);
/// Dumps the instance into a [StringBuffer]
StringBuffer dump(StringBuffer stringBuffer) {
stringBuffer.write(
- ' column $name: $dataType "$label" options: ${options.join(' ')}\n');
+ ' column $name: $dataType "$label" options: ${options?.join(' ')}\n');
return stringBuffer;
}
/// Tests whether a given [option] is part of [options].
bool hasOption(String option) {
- bool rc = options.contains(option);
+ bool rc = options?.contains(option) ?? false;
return rc;
}
name = parseString('column', map, required: true);
checkSuperfluousAttributes(
map,
- 'column dataType foreignKey label options rows size tooTip widgetType'
+ 'column dataType foreignKey label listOption listType options rows size texts tooTip values widgetType'
.split(' '));
+ super.parse();
dataType =
parseEnum<DataType>('dataType', map, DataType.values, required: true);
- label = parseString('label', map, required: false);
- toolTip = parseString('toolTip', map, required: false);
size = parseInt('size', map, required: dataType == DataType.string);
rows = parseInt('rows', map);
- options = parseOptions('options', map);
checkOptionsByRegExpr(options, regExprOptions);
if (options.contains('primary')) {
if (!options.contains('notnull')) {
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+
+import 'field_model.dart';
+import 'model_types.dart';
+import 'page_model.dart';
+import 'section_model.dart';
+import 'widget_model.dart';
+
+/// A base class for combobox items like ComboboxModel, ColumnModel and DbReferenceModel.
+abstract class ComboBaseModel extends FieldModel {
+ static final regExprListDbOption =
+ RegExp(r'^\w+\.\w+;\w+ \w+(?:;(:? ?:\w+=[^ ]*?)+)?$');
+ static final regExprListConfiguration = RegExp(r'^scope:\w+$');
+ List<String> texts;
+ List values;
+ String listOption;
+ ComboboxListType listType;
+
+ ComboBaseModel(SectionModel section, PageModel page, Map map,
+ WidgetModelType widgetType, BaseLogger logger)
+ : super(section, page, map, widgetType, logger);
+
+ ComboBaseModel.direct(
+ {SectionModel section,
+ PageModel page,
+ Map map,
+ String name,
+ String label,
+ String toolTip,
+ DataType dataType,
+ List<String> options,
+ this.texts,
+ this.values,
+ this.listOption,
+ this.listType,
+ WidgetModelType widgetType,
+ BaseLogger logger})
+ : super.direct(section, page, map, widgetType, name, label, toolTip,
+ dataType, options, logger);
+
+/*
+ SectionModel section,
+ PageModel page,
+ this.map,
+ WidgetModelType fieldModelType,
+ String name,
+ String label,
+ String toolTip,
+ DataType dataType,
+ List<String> options,
+ BaseLogger logger,
+
+ */
+
+ /// Parses the map and stores the data in the instance.
+ void parse() {
+ super.parse();
+ texts = parseStringList('texts', map);
+ listType =
+ parseEnum<ComboboxListType>('listType', map, ComboboxListType.values);
+ listOption = parseString('listOption', map) ?? '';
+ values = parseValueList('values', map, dataType);
+ switch (listType) {
+ case ComboboxListType.undef:
+ logger.error(
+ 'wrong value "undef" in attribute "listType" in ${fullName()}');
+ break;
+ case ComboboxListType.explicite:
+ if (texts.isEmpty) {
+ logger.error('missing attribute "texts" in ${fullName()}');
+ listType = ComboboxListType.undef;
+ } else if (values.isNotEmpty && texts.length != values.length) {
+ logger.error(
+ 'different sizes of "Texts" and "values": ${texts.length}/${values.length}');
+ listType = ComboboxListType.undef;
+ }
+ break;
+ case ComboboxListType.configuration:
+ if (regExprListConfiguration.firstMatch(listOption) == null) {
+ logger.error(
+ 'wrong syntax in "listOption". Example: "scope:userstate"');
+ listType = ComboboxListType.undef;
+ }
+ break;
+ case ComboboxListType.dbColumn:
+ if (regExprListDbOption.firstMatch(listOption) == null) {
+ logger.error(
+ 'wrong syntax in "listOption". Example: "role.list;role_name role_id;:role_name=%"');
+ listType = ComboboxListType.undef;
+ }
+ break;
+ }
+ }
+}
+
+class ComboboxData<T> {
+ final List<String> texts;
+ final List<T> values;
+ WaitState waitState;
+
+ ComboboxData(this.texts, this.values, [this.waitState = WaitState.undef]);
+}
+
+enum ComboboxListType {
+ configuration,
+ dbColumn,
+ explicite,
+ undef,
+}
import 'package:dart_bones/dart_bones.dart';
-import 'field_model.dart';
+import 'combo_base_model.dart';
import 'page_model.dart';
import 'section_model.dart';
import 'widget_model.dart';
/// Describes a combobox widget.
-class ComboboxModel extends FieldModel {
+class ComboboxModel extends ComboBaseModel {
static final regExprOptions = RegExp(r'^(readonly|disabled|required|undef)$');
- List<String> texts;
- List<dynamic> values;
-
- final Map<String, dynamic> map;
ComboboxModel(
- SectionModel section, PageModel page, this.map, BaseLogger logger)
+ SectionModel section, PageModel page, Map map, BaseLogger logger)
: super(section, page, map, WidgetModelType.combobox, logger);
/// Dumps the instance into a [StringBuffer]
void parse() {
checkSuperfluousAttributes(
map,
- 'name label dataType filterType options texts toolTip widgetType values'
+ 'name label dataType filterType listOption listType options texts toolTip values widgetType'
.split(' '));
super.parse();
- texts = parseStringList('texts', map);
- values = parseValueList('values', map, dataType);
- options = parseOptions('options', map);
checkOptionsByRegExpr(options, regExprOptions);
}
}
import 'package:dart_bones/dart_bones.dart';
import 'column_model.dart';
-import 'field_model.dart';
+import 'combo_base_model.dart';
import 'page_model.dart';
import 'section_model.dart';
import 'widget_model.dart';
/// Describes a form text field widget.
-class DbReferenceModel extends FieldModel {
+class DbReferenceModel extends ComboBaseModel {
static final regExprOptions =
RegExp(r'^(readonly|disabled|required|password|unique|combobox|undef)$');
int maxSize;
: super(section, page, map, WidgetModelType.dbReference, logger);
/// A constructor without map parsing.
- DbReferenceModel.direct(SectionModel section, PageModel page,
+ DbReferenceModel.fromColumn(SectionModel section, PageModel page,
ColumnModel column, BaseLogger logger)
: super.direct(
- section,
- page,
- null,
- WidgetModelType.dbReference,
- column.name,
- column.label,
- column.toolTip,
- column.dataType,
- column.options,
- logger) {
+ section: section,
+ page: page,
+ map: null,
+ widgetType: WidgetModelType.dbReference,
+ name: column.name,
+ label: column.label,
+ toolTip: column.toolTip,
+ dataType: column.dataType,
+ options: column.options = <String>[],
+ texts: column.texts,
+ values: column.values,
+ listOption: column.listOption,
+ listType: column.listType,
+ logger: logger) {
this.column = column;
maxSize = column.size;
rows = column.rows;
- if (column.hasOption('primary') && ! column.hasOption('readonly')){
+ if (column.hasOption('primary') && !column.hasOption('readonly')) {
options.add('readonly');
}
}
super.parse();
checkSuperfluousAttributes(
map,
- 'column label maxSize name options rows toolTip value widgetType'
+ 'column label maxSize listOption listType name options rows toolTip texts values'
.split(' '));
final columnName = parseString('column', map, required: true);
column = page.module.getColumn(columnName, this);
/// Tests whether a given [option] is part of [options].
bool hasOption(String option) {
+ if (options == null){
+ return false;
+ }
bool rc = options.contains(option);
return rc;
}
/// Parses the map and stores the data in the instance.
void parse() {
- name = parseString('name', map, required: true);
+ name = parseString(widgetModelType == WidgetModelType.column ? 'column' : 'name', map, required: true);
label = parseString('label', map, required: false);
toolTip = parseString('toolTip', map, required: false);
filterType = parseEnum<FilterType>('filterType', map, FilterType.values);
-
+ options = parseOptions('options', map);
dataType = parseEnum<DataType>('dataType', map, DataType.values);
if (dataType == null) {
switch (widgetModelType) {
if (map.containsKey(key)) {
final value = map[key];
if (value.runtimeType == String && value.isNotEmpty) {
- rc = value.split(';');
+ rc = value.replaceAll(';', ' ').replaceAll(',', ' ').split(' ');
} else {
logger.error(
'wrong datatype of options ${value.runtimeType} in ${fullName()}');
/// This entry is split by the delimiter given at index 0.
/// Example: ";a;b" returns ['a', 'b'].
/// An error is logged if [required] is true and the map does not contain the key.
- List<dynamic> parseValueList(
- String key, Map<String, dynamic> map, DataType dataType,
+ List parseValueList(String key, Map<String, dynamic> map, DataType dataType,
{bool required = false}) {
if (dataType == null) {
dataType = DataType.string;
}
- List<dynamic> rc;
- if (ModelBase.isList(map[key])) {
- rc = map[key];
- } else {
- final strings = parseStringList(key, map, required: required).toList();
- if (strings.isNotEmpty) {
- rc = strings.map((item) {
- var rc2;
- switch (dataType) {
- case DataType.int:
- rc2 = StringUtils.asInt(item);
- break;
- default:
- logger.error('unknown dataType in parseValueList()');
- rc2 = item;
- }
- return rc2;
- });
+ List rc;
+ if (map.containsKey(key)) {
+ if (ModelBase.isList(map[key])) {
+ rc = map[key];
+ } else {
+ List<String> strings =
+ parseStringList(key, map, required: required).toList();
+ if (strings.isNotEmpty) {
+ rc = strings.map((item) {
+ var rc2;
+ if (item.isNotEmpty) {
+ switch (dataType) {
+ case DataType.int:
+ case DataType.reference:
+ rc2 = StringUtils.asInt(item);
+ break;
+ default:
+ logger.error('unknown dataType in parseValueList()');
+ rc2 = item;
+ }
+ }
+ return rc2;
+ }).toList();
+ }
}
}
return rc;
equals,
pattern,
}
+enum WaitState { undef, initial, waiting, ready }
import 'package:dart_bones/dart_bones.dart';
+
import 'button_model.dart';
import 'field_model.dart';
import 'model_base.dart';
/// Parses the map and stores the data in the instance.
void parse() {
name = parseString('page', map, required: true);
- checkSuperfluousAttributes(
- map, 'options page pageType sections tableColumns tableTitles'.split(' '));
+ checkSuperfluousAttributes(map,
+ 'options page pageType sections tableColumns tableTitles'.split(' '));
pageModelType = parseEnum<PageModelType>(
'pageType', map, PageModelType.values,
required: true);
tableTitles = parseStringList('tableTitles', map);
tableColumns = parseString('tableColumns', map)?.split(' ');
if (pageModelType != PageModelType.list &&
- (tableTitles != null || tableColumns != null)) {
+ (tableTitles != null && tableTitles.length > 0 ||
+ tableColumns != null && tableColumns.length > 0)) {
logger.error(
'tableTitles and tableColumns are only meaningful in list pages: ${fullName()}');
}
import 'package:dart_bones/dart_bones.dart';
+
import '../module_model.dart';
///
'dataType': 'string',
'label': 'Bereich',
'size': 64,
- 'options': 'unique;notnull',
+ 'options': 'unique notnull',
},
{
'column': 'configuration_property',
{
"page": "list",
"pageType": "list",
- "tableColumns": "configuration_id configuration_scope configuration_property configuration_order configuration_value configuration_type",
+ "tableColumns":
+ "configuration_id configuration_scope configuration_property configuration_order configuration_value configuration_type",
"tableTitles": ";Id;Bereich;Eigenschaft;Reihe;Wert;Typ",
"sections": [
{
"sectionType": "filterPanel",
"children": [
{
- "name": "configuration_name",
+ "name": "configuration_scope",
+ "label": "Bereich",
"widgetType": "textField",
"filterType": "pattern",
+ //"options": 'undef',
},
{
- "name": "configuration_scope",
- "widgetType": "combobox",
- "filterType": "equals",
- "options": 'undef',
+ "name": "configuration_property",
+ "label": "Eigenschaft",
+ "widgetType": "textField",
+ "filterType": "pattern",
},
]
}
'dataType': 'string',
'label': 'Rolle',
'size': 32,
- 'options': 'unique;notnull',
+ 'options': 'unique notnull',
},
{
'column': 'role_priority',
{
"page": "list",
"pageType": "list",
- "tableColumns": "role_id role_name role_prio",
+ "tableColumns": "role_id role_name role_priority",
"tableTitles": ";Id;Rolle;Priorität",
"sections": [
{
import 'package:dart_bones/dart_bones.dart';
+
import '../module_model.dart';
class UserModel extends ModuleModel {
'dataType': 'string',
'label': 'User',
'size': 64,
- 'options': 'unique;notnull',
+ 'options': 'unique notnull',
},
{
'column': 'user_displayname',
{
'column': 'user_password',
'dataType': 'string',
- 'label': 'User',
+ 'label': 'Passwort',
'size': 128,
'options': 'password',
},
'dataType': 'reference',
'label': 'Role',
'foreignKey': 'role.role_id',
- 'widgetType': 'combobox',
+ 'listType': 'explicite',
+ 'texts': ';-;Administrator;Benutzer;Gast;Verwalter',
+ 'values': ';;1;2;3;4',
+ //"listType": "dbColumn",
+ //"listOption": "role.list;role_name role_id;:role_name=%",
},
]
},
{
"page": "list",
"pageType": "list",
- "tableColumns": "user_id user_name user_displayname user_email user_role",
+ "tableColumns":
+ "user_id user_name user_displayname user_email user_role",
"tableTitles": ";Id;Name;Anzeigename;EMail;Rolle",
"sections": [
{
"widgetType": "textField",
"filterType": "pattern",
"name": "user_name",
+ "label": "Name",
},
{
"widgetType": "combobox",
"filterType": "equals",
"name": "user_role",
+ "label": "Rolle",
+ "listType": "explicite",
+ "texts": ";Alle Rollen;Administrator;Benutzer;Gast;Verwalter",
+ "values": ";;1;2;3;4"
+ //"listType": "dbColumn",
+ //"listOption": "role.list;role_name role_id;:role_name=%",
}
]
}
}
}
+ /// Adds a column [name] if it does not exist with [label] and [dataType].
+ void addIfMissing(
+ String name, String label, DataType dataType, List<String> options,
+ [int size]) {
+ if (columnByName(name, required: false) == null) {
+ addColumn(ColumnModel.direct(
+ name: name,
+ table: this,
+ label: label,
+ dataType: dataType,
+ options: options ?? [],
+ size: size,
+ logger: logger));
+ }
+ }
+
/// Returns a column by [name] or null if not found.
ColumnModel columnByName(String name, {bool required = true}) {
ColumnModel rc = columns.firstWhere((element) => element.name == name,
}
}
checkOptionsByRegExpr(options, regExprOptions);
- _addIfMissing(
+ addIfMissing(
'${name}_createdat', 'Erzeugt', DataType.dateTime, ['hidden', 'null']);
- _addIfMissing(
+ addIfMissing(
'${name}_createdby', 'Erzeugt von', DataType.string, ['hidden'], 16);
- _addIfMissing(
+ addIfMissing(
'${name}_changedat', 'Geändert', DataType.dateTime, ['hidden', 'null']);
- _addIfMissing(
+ addIfMissing(
'${name}_changedby', 'Geändert von', DataType.string, ['hidden'], 16);
}
@override
widgetName() => name;
- /// Adds a column [name] if it does not exist with [label] and [dataType].
- void _addIfMissing(
- String name, String label, DataType dataType, List<String> options,
- [int size]) {
- if (columnByName(name, required: false) == null) {
- addColumn(ColumnModel.raw(
- name: name,
- table: this,
- label: label,
- dataType: dataType,
- options: options ?? [],
- size: size,
- logger: logger));
- }
- }
-
/// Returns a list of tables constructed by the Json like [list].
static void parseList(
ModuleModel module, List<dynamic> list, BaseLogger logger) {
final Persistence persistence;
String currentUser;
int currentRoleId;
+
/// for unittests:
dynamic lastModuleState;
+
+ /// <page_full_name>: <last_error_message>
+ final _lastErrorMessageMap = <String, String>{};
+
@protected
final callerStack = <PageControllerBones>[];
currentUser = 'Gast';
currentRoleId = 100;
}
+
/// Enforces a redraw of the caller of the current page.
/// [reason] specifies why the redraw is needed and [customString]
/// is an additional info for the reason.
- void callerRedraw(RedrawReason reason, [String customString]){
- if (callerStack.isNotEmpty && callerStack.last != null){
- callerStack.last.redraw(reason, customString);
+ void callerRedraw(RedrawReason reason, [String customString]) {
+ if (callerStack.isNotEmpty && callerStack.last != null) {
+ callerStack.last.redraw(reason, customString: customString);
}
}
- void pushCaller(PageControllerBones controller){
+
+ void pushCaller(PageControllerBones controller) {
callerStack.add(controller);
}
- void popCaller(){
- if (callerStack.isNotEmpty){
+
+ void popCaller() {
+ if (callerStack.isNotEmpty) {
callerStack.removeLast();
}
}
+
+ /// Sets the last severe error of the [page]. [message] may be null (no error).
+ void setLastErrorMessage(String page, String message) {
+ _lastErrorMessageMap[page] = message;
+ }
+
+ /// Returns the last severe error of the [page] or null if no error is set.
+ String lastErrorMessage(String page) {
+ final rc = _lastErrorMessageMap.containsKey(page)
+ ? _lastErrorMessageMap[page]
+ : null;
+ _lastErrorMessageMap[page] = null;
+ return rc;
+ }
}
@override
ConfigurationChangePageState createState() {
- final rc = ConfigurationChangePageState(primaryId, applicationData, initialRow);
+ final rc =
+ ConfigurationChangePageState(primaryId, applicationData, initialRow);
/// for unittests:
applicationData.lastModuleState = rc;
final int primaryId;
final Map initialRow;
final GlobalKey<FormState> _formKey =
- GlobalKey<FormState>(debugLabel: 'configuration_change');
+ GlobalKey<FormState>(debugLabel: 'configuration_change');
ConfigurationController controller;
- ConfigurationChangePageState(this.primaryId, this.applicationData, this.initialRow);
+ ConfigurationChangePageState(this.primaryId, this.applicationData,
+ this.initialRow);
@override
Widget build(BuildContext context) {
if (controller == null) {
controller = ConfigurationController(
- _formKey, this, 'change', context, applicationData,
- redrawCallback: (RedrawReason reason, String customString) =>
- setState(() => null));
+ _formKey, this, 'change', context, applicationData, redrawCallback:
+ (RedrawReason reason,
+ {String customString,
+ RedrawCallbackFunctionSimple callback}) {
+ switch (reason) {
+ case RedrawReason.callback:
+ callback(RedrawReason.custom, customString);
+ setState(() {});
+ break;
+ default:
+ setState(() {});
+ break;
+ }
+ });
controller.initialize();
}
// controller.buildWidgetList() is called in editForm
return Scaffold(
- appBar: applicationData.appBarBuilder('Rolle ändern'),
+ appBar: applicationData.appBarBuilder('Konfiguration ändern'),
drawer: applicationData.drawerBuilder(context),
body: EditForm.editForm(
key: _formKey,
initialRow: initialRow,
));
}
+
void dispose() {
controller.dispose();
super.dispose();
import 'package:flutter_bones/flutter_bones.dart';
import '../../model/standard/configuration_model.dart';
-import 'configuration_change_page.dart';
import '../../widget/page_controller_bones.dart';
+import 'configuration_change_page.dart';
class ConfigurationController extends PageControllerBones {
/// Controller for a page named [pageName].
- ConfigurationController(GlobalKey<FormState> formKey, State<StatefulWidget> parent,
- String pageName, BuildContext context, ApplicationData applicationData,
+ ConfigurationController(
+ GlobalKey<FormState> formKey,
+ State<StatefulWidget> parent,
+ String pageName,
+ BuildContext context,
+ ApplicationData applicationData,
{Function redrawCallback})
- : super(formKey, parent, ConfigurationModel(Settings().logger), pageName, context,
- applicationData, redrawCallback) {
+ : super(formKey, parent, ConfigurationModel(Settings().logger), pageName,
+ context, applicationData, redrawCallback) {
moduleModel.parse();
}
+
@override
void startChange(int id, Map row) {
applicationData.pushCaller(this);
- Navigator.push(context,
- MaterialPageRoute(builder: (context) => ConfigurationChangePage(id, applicationData, row)));
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) =>
+ ConfigurationChangePage(id, applicationData, row)));
}
}
@override
Widget build(BuildContext context) {
if (controller == null) {
- controller =
- ConfigurationController(_formKey, this, 'create', context, applicationData);
+ controller = ConfigurationController(
+ _formKey, this, 'create', context, applicationData);
controller.initialize();
}
controller.buildWidgetList();
return Scaffold(
- appBar: applicationData.appBarBuilder('Neue Rolle'),
+ appBar: applicationData.appBarBuilder('Neue Konfiguration'),
drawer: applicationData.drawerBuilder(context),
body: EditForm.editForm(
key: _formKey,
ConfigurationListPageState createState() {
// ConfigurationListPageState.setPageData(pageData);
final rc = ConfigurationListPageState(applicationData);
+
/// for unittests:
applicationData.lastModuleState = rc;
return rc;
Widget build(BuildContext context) {
if (controller == null) {
controller = ConfigurationController(
- _formKey, this, 'list', context, applicationData,
- redrawCallback: (RedrawReason reason, String customString) => setState(() => null));
+ _formKey, this, 'list', context, applicationData, redrawCallback:
+ (RedrawReason reason,
+ {String customString,
+ RedrawCallbackFunctionSimple callback}) {
+ switch (reason) {
+ case RedrawReason.fetchList:
+ controller.buildRows();
+ break;
+ case RedrawReason.callback:
+ callback(RedrawReason.custom, customString);
+ setState(() {});
+ break;
+ default:
+ setState(() {});
+ break;
+ }
+ });
controller.initialize();
controller.buildWidgetList();
+ controller.buildRows();
+ } else {
+ controller = controller;
}
filters ??= controller.filterSet(pageName: 'list');
- controller.buildRows();
return Scaffold(
- appBar: applicationData.appBarBuilder('Rollen'),
+ appBar: applicationData.appBarBuilder('Konfigurationen'),
drawer: applicationData.drawerBuilder(context),
body: ListForm.listForm(
key: _formKey,
ButtonBar(alignment: MainAxisAlignment.center, children: [
controller.searchButton(),
RaisedButton(
- child: Text('Neue Rolle'),
+ child: Text('Neue Konfiguration'),
onPressed: () {
Navigator.pushNamed(context, '/configuration/create');
]),
],
filters: filters,
+ errorMessage:
+ applicationData.lastErrorMessage(controller.page.fullName()),
),
);
}
--- /dev/null
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+class DemoPage extends StatefulWidget {
+ final ApplicationData pageData;
+
+ DemoPage(this.pageData, {Key key}) : super(key: key);
+
+ @override
+ DemoPageState createState() {
+ // DemoPageState.setPageData(pageData);
+ final rc = DemoPageState(pageData);
+
+ return rc;
+ }
+}
+
+class DemoPageState extends State<DemoPage> {
+ DemoPageState(this.pageData);
+
+ final ApplicationData pageData;
+
+ final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+ static User currentUser = User();
+
+ @override
+ Widget build(BuildContext context) {
+ final item = DemoItem();
+ final texts = <String>['one', 'two', 'three'];
+ final items = texts
+ .map((text) => DropdownMenuItem<String>(value: text, child: Text(text)))
+ .toList();
+ return Scaffold(
+ appBar: pageData.appBarBuilder('Demo'),
+ drawer: pageData.drawerBuilder(context),
+ body: SimpleForm.simpleForm(
+ key: _formKey,
+ configuration: pageData.configuration,
+ fields: <Widget>[
+ TextFormField(
+ validator: checkNotEmpty,
+ decoration: InputDecoration(labelText: 'Name'),
+ onSaved: (input) => item.name = input,
+ ),
+ DropdownButtonFormField<String>(
+ value: 'two',
+ items: items,
+ decoration: InputDecoration(labelText: 'Number'),
+ onChanged: (value) => item.number = value,
+ ),
+ ],
+ buttons: <Widget>[
+ RaisedButton(
+ onPressed: () => login(context),
+ child: Text('Anmelden'),
+ ),
+ ],
+ ));
+ }
+
+ void login(context) async {
+ if (_formKey.currentState.validate()) {
+ _formKey.currentState.save();
+ //@ToDo: store in database
+ }
+ }
+}
+
+class DemoItem {
+ String name;
+ String number;
+}
@override
Widget build(BuildContext context) {
if (controller == null) {
- controller = RoleController(
- _formKey, this, 'change', context, applicationData,
- redrawCallback: (RedrawReason reason, String customString) =>
- setState(() => null));
+ controller =
+ RoleController(_formKey, this, 'change', context, applicationData,
+ redrawCallback: (RedrawReason reason,
+ {String customString,
+ RedrawCallbackFunctionSimple callback}) {
+ switch (reason) {
+ case RedrawReason.callback:
+ callback(RedrawReason.custom, customString);
+ setState(() {});
+ break;
+ default:
+ setState(() {});
+ break;
+ }
+ });
controller.initialize();
}
// controller.buildWidgetList() is called in editForm
initialRow: initialRow,
));
}
+
void dispose() {
controller.dispose();
super.dispose();
import 'package:flutter_bones/flutter_bones.dart';
import '../../model/standard/role_model.dart';
-import 'role_change_page.dart';
import '../../widget/page_controller_bones.dart';
+import 'role_change_page.dart';
class RoleController extends PageControllerBones {
/// Controller for a page named [pageName].
@override
void startChange(int id, Map row) {
applicationData.pushCaller(this);
- Navigator.push(context,
- MaterialPageRoute(builder: (context) => RoleChangePage(id, applicationData, row)));
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => RoleChangePage(id, applicationData, row)));
}
}
if (controller == null) {
controller =
RoleController(_formKey, this, 'list', context, applicationData,
- redrawCallback: (RedrawReason reason, String customString) {
- if (reason == RedrawReason.fetchList) {
- applicationData.persistence
- .list(
- module: controller.moduleModel.name,
- params: controller.buildSqlParams())
- .then((rows) {
- setState(() => null);
- });
+ redrawCallback: (RedrawReason reason,
+ {String customString,
+ RedrawCallbackFunctionSimple callback}) {
+ switch (reason) {
+ case RedrawReason.fetchList:
+ controller.buildRows();
+ break;
+ case RedrawReason.callback:
+ callback(RedrawReason.custom, customString);
+ setState(() {});
+ break;
+ default:
+ setState(() {});
+ break;
}
});
controller.initialize();
controller.buildWidgetList();
+ controller.buildRows();
+ } else {
+ controller = controller;
}
filters ??= controller.filterSet(pageName: 'list');
- controller.buildRows();
return Scaffold(
appBar: applicationData.appBarBuilder('Rollen'),
drawer: applicationData.drawerBuilder(context),
]),
],
filters: filters,
+ errorMessage:
+ applicationData.lastErrorMessage(controller.page.fullName()),
),
);
}
@override
Widget build(BuildContext context) {
if (controller == null) {
- controller = UserController(
- _formKey, this, 'change', context, applicationData,
- redrawCallback: (RedrawReason reason, String customString) =>
- setState(() => null));
+ controller =
+ UserController(_formKey, this, 'change', context, applicationData,
+ redrawCallback: (RedrawReason reason,
+ {String customString,
+ RedrawCallbackFunctionSimple callback}) {
+ switch (reason) {
+ case RedrawReason.callback:
+ callback(RedrawReason.custom, customString);
+ setState(() {});
+ break;
+ default:
+ setState(() {});
+ break;
+ }
+ });
controller.initialize();
}
// controller.buildWidgetList() is called in editForm
return Scaffold(
- appBar: applicationData.appBarBuilder('Rolle ändern'),
+ appBar: applicationData.appBarBuilder('Benutzer ändern'),
drawer: applicationData.drawerBuilder(context),
body: EditForm.editForm(
key: _formKey,
initialRow: initialRow,
));
}
+
void dispose() {
controller.dispose();
super.dispose();
import 'package:flutter_bones/flutter_bones.dart';
import '../../model/standard/user_model.dart';
-import 'user_change_page.dart';
import '../../widget/page_controller_bones.dart';
+import 'user_change_page.dart';
class UserController extends PageControllerBones {
/// Controller for a page named [pageName].
@override
void startChange(int id, Map row) {
applicationData.pushCaller(this);
- Navigator.push(context,
- MaterialPageRoute(builder: (context) => UserChangePage(id, applicationData, row)));
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => UserChangePage(id, applicationData, row)));
}
}
UserListPageState createState() {
// UserListPageState.setPageData(pageData);
final rc = UserListPageState(applicationData);
+
/// for unittests:
applicationData.lastModuleState = rc;
return rc;
@override
Widget build(BuildContext context) {
if (controller == null) {
- controller = UserController(
- _formKey, this, 'list', context, applicationData,
- redrawCallback: (RedrawReason reason, String customString) => setState(() => null));
+ controller =
+ UserController(_formKey, this, 'list', context, applicationData,
+ redrawCallback: (RedrawReason reason,
+ {String customString,
+ RedrawCallbackFunctionSimple callback}) {
+ switch (reason) {
+ case RedrawReason.fetchList:
+ controller.buildRows();
+ break;
+ case RedrawReason.callback:
+ callback(RedrawReason.custom, customString);
+ setState(() {});
+ break;
+ default:
+ setState(() {});
+ break;
+ }
+ });
controller.initialize();
controller.buildWidgetList();
+ controller.buildRows();
+ } else {
+ controller = controller;
}
filters ??= controller.filterSet(pageName: 'list');
- controller.buildRows();
return Scaffold(
- appBar: applicationData.appBarBuilder('Rollen'),
+ appBar: applicationData.appBarBuilder('Benutzer'),
drawer: applicationData.drawerBuilder(context),
body: ListForm.listForm(
key: _formKey,
ButtonBar(alignment: MainAxisAlignment.center, children: [
controller.searchButton(),
RaisedButton(
- child: Text('Neue Rolle'),
+ child: Text('Neuer Benutzer'),
onPressed: () {
Navigator.pushNamed(context, '/user/create');
]),
],
filters: filters,
+ errorMessage:
+ applicationData.lastErrorMessage(controller.page.fullName()),
),
);
}
import 'package:flutter/material.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-import 'package:flutter_bones/src/private/bsettings.dart';
import '../page/configuration/configuration_list_page.dart';
+import '../page/demo_page.dart';
+import '../page/login_page.dart';
import '../page/role/role_list_page.dart';
import '../page/user/user_list_page.dart';
+import 'bsettings.dart';
class MenuItem {
final String title;
final dynamic page;
final IconData icon;
+
MenuItem(this.title, this.page, this.icon);
static List<MenuItem> menuItems() {
Icons.account_box_outlined),
MenuItem('Konfiguration', () => ConfigurationListPage(settings.pageData),
Icons.account_box_outlined),
+ MenuItem('Demo', () => DemoPage(settings.pageData),
+ Icons.account_box_outlined),
];
}
}
import 'package:flutter/material.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-typedef RedrawCallbackFunction = Function(
+import '../model/combobox_model.dart';
+import '../model/combo_base_model.dart';
+import '../model/field_model.dart';
+import '../page/application_data.dart';
+
+typedef RedrawCallbackFunctionSimple = Function(
RedrawReason reason, String customString);
+typedef RedrawCallbackFunction = Function(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback});
/// Interface for a callback controller for flutter_bones specific widgets.
/// flutter_bones specific widgets: [CheckboxListTileBone],
/// [DropDownButtonFormBone], [RaisedButtonBone], [TextFormFieldBone]
abstract class CallbackControllerBones {
- /// Prepares the rows shown in the list page
+ /// Retrieves the rows shown in the list page.
void buildRows();
- /// Returns the texts of the [ComboboxModel] named [name].
- List<String> comboboxTexts(String name);
-
- /// Returns the values of the [ComboboxModel] named [name].
- List<dynamic> comboboxValues(String name);
+ /// Returns the [ComboboxData] (texts and values) of the [ComboboxModel] named [name].
+ ComboboxData comboboxData<T>(String name);
/// Frees all resources.
void dispose();
/// Returns the [model] named [name].
FieldModel getModel(String name);
+
ValueChanged<String> getOnChanged(
String customString, CallbackControllerBones controller);
-
ValueChanged<bool> getOnChangedCheckbox(
String customString, CallbackControllerBones controller);
/// Rebuilds the view of the page.
/// [reason] and [customString] will be forwarded to the callback function.
- void redraw(RedrawReason reason, String customString);
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback});
/// Returns a standard search button for the list page.
Widget searchButton();
enum RedrawReason {
custom,
+ callback,
fetchList,
fetchRecord,
+ redraw,
+ setError,
}
import '../helper/string_helper.dart';
import 'filter_set.dart';
import 'page_controller_bones.dart';
+import 'view.dart';
typedef Function OnEditTap(Map<String, dynamic> row, int index);
TableCallbackController tableCallbackController,
String customString,
}) {
- if (titles.length != columnNames.length){
- controller.moduleModel.logger.error('titles.length != columnNames.length: ${titles.length}/${columnNames.length}');
+ if (titles.length != columnNames.length) {
+ controller.moduleModel.logger.error(
+ 'titles.length != columnNames.length: ${titles.length}/${columnNames.length}');
}
final titles2 = titles.map((item) => DataColumn(label: item)).toList();
if (showEditIcon) {
}
for (var key in columnNames) {
cells.add(DataCell(
- Text(StringHelper.asString(row[key])),
+ Text(StringHelper.asString(row[key], nullString: '')),
));
}
return DataRow(cells: cells);
/// [rows] is a list of rows normally delivered from a database query:
/// each row is a map with (key, value) pairs.
/// If [showEditItems] is true the edit icon is shown in the first column.
+ /// If [errorMessage] is not null this message will be shown.
static Form listForm(
{@required Key key,
@required FilterSet filters,
@required List<String> columnNames,
@required Iterable<dynamic> rows,
bool showEditIcon = false,
+ String errorMessage,
PageControllerBones pageController,
@required BaseConfiguration configuration,
String customString}) {
final padding =
configuration.asFloat('form.card.padding', defaultValue: 16.0);
+ final widgets = <Widget>[
+ ...filters.getWidgets(),
+ SizedBox(
+ height: configuration.asFloat('form.gap.field_button.height',
+ defaultValue: 16.0)),
+ ...buttons
+ ];
+ if (errorMessage != null) {
+ widgets.add(View().errorMessage(errorMessage));
+ }
+ widgets.add(table(
+ titles: titles,
+ columnNames: columnNames,
+ rows: rows,
+ showEditIcon: showEditIcon,
+ controller: pageController,
+ customString: customString,
+ ));
return Form(
key: key,
child: Card(
margin: EdgeInsets.symmetric(vertical: padding, horizontal: padding),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
- child: ListView(children: <Widget>[
- ...filters.getWidgets(),
- SizedBox(
- height: configuration.asFloat(
- 'form.gap.field_button.height',
- defaultValue: 16.0)),
- ...buttons,
- table(
- titles: titles,
- columnNames: columnNames,
- rows: rows,
- showEditIcon: showEditIcon,
- controller: pageController,
- customString: customString,
- )
- ])),
+ child: ListView(children: widgets)),
));
}
}
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-import 'package:flutter_bones/src/widget/widget_list.dart';
+import '../helper/string_helper.dart';
+import '../model/model_types.dart';
import '../model/column_model.dart';
+import '../model/combo_base_model.dart';
+import '../model/page_model.dart';
import '../model/module_model.dart';
+import '../model/field_model.dart';
import '../page/application_data.dart';
import 'callback_controller_bones.dart';
import 'filter_set.dart';
import 'view.dart';
+import 'widget_list.dart';
// This interface allows the generic handling of the edit form by a model driven module.
class PageControllerBones implements CallbackControllerBones {
final BuildContext context;
Iterable listRows;
final textControllers = <String, TextEditingController>{};
+ final comboboxDataMap = <String, ComboboxData>{};
PageControllerBones(this.globalKey, this.parent, this.moduleModel,
this.pageName, this.context, this.applicationData,
[this.redrawCallback]);
@override
- void buildRows() {
+ buildRows() {
final persistence = applicationData.persistence;
final params = buildSqlParams() ?? {};
- persistence.list(module: 'role', params: params).then((list) {
- if (listRows == null) {
- listRows = list;
- redraw(RedrawReason.fetchList, null);
- }
+ persistence.list(module: moduleModel.name, params: params).then((list) {
+ listRows = list;
+ redraw(RedrawReason.redraw);
}, onError: (error) {
- applicationData.logger.error('cannot retrieve role list: $error');
+ applicationData.logger
+ .error('cannot retrieve ${moduleModel.name} list: $error');
+ redraw(RedrawReason.setError,
+ customString: 'Keine Verbindung zum Server');
});
}
}
@override
- List<String> comboboxTexts(String name) {
- return [];
+ ComboboxData comboboxData<T>(String name) {
+ ComboboxData rc = comboboxDataMap.containsKey(name)
+ ? comboboxDataMap[name]
+ : ComboboxData<T>([], []);
+ comboboxDataMap[name] = rc;
+ if (rc.waitState == WaitState.undef) {
+ ComboBaseModel model = page.fieldByName(name) as ComboBaseModel;
+ if (model != null) {
+ switch (model.listType) {
+ case ComboboxListType.explicite:
+ rc = ComboboxData<T>(model.texts, model.values, WaitState.ready);
+ comboboxDataMap[name] = rc;
+ break;
+ case ComboboxListType.undef:
+ rc = ComboboxData<T>([], [], WaitState.ready);
+ comboboxDataMap[name] = rc;
+ break;
+ case ComboboxListType.dbColumn:
+ comboboxDataDb(model, rc);
+ break;
+ case ComboboxListType.configuration:
+ break;
+ }
+ }
+ }
+ return rc;
}
- @override
- List comboboxValues(String name) {
- return [];
+ void comboboxDataDb(ComboBaseModel model, ComboboxData data) {
+ // example: role.list;role_displayname role_id;:role_name=% :excluded=0'
+ final parts = model.listOption.split(';');
+ final moduleName = parts[0].split('.');
+ final cols = parts[1].split(' ');
+ final params = <String, dynamic>{};
+ if (parts.length > 2 && parts[2].isNotEmpty) {
+ parts[2].split(' ').forEach((element) {
+ final keyValue = element.split('=');
+ params[keyValue[0]] = keyValue[1];
+ });
+ }
+ applicationData.persistence
+ .list(module: moduleName[0], sqlName: moduleName[1], params: params)
+ .then((rows) {
+ rows.forEach((row) {
+ data.texts.add(row[cols[0]]);
+ data.values.add(row[cols[1]]);
+ });
+ if (model.hasOption('undef')) {
+ data.texts.insert(0, '-');
+ data.values.insert(0, null);
+ }
+ data.waitState = WaitState.ready;
+ redraw(RedrawReason.redraw);
+ });
}
@override
@override
getOnChangedCombobox<T>(
String customString, CallbackControllerBones controller) {
- return null;
+ var rc;
+ rc = (value) {
+ final model = page.fieldByName(customString);
+ model.value = value;
+ };
+ return rc;
}
@override
switch (pageType) {
case PageModelType.create:
applicationData.persistence
- .insert(module: moduleModel.name, data: params);
+ .insert(module: moduleModel.name, data: params)
+ .then((id) {
+ applicationData.callerRedraw(RedrawReason.fetchList);
applicationData.popCaller();
- Navigator.pop(controller.getContext());
+ Navigator.pop(controller.getContext());
+ });
break;
case PageModelType.change:
applicationData.persistence
}
@override
- void redraw(RedrawReason reason, [String customString]) {
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
if (redrawCallback == null) {
moduleModel.logger.error(
'not overridden: fetchListRows() in ${moduleModel.widgetName()}.$pageName');
} else {
- redrawCallback(reason, customString);
+ if (reason == RedrawReason.setError) {
+ applicationData.setLastErrorMessage(page.fullName(), customString);
+ }
+ redrawCallback(reason, customString: customString, callback: callback);
}
}
import 'package:dart_bones/dart_bones.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
-import 'package:flutter_bones/src/widget/checkbox_list_tile_bone.dart';
import '../helper/settings.dart';
+import '../helper/string_helper.dart';
import '../model/db_reference_model.dart';
+import '../model/model_types.dart';
import '../model/empty_line_model.dart';
import '../model/field_model.dart';
import '../model/section_model.dart';
import '../model/text_model.dart';
import '../model/widget_model.dart';
+import '../model/button_model.dart';
+import '../model/combo_base_model.dart';
+import 'callback_controller_bones.dart';
+import 'checkbox_list_tile_bone.dart';
import 'dropdown_button_form_bone.dart';
import 'raised_button_bone.dart';
+import 'text_form_field_bone.dart';
class View {
static View _instance;
final BaseLogger logger;
- factory View(BaseLogger logger) {
+ factory View([BaseLogger logger]) {
if (_instance == null) {
_instance = View.internal(logger);
_instance.settings = Settings(logger: logger);
/// Creates a combobox via the [controller].
Widget combobox<T>(
FieldModel model, CallbackControllerBones controller, initialValue) {
- final texts = controller.comboboxTexts(model.name);
- final values = controller.comboboxValues(model.name) ?? texts;
+ ComboboxData<T> comboboxData = controller.comboboxData(model.name);
final items = <DropdownMenuItem<T>>[];
- for (var ix = 0; ix < texts.length; ix++) {
+ for (var ix = 0; ix < comboboxData.texts.length; ix++) {
items.add(DropdownMenuItem(
onTap: controller.getOnTap(model.name, controller),
- value: values[ix],
- child: Text(texts[ix])));
+ value: comboboxData.values[ix],
+ child: Text(comboboxData.texts[ix])));
}
- final rc = DropdownButtonFormBone(model.name, controller,
- items: items, value: initialValue);
+ final rc = DropdownButtonFormBone(
+ model.name,
+ controller,
+ items: items,
+ value: initialValue,
+ decoration: InputDecoration(labelText: model.label),
+ );
return rc;
}
Widget dbReference(DbReferenceModel model, CallbackControllerBones controller,
- initialValue) {
+ dynamic initialValue) {
var rc;
if (model.dataType == DataType.bool) {
- rc = checkbox(model, controller, initialValue);
- } else if (model.hasOption('combobox')) {
+ rc = checkbox(model, controller, StringHelper.fromString(initialValue, DataType.bool));
+ } else if (model.listType != null) {
rc = combobox(model, controller, initialValue);
} else {
rc = textField(model, controller, initialValue);
return rc;
}
+ /// Returns a [Text] widget with an error [message].
+ Text errorMessage(String message) {
+ final rc = Text(
+ message,
+ style: TextStyle(color: Colors.red, backgroundColor: Colors.yellow),
+ textAlign: TextAlign.center,
+ );
+ return rc;
+ }
+
/// Creates image from the [model].
Widget image(WidgetModel model) {
var rc;
rc = checkbox(model, controller, initialValue);
break;
case WidgetModelType.combobox:
- rc = text(model);
+ rc = combobox(model, controller, initialValue);
break;
case WidgetModelType.image:
rc = image(model);
controller: textController,
readOnly: model.hasOption('readonly'),
decoration: InputDecoration(labelText: model.label),
+ obscureText: model.hasOption('password'),
),
model);
return rc;
});
group('conversion', () {
test('asString', () {
+ expect(StringHelper.asString(null), isNull);
+ expect(StringHelper.asString(null, nullString: '?'), equals('?'));
expect(StringHelper.asString('abc'), equals('abc'));
expect(StringHelper.asString(345), equals('345'));
expect(StringHelper.asString(34.5), equals('34.5'));
'name': 'user',
'label': 'User',
'column': 'user_id',
- 'options': 'required;unique',
+ 'options': 'required unique',
},
{
'widgetType': 'dbReference',
'dataType': 'string',
'label': 'User',
'size': 64,
- 'options': 'unique;notnull',
+ 'options': 'unique notnull',
},
{
'column': 'user_role',
'widgetType': 'textField',
'name': 'user',
'label': 'User',
- 'options': 'required;unique',
+ 'options': 'required unique',
},
{
'widgetType': 'button',