--- /dev/null
+#! /bin/bash
+dartdoc --sdk-dir=/opt/dart-sdk
+import 'package:dart_bones/dart_bones.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/page/role_list_page.dart';
import 'package:flutter_bones/src/private/bsettings.dart';
class BoneApp extends StatefulWidget {
@override
- BoneAppState createState() => BoneAppState();
+ BoneAppState createState() {
+ final mapWidgetData = <String, dynamic>{
+ 'form.card.padding': '16.0',
+ 'form.gap.field_button.height': '16.0',
+ };
+ final logger = MemoryLogger();
+ Settings(
+ logger: logger,
+ widgetConfiguration: BaseConfiguration(mapWidgetData, logger));
+ return BoneAppState();
+ }
}
class BoneAppState extends State<BoneApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: 'Virtuelle Fragestunde',
+ title: 'Test Standardseiten',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
- initialRoute: '/login',
+ initialRoute: '/role/list',
onGenerateRoute: _getRoute,
);
}
Route<dynamic> _getRoute(RouteSettings settings) {
MaterialPageRoute route;
- if (settings.name == '/login') {
+ if (settings.name == '/role/list') {
route = MaterialPageRoute<void>(
settings: settings,
- builder: (BuildContext context) => LoginPage(BSettings.instance.pageData),
+ builder: (BuildContext context) =>
+ RoleListPage(BSettings.instance.pageData),
fullscreenDialog: false,
);
} else {
route = MaterialPageRoute<void>(
- settings: settings,
- builder: (BuildContext context) => LoginPage(BSettings.instance.pageData),
- fullscreenDialog: false,
+ settings: settings,
+ builder: (BuildContext context) => LoginPage(BSettings.instance.pageData),
+ fullscreenDialog: false,
);
}
return route;
export 'src/model/module_model.dart';
export 'src/model/page_model.dart';
export 'src/model/section_model.dart';
+export 'src/model/standard/role_model.dart';
+export 'src/model/standard/user_model.dart';
export 'src/model/text_field_model.dart';
export 'src/model/text_model.dart';
export 'src/model/widget_model.dart';
export 'src/page/login_page.dart';
export 'src/page/page_data.dart';
-export 'src/page/role_page.dart';
+export 'src/page/role_create_page.dart';
export 'src/page/user_page.dart';
export 'src/widget/raised_button_bone.dart';
export 'src/widget/simple_form.dart';
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/material.dart';
+
+typedef FilterPredicate = bool Function(Map<String, dynamic> row);
+
+class FilterItem {
+ final String name;
+ final String label;
+ final FilterType filterType;
+ final String toolTip;
+ final FilterPredicate filterPredicate;
+ var value;
+
+ FilterItem(
+ {this.label,
+ this.filterType,
+ this.toolTip,
+ this.name,
+ this.filterPredicate});
+
+ bool isValid(Map<String, dynamic> row) {
+ bool rc = true;
+ if (filterPredicate != null) {
+ rc = filterPredicate(row);
+ } else {
+ final current = row[name].toString();
+ final value2 = value ?? '';
+ switch (filterType) {
+ case FilterType.pattern:
+ rc = value2 == ''
+ ? true
+ : (value2.startsWidth('*')
+ ? current.contains(value2.substring(1))
+ : current.startsWith(value2));
+ break;
+ case FilterType.dateFrom:
+ // TODO: Handle this case.
+ break;
+ case FilterType.dateTil:
+ // TODO: Handle this case.
+ break;
+ case FilterType.dateTimeFrom:
+ // TODO: Handle this case.
+ break;
+ case FilterType.dateTimeTil:
+ // TODO: Handle this case.
+ break;
+ default:
+ rc = true;
+ break;
+ }
+ }
+ return rc;
+ }
+}
+
+class Filters {
+ var filters = <FilterItem>[];
+ final BaseLogger logger;
+
+ Filters(this.logger);
+
+ Filters.ready(this.filters, this.logger);
+
+ void add(FilterItem item) => filters.add(item);
+
+ FilterItem byName(String name) =>
+ filters.firstWhere((element) => element.name == name);
+
+ /// Returns a list of widgets for the filter fields.
+ List<Widget> getWidgets() {
+ final rc = filters.map((filter) {
+ Widget rc = TextFormField(
+ decoration: InputDecoration(labelText: filter.label),
+ );
+ if (filter.toolTip != null) {
+ rc = Tooltip(message: filter.toolTip, child: rc);
+ }
+ return rc;
+ }).toList();
+ return rc;
+ }
+
+ /// Tests whether the [row] belongs to the result.
+ bool isValid(Map<String, dynamic> row) {
+ var rc = true;
+ for (var filter in filters) {
+ if (!filter.isValid(row)) {
+ rc = false;
+ break;
+ }
+ }
+ return rc;
+ }
+}
+
+enum FilterType {
+ pattern,
+ dateFrom,
+ dateTil,
+ dateTimeFrom,
+ dateTimeTil,
+}
final BaseLogger logger;
- factory Settings(BaseLogger logger, {BaseConfiguration widgetConfiguration}) {
+ factory Settings({BaseLogger logger, BaseConfiguration widgetConfiguration}) {
if (_instance == null) {
_instance = Settings.internal(
widgetConfiguration == null
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+
+import 'page_model.dart';
+import 'section_model.dart';
+import 'widget_model.dart';
+
+/// Describes a text widget without user interaction.
+class AllDbFieldsModel extends WidgetModel {
+ static final regExprOptions = RegExp(r'^(unknown)$');
+ List<String> options;
+ String text;
+ bool isRichText;
+ final Map<String, dynamic> map;
+
+ AllDbFieldsModel(
+ SectionModel section, PageModel page, this.map, BaseLogger logger)
+ : super(section, page, WidgetModelType.text, logger);
+
+ /// Returns the name including the names of the parent
+ @override
+ String fullName() => '${section.name}.allDbFields$id';
+
+ /// Dumps the internal structure into a [stringBuffer]
+ StringBuffer dump(StringBuffer stringBuffer) {
+ stringBuffer
+ .write(' allDbFields $id text: options: ${options.join(' ')}\n');
+ return stringBuffer;
+ }
+
+ /// Parses the map and stores the data in the instance.
+ void parse() {
+ checkSuperfluousAttributes(map, 'options widgetType'.split(' '));
+ options = parseOptions('options', map);
+ checkOptionsByRegExpr(options, regExprOptions);
+ }
+
+ @override
+ String widgetName() => 'allDbFields$id';
+}
/// Describes a column of a database table.
class ColumnModel extends WidgetModel {
- static final regExprOptions =
- RegExp(r'^(undef|readonly|disabled|primary|required|unique)$');
+ static final regExprOptions = RegExp(
+ r'^(undef|readonly|disabled|hidden|null|notnull|primary|required|unique)$');
String name;
String label;
String toolTip;
+++ /dev/null
-import 'package:dart_bones/dart_bones.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-
-class UserModel extends ModuleModel {
- static final model = <String, dynamic>{
- "module": "user",
- "pages": [
- {
- "name": "create",
- "pageType": "create",
- "sections": [
- {
- "sectionType": "simpleForm",
- "children": [
- {
- "widgetType": "text",
- "text": "*_Erfassung eines neuen Benutzers:_*",
- "options": "rich",
- },
- {
- "widgetType": "emptyLine",
- },
- {
- "widgetType": "textField",
- "name": "user",
- "label": "Benutzer",
- "options": "required;unique",
- },
- {
- "widgetType": "textField",
- "name": "displayname",
- "label": "Anzeigename",
- "fieldType": "text",
- "options": "required",
- },
- {
- "widgetType": "combobox",
- "name": "role",
- "label": "Rolle",
- "dataType": "reference",
- "options": "required;undef",
- },
- ]
- }
- ]
- },
- ],
- };
-
- UserModel(BaseLogger logger) : super(model, logger);
-
- /// Returns the name including the names of the parent
- @override
- String fullName() => name;
-
- @override
- String widgetName() => name;
-}
return stringBuffer;
}
+ /// Exports the SQL statement to create the module tables.
+ String exportSql() {
+ StringBuffer buffer = StringBuffer();
+ for (var table in tables) {
+ buffer.write('drop table if exists ${table.name};\n');
+ buffer.write('create table ${table.name} (\n');
+ for (var column in table.columns) {
+ String type;
+ switch (column.dataType) {
+ case DataType.bool:
+ type = 'char(1)';
+ break;
+ case DataType.currency:
+ type = 'int(10)';
+ break;
+ case DataType.date:
+ type = 'date';
+ break;
+ case DataType.dateTime:
+ type = 'timestamp';
+ break;
+ case DataType.float:
+ type = 'double';
+ break;
+ case DataType.int:
+ type = 'int(10)';
+ break;
+ case DataType.reference:
+ type = 'int(10)';
+ break;
+ case DataType.string:
+ if (column.size == null) {
+ type = 'varchar(255)';
+ } else if (column.size <= 255) {
+ type = 'varchar($column.size})';
+ } else if (column.size <= 0xffff) {
+ type = 'text';
+ } else {
+ type = 'mediumtext';
+ }
+ break;
+ }
+ String options = '';
+ for (var option in column.options) {
+ if ('notnull null primary unique'.contains(option)) {
+ options += ' ' + option;
+ }
+ }
+ buffer.write(' ${column.name} $type$options;\n');
+ }
+ buffer.write(');\n');
+ }
+ final rc = buffer.toString();
+ return rc;
+ }
+
/// Returns the name including the names of the parent
@override
String fullName() => name;
import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter_bones/src/model/all_db_fields_model.dart';
import 'package:flutter_bones/src/model/db_reference_model.dart';
import 'button_model.dart';
child['widgetType'].toString(), WidgetModelType.values);
WidgetModel widget;
switch (widgetType) {
+ case WidgetModelType.allDbFields:
+ widget = AllDbFieldsModel(this, page, child, logger);
+ break;
case WidgetModelType.checkbox:
widget = CheckboxModel(this, page, child, logger);
break;
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+class RoleModel extends ModuleModel {
+ static final model = <String, dynamic>{
+ "module": "role",
+ "tables": [
+ {
+ 'name': 'role',
+ 'columns': [
+ {
+ 'name': 'role_id',
+ 'dataType': 'int',
+ 'label': 'Id',
+ 'options': 'primary',
+ },
+ {
+ 'name': 'role_name',
+ 'dataType': 'string',
+ 'label': 'Rolle',
+ 'size': 32,
+ 'options': 'unique;notnull',
+ },
+ {
+ 'name': 'role_priority',
+ 'dataType': 'int',
+ 'label': 'Priorität',
+ },
+ {
+ 'name': 'role_created',
+ 'dataType': 'dateTime',
+ 'label': 'Erzeugt',
+ 'options': 'hidden;null',
+ },
+ {
+ 'name': 'role_changed',
+ 'dataType': 'dateTime',
+ 'label': 'Geändert',
+ 'options': 'hidden;null',
+ },
+ ]
+ },
+ ],
+ 'pages': [
+ {
+ "name": "create",
+ "pageType": "create",
+ "sections": [
+ {
+ "sectionType": "simpleForm",
+ "children": [
+ {
+ "widgetType": "allDbFields",
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "change",
+ "pageType": "change",
+ "sections": [
+ {
+ "sectionType": "simpleForm",
+ "children": [
+ {
+ "widgetType": "allDbFields",
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "list",
+ "pageType": "list",
+ "sections": [
+ {
+ "sectionType": "filterPanel",
+ "children": [
+ {
+ "widgetType": "textfield",
+ "searchMode": "pattern",
+ }
+ ]
+ }
+ ]
+ },
+ ],
+ };
+
+ RoleModel(BaseLogger logger) : super(model, logger);
+
+ /// Returns the name including the names of the parent
+ @override
+ String fullName() => name;
+
+ @override
+ String widgetName() => name;
+}
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+class UserModel extends ModuleModel {
+ static final model = <String, dynamic>{
+ "module": "user",
+ "tables": [
+ {
+ 'name': 'users',
+ 'columns': [
+ {
+ 'name': 'user_id',
+ 'dataType': 'int',
+ 'label': 'Id',
+ 'options': 'primary',
+ },
+ {
+ 'name': 'user_name',
+ 'dataType': 'string',
+ 'label': 'User',
+ 'size': 64,
+ 'options': 'unique',
+ },
+ {
+ 'name': 'user_displayname',
+ 'dataType': 'string',
+ 'label': 'Anzeigename',
+ 'size': 32,
+ 'options': 'unique',
+ },
+ {
+ 'name': 'user_email',
+ 'dataType': 'string',
+ 'label': 'EMail',
+ 'size': 128,
+ 'options': 'unique',
+ },
+ {
+ 'name': 'user_password',
+ 'dataType': 'string',
+ 'label': 'User',
+ 'size': 128,
+ 'options': 'password',
+ },
+ {
+ 'name': 'user_role',
+ 'dataType': 'reference',
+ 'label': 'Role',
+ 'foreignKey': 'role.role_id',
+ 'widgetType': 'combobox',
+ },
+ ]
+ },
+ ],
+ 'pages': [
+ {
+ "name": "create",
+ "pageType": "create",
+ "sections": [
+ {
+ "sectionType": "simpleForm",
+ "children": [
+ {
+ "widgetType": "text",
+ "text": "*_Erfassung eines neuen Benutzers:_*",
+ "options": "rich",
+ },
+ {
+ "widgetType": "emptyLine",
+ },
+ {
+ "widgetType": "textField",
+ "name": "user",
+ "label": "Benutzer",
+ "options": "required;unique",
+ },
+ {
+ "widgetType": "textField",
+ "name": "displayname",
+ "label": "Anzeigename",
+ "fieldType": "text",
+ "options": "required",
+ },
+ {
+ "widgetType": "combobox",
+ "name": "role",
+ "label": "Rolle",
+ "dataType": "reference",
+ "options": "required;undef",
+ },
+ ]
+ }
+ ]
+ },
+ ],
+ };
+
+ UserModel(BaseLogger logger) : super(model, logger);
+
+ /// Returns the name including the names of the parent
+ @override
+ String fullName() => name;
+
+ @override
+ String widgetName() => name;
+}
}
enum WidgetModelType {
+ allDbFields,
button,
checkbox,
column,
--- /dev/null
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+class RoleCreatePage extends StatefulWidget {
+ final PageData pageData;
+
+ RoleCreatePage(this.pageData, {Key key}) : super(key: key);
+
+ @override
+ RoleCreatePageState createState() {
+ // RoleCreatePageState.setPageData(pageData);
+ final rc = RoleCreatePageState(pageData);
+
+ return rc;
+ }
+}
+
+class RoleCreatePageState extends State<RoleCreatePage> {
+ RoleCreatePageState(this.pageData);
+
+ final PageData pageData;
+
+ final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+ static Role currentRole = Role();
+
+ @override
+ Widget build(BuildContext context) {
+ final role = Role();
+ return Scaffold(
+ appBar: pageData.appBarBuilder('Rollen'),
+ drawer: pageData.drawerBuilder(context),
+ body: SimpleForm.simpleForm(
+ key: _formKey,
+ configuration: pageData.configuration,
+ fields: <Widget>[
+ TextFormField(
+ validator: checkNotEmpty,
+ decoration: InputDecoration(labelText: 'Name'),
+ onSaved: (input) => role.name = input,
+ ),
+ TextFormField(
+ validator: checkNat,
+ decoration: InputDecoration(labelText: 'Priorität'),
+ onSaved: (input) => role.priority = input,
+ ),
+ ],
+ 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 Role {
+ String priority;
+ String name;
+}
\ No newline at end of file
--- /dev/null
+import 'package:flutter/material.dart';
+
+import '../helper/filters.dart';
+import '../helper/settings.dart';
+import '../page/page_data.dart';
+import '../widget/list_form.dart';
+
+class RoleListPage extends StatefulWidget {
+ final PageData pageData;
+
+ RoleListPage(this.pageData, {Key key}) : super(key: key);
+
+ @override
+ RoleListPageState createState() {
+ // RoleListPageState.setPageData(pageData);
+ final rc = RoleListPageState(pageData);
+
+ return rc;
+ }
+}
+
+class RoleListPageState extends State<RoleListPage> {
+ RoleListPageState(this.pageData);
+
+ final PageData pageData;
+
+ final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+ static Role currentRole = Role();
+
+ List<Map<String, dynamic>> getRows(Filters filters) {
+ final rows = <Map<String, dynamic>>[
+ {
+ 'role_id': '1',
+ 'role_name': 'Administrator',
+ 'role_priority': '10',
+ },
+ {
+ 'role_id': '2',
+ 'role_name': 'Verwalter',
+ 'role_priority': '20',
+ },
+ {
+ 'role_id': '3',
+ 'role_name': 'Benutzer',
+ 'role_priority': '30',
+ },
+ {
+ 'role_id': '4',
+ 'role_name': 'Gast',
+ 'role_priority': '40',
+ },
+ ];
+ final rc = rows.where((row) => filters.isValid(row)).toList();
+ return rc;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final logger = Settings().logger;
+ final filters = Filters.ready([
+ FilterItem(filterType: FilterType.pattern, label: 'Name'),
+ ], logger);
+ return Scaffold(
+ appBar: pageData.appBarBuilder('Rollen'),
+ drawer: pageData.drawerBuilder(context),
+ body: ListForm.listForm(
+ key: _formKey,
+ configuration: pageData.configuration,
+ titles: ListForm.stringsToTitles(';Id;Name;Priorität'),
+ columnNames: 'role_id role_name role_priority'.split(' '),
+ rows: getRows(filters),
+ showEditIcon: true,
+ buttons: <Widget>[
+ RaisedButton(
+ onPressed: () => search(context),
+ child: Text('Suchen'),
+ ),
+ ],
+ filters: filters,
+ ),
+ );
+ }
+
+ void search(context) async {
+ if (_formKey.currentState.validate()) {
+ _formKey.currentState.save();
+ }
+ }
+}
+
+class Role {
+ int id;
+ String priority;
+ String name;
+}
+++ /dev/null
-import 'package:flutter/material.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-
-class RolePage extends StatefulWidget {
- final PageData pageData;
- RolePage(this.pageData, { Key key }) : super(key: key);
- @override
- RolePageState createState() {
- // RolePageState.setPageData(pageData);
- final rc = RolePageState(pageData);
-
- return rc;
- }
-}
-
-class RolePageState extends State<RolePage>{
- RolePageState(this.pageData);
- final PageData pageData;
-
- final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
- static Role currentRole = Role();
-
- @override
- Widget build(BuildContext context) {
- final role = Role();
- return Scaffold(
- appBar: pageData.appBarBuilder('Rollen'),
- drawer: pageData.drawerBuilder(context),
- body: SimpleForm.simpleForm(
- key: _formKey,
- configuration: pageData.configuration,
- fields: <Widget>[
- TextFormField(
- validator: checkNotEmpty,
- decoration: InputDecoration(labelText: 'Name'),
- onSaved: (input) => role.name = input,
- ),
- TextFormField(
- validator: checkNat,
- decoration: InputDecoration(labelText: 'Priorität'),
- onSaved: (input) => role.priority = input,
- ),
- ],
- 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 Role {
- String priority;
- String name;
-}
\ No newline at end of file
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+import 'package:test/test.dart';
+
+import '../model/standard/role_model.dart';
+import '../model/standard/user_model.dart';
+
+void dummy() {
+ group('xxx', () {
+ test('y', () {
+ Widget text = Text('');
+ expect(text, isNotNull);
+ });
+ });
+}
+
+void main(List<String> argv) async {
+ final logger = MemoryLogger(LEVEL_FINE);
+ if (argv.length > 0xffff) {
+ dummy();
+ }
+ final dbHelper = DbHelper(logger);
+ if (argv.length == 0) {
+ logger.error("missing arguments");
+ } else {
+ final mode = argv[0];
+ argv.removeAt(0);
+ switch (mode) {
+ case 'create-sql':
+ dbHelper.exportSql(argv);
+ break;
+ default:
+ logger.error('unknown mode: ${argv[0]}');
+ break;
+ }
+ }
+ //await tool.main();
+}
+
+class DbHelper {
+ final BaseLogger logger;
+
+ DbHelper(this.logger);
+
+ void exportSql(List<String> argv) {
+ if (argv.length == 0) {
+ logger.error('missing table');
+ } else {
+ final table = argv[0];
+ argv.removeAt(0);
+ ModuleModel module;
+ switch (table) {
+ case 'user':
+ module = UserModel(logger);
+ break;
+ case 'role':
+ module = RoleModel(logger);
+ break;
+ default:
+ logger.error('unknown table');
+ break;
+ }
+ final filename = argv.length == 0 ? '$table.sql' : argv[0];
+ FileSync.toFile(filename, module.exportSql());
+ print('exported: $filename');
+ }
+ }
+
+ void usage(String error) {
+ print('''usage: dbhelper <mode> [<args>]
+<mode>:
+ create-sql <module> [<output-file>]
+ <module>: 'role', 'user' ...
+Examples:
+dbhelper create-sql role role.sql
+''');
+ }
+}
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/material.dart';
+
+import '../helper/filters.dart';
+
+typedef Function OnEditTap(Map<String, dynamic> row, int index);
+
+class ListForm {
+ /// Converts a string with [titles] into a list of widgets of type Text().
+ /// Format of [titles]: first character is the delimiter, e.g. ";Id;Name;"
+ /// This allows to use different delimiters when the title text
+ /// contains characters normally used as delimiters.
+ static List<Widget> stringsToTitles(String titles) {
+ final rc = titles
+ .substring(1)
+ .split(titles[0])
+ .map((String title) =>
+ Text(title, style: TextStyle(fontWeight: FontWeight.bold)))
+ .toList();
+ return rc;
+ }
+
+ /// Returns a widget with a data table.
+ /// [titles] is used for the table header.
+ /// [columnNames] are the keys to display: @precondition: titles.length == columnNames.length
+ /// [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.
+ static Widget table({
+ @required List<Widget> titles,
+ @required List<String> columnNames,
+ @required List<Map<String, dynamic>> rows,
+ bool showEditIcon = false,
+ OnEditTap onEditTap,
+ }) {
+ Widget rc = Container(
+ margin: EdgeInsets.all(2),
+ child: DataTable(
+ showCheckboxColumn: true,
+ showBottomBorder: true,
+ sortColumnIndex: 1,
+ columns: titles.map((item) => DataColumn(label: item)).toList(),
+ rows: rows.map((row) {
+ final cells = <DataCell>[];
+ int ix = -1;
+ for (var key in columnNames) {
+ ix++;
+ cells.add(DataCell(
+ Text(row[key]),
+ showEditIcon: showEditIcon && ix == 0,
+ onTap: () => onEditTap == null ? null : onEditTap(row, ix),
+ ));
+ }
+ return DataRow(cells: cells);
+ }).toList()));
+ return rc;
+ }
+
+ /// Returns a widget with a form containing some [filters] and a data table.
+ /// [titles] is used for the table header.
+ /// [columnNames] are the keys to display: @precondition: titles.length == columnNames.length
+ /// [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.
+ static Form listForm(
+ {@required Key key,
+ @required Filters filters,
+ @required List<Widget> buttons,
+ @required List<Widget> titles,
+ @required List<String> columnNames,
+ @required List<Map<String, dynamic>> rows,
+ bool showEditIcon = false,
+ OnEditTap onEditTap,
+ @required BaseConfiguration configuration}) {
+ final padding =
+ configuration.asFloat('form.card.padding', defaultValue: 16.0);
+ 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,
+ onEditTap: onEditTap),
+ ])),
+ ));
+ }
+}
factory View(BaseLogger logger) {
if (_instance == null) {
_instance = View.internal(logger);
- _instance.settings = Settings(logger);
+ _instance.settings = Settings(logger: logger);
_instance.widgetConfiguration = _instance.settings.widgetConfiguration;
}
return _instance;
break;
case WidgetModelType.table:
case WidgetModelType.column:
+ case WidgetModelType.allDbFields:
logger.error('not allowed in section: ${child.fullName()}');
break;
}
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+import 'package:test/test.dart';
+
+void main() {
+ final logger = MemoryLogger(LEVEL_FINE);
+ group('sql', () {
+ test('export-sql', () {
+ logger.clear();
+ final module = RoleModel(logger);
+ module.parse();
+ final content = module.exportSql();
+ final errors = logger.errors;
+ expect(errors.length, equals(0));
+ expect(content, equals('''drop table if exists role;
+create table role (
+ role_id int(10) primary;
+ role_name varchar(255) unique notnull;
+ role_priority int(10);
+ role_created timestamp null;
+ role_changed timestamp null;
+);
+'''));
+ });
+ });
+}