+++ /dev/null
-import 'package:flutter_bones/flutter_bones.dart';
-
-/// Base class of all controller classes in this package.
-abstract class BaseController {
- /// Returns the assigned model.
- WidgetModel getModel();
-
- /// Returns a unique name of the controller inside the module, mostly the
- /// widget name of the assigned model.
- String getName();
-}
+++ /dev/null
-import 'package:flutter/material.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-import 'package:flutter_bones/src/controller/base_controller.dart';
-
-import '../widget/raised_button_bone.dart';
-
-class ButtonController extends BaseController
- implements ButtonCallbackController {
- ButtonModel model;
-
- ButtonController(this.model);
-
- @override
- WidgetModel getModel() {
- return model;
- }
-
- @override
- String getName() {
- return model.widgetName();
- }
-
- @override
- getOnHighlightChanged(String customString, ButtonCallbackController controller) {
- return null;
- }
-
- @override
- getOnLongPressed(String customString, ButtonCallbackController controller) {
- return null;
- }
-
- @override
- getOnPressed(String customString, ButtonCallbackController controller) {
- var rc;
- switch (model.buttonModelType) {
- case ButtonModelType.cancel:
- break;
- case ButtonModelType.custom:
- break;
- case ButtonModelType.search:
- break;
- case ButtonModelType.store:
- break;
- }
- return rc;
- }
-
- @override
- BuildContext getContext() {
- return null;
- }
-}
+++ /dev/null
-import 'package:flutter_bones/flutter_bones.dart';
-
-import '../widget/dropdown_button_form_bone.dart';
-import 'base_controller.dart';
-
-class ComboboxController<T> extends BaseController
- implements ComboboxCallbackController {
- ComboboxModel model;
-
- ComboboxController(this.model);
-
- @override
- WidgetModel getModel() {
- return model;
- }
-
- @override
- String getName() {
- return model.widgetName();
- }
-
- @override
- getOnChanged(String customString, ComboboxCallbackController controller) {
- return null;
- }
-
- @override
- getOnSaved(String customString, ComboboxCallbackController controller) {
- return null;
- }
-
- @override
- getOnSelectedItemBuilder(
- String customString, ComboboxCallbackController controller) {
- return null;
- }
-
- @override
- getOnTap(String customString, ComboboxCallbackController controller) {
- return null;
- }
-
- @override
- getOnValidator(String customString, ComboboxCallbackController controller) {
- return null;
- }
-
- @override
- List<String> texts() {
- return model.texts;
- }
-
- @override
- List<dynamic> values() {
- return model.values;
- }
-}
+++ /dev/null
-import 'package:flutter_bones/flutter_bones.dart';
-
-import '../widget/text_form_field_bone.dart';
-import 'base_controller.dart';
-
-class TextFormController extends BaseController
- implements TextFormCallbackController {
- ComboboxModel model;
-
- TextFormController(this.model);
-
- @override
- WidgetModel getModel() {
- return model;
- }
-
- @override
- String getName() {
- return model.widgetName();
- }
-
- @override
- getOnChanged(String customString, TextFormCallbackController controller) {
- return null;
- }
-
- @override
- getOnEditingComplete(
- String customString, TextFormCallbackController controller) {
- return null;
- }
-
- @override
- getOnFieldSubmitted(
- String customString, TextFormCallbackController controller) {
- return null;
- }
-
- @override
- getOnSaved(String customString, TextFormCallbackController controller) {
- return null;
- }
-
- @override
- getOnTap(String customString, TextFormCallbackController controller) {
- return null;
- }
-
- @override
- getValidator(String customString, TextFormCallbackController controller) {
- return null;
- }
-}
import 'column_model.dart';
import 'combo_base_model.dart';
+import 'model_base.dart';
import 'page_model.dart';
import 'section_model.dart';
-import 'model_base.dart';
/// Describes a form text field widget.
class DbReferenceModel extends ComboBaseModel {
listOption ??= column?.listOption;
listType ??= column?.listType;
checkOptionsByRegExpr(regExprOptions);
- options += column?.options ?? [];
+ mergeOptions(column?.options);
parseFinish();
}
+
+ /// Merges entries of [options2] into [options].
+ void mergeOptions(List<String> options2) {
+ if (options2 != null) {
+ for (var option in options2) {
+ if (hasOption(option)) {
+ continue;
+ }
+ if (filterType != null) {
+ if (['required', 'notnull', 'unique', 'primary'].contains(option)) {
+ // list filters do not have this options by default.
+ continue;
+ }
+ }
+ options.add(option);
+ }
+ }
+ }
}
bool checkOptionsByRegExpr(RegExp regExpr) {
bool rc = false;
options?.forEach((element) {
- if (regExpr.firstMatch(element) == null) {
+ final toTest =
+ element.startsWith('not.') ? element.substring(4) : element;
+ if (regExpr.firstMatch(toTest) == null) {
logger.error('wrong option $element in ${fullName()}');
rc = true;
}
import 'package:flutter/material.dart';
+
import '../../model/page_model.dart';
import '../../widget/list_form.dart';
import '../../widget/page_controller_bones.dart';
),
]),
],
- filters: controller.widgetList,
+ filters: controller.modelList,
errorMessage:
applicationData.lastErrorMessage(controller.page.fullName()),
),
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/material.dart';
+
+import '../application_data.dart';
+import '../configuration/configuration_list_page.dart';
+import '../demo_page.dart';
+import '../menu/menu_list_page.dart';
+import '../role/role_list_page.dart';
+import '../user/user_list_page.dart';
+import '../user/user_login_page.dart';
+import '../user/user_password_page.dart';
+
+/// Converts menu specific strings to objects:
+/// [pageByName]() converts a name to a page (of type StatefulWidget)
+/// [iconByName]() converts a name to an icon.
+/// Override them for more pages / icons.
+class MenuConverter {
+ /// Returns the page given by [name].
+ StatefulWidget pageByName(String name, ApplicationData applicationData) {
+ var rc;
+ switch (name) {
+ case 'user.login':
+ rc = UserLoginPage(applicationData);
+ break;
+ case 'user.list':
+ rc = UserListPage(applicationData);
+ break;
+ case 'role.list':
+ rc = RoleListPage(applicationData);
+ break;
+ case 'configuration.list':
+ rc = ConfigurationListPage(applicationData);
+ break;
+ case 'menu.list':
+ rc = MenuListPage(applicationData);
+ break;
+ case 'user.password':
+ rc = UserPasswordPage(applicationData.currentUserId,
+ applicationData.currentUserName, applicationData, null);
+ break;
+ case 'demo':
+ rc = DemoPage(applicationData);
+ break;
+ default:
+ applicationData.logger
+ .error('MenuConverter.pageByName(): unknown page $name');
+ break;
+ }
+ return rc;
+ }
+
+ /// Returns the icon given by [name].
+ IconData iconByName(String name, BaseLogger logger) {
+ IconData rc;
+ switch (name) {
+ case 'account_box_outlined':
+ rc = Icons.account_box_outlined;
+ break;
+ case 'account_circle_outlined':
+ rc = Icons.account_circle_outlined;
+ break;
+ case 'build_outlined':
+ rc = Icons.build_outlined;
+ break;
+ case 'article_outlined':
+ rc = Icons.article_outlined;
+ break;
+ case 'login_outlined':
+ rc = Icons.login_outlined;
+ break;
+ case 'menu_open_outlined':
+ rc = Icons.menu_open_outlined;
+ break;
+ case 'square_foot_outlined':
+ rc = Icons.square_foot_outlined;
+ break;
+ case 'table_chart_outlined':
+ rc = Icons.table_chart_outlined;
+ break;
+ case 'text_snippet_outlined':
+ rc = Icons.text_snippet_outlined;
+ break;
+ case 'folder_outlined':
+ rc = Icons.folder_outlined;
+ break;
+ case 'watch_later_outlined':
+ rc = Icons.watch_later_outlined;
+ break;
+ case 'account_tree':
+ rc = Icons.account_tree_outlined;
+ break;
+ case 'construction_outlined':
+ rc = Icons.construction_outlined;
+ break;
+ default:
+ logger.error('MenuConverter.iconByName(): unknown icon $name');
+ break;
+ }
+ return rc;
+ }
+}
import 'package:flutter/material.dart';
+
import '../../model/page_model.dart';
import '../../widget/list_form.dart';
import '../../widget/page_controller_bones.dart';
),
]),
],
- filters: controller.widgetList,
+ filters: controller.modelList,
errorMessage:
applicationData.lastErrorMessage(controller.page.fullName()),
),
import 'package:flutter/material.dart';
+
import '../../model/page_model.dart';
import '../../widget/list_form.dart';
import '../../widget/page_controller_bones.dart';
),
]),
],
- filters: controller.widgetList,
+ filters: controller.modelList,
errorMessage:
applicationData.lastErrorMessage(controller.page.fullName()),
),
),
]),
],
- filters: controller.widgetList,
+ filters: controller.modelList,
errorMessage:
applicationData.lastErrorMessage(controller.page.fullName()),
),
final sourceColumnsParams = key.split(';');
final idModuleName = sourceColumnsParams[0].split('.');
final nameValue = sourceColumnsParams[1].split(' ');
- final params = sourceColumnsParams[2].split(' ');
final params2 = <String, dynamic>{};
- params.forEach((element) {
- final keyValue = element.split('=');
- params2[keyValue[0]] = keyValue[1];
- });
+ if (sourceColumnsParams.length > 2 && sourceColumnsParams[2].isNotEmpty) {
+ final params = sourceColumnsParams[2].split(' ');
+ params.forEach((element) {
+ final keyValue = element.split('=');
+ params2[keyValue[0]] = keyValue[1];
+ });
+ }
final texts = hasUndef ? ['-'] : <String>[];
final values = hasUndef ? <dynamic>[null] : <dynamic>[];
if (listType == ComboboxListType.configuration) {
/// A persistence layer using a REST interface to store/fetch the data.
class RestPersistence extends Persistence {
static RestPersistence _instance;
+ static final jsonHeader = <String, String>{
+ 'Content-Type': 'application/json; charset=utf-8',
+ };
final String application;
final String version;
final BaseLogger logger;
int sessionTimeout;
String uriPrefix;
- Map<String, String> headers;
-
factory RestPersistence(
{String application,
String version,
var rc;
assert(['list', 'record', 'update'].contains(sqlType));
final params2 = params == null ? '{}' : convert.jsonEncode(params);
- final answer = await runRequest(module, sqlName, sqlType, body: params2);
+ final answer = await runRequest(module, sqlName, sqlType,
+ body: params2, headers: jsonHeader);
if (answer.isNotEmpty) {
rc = convert.jsonDecode(answer);
}
Future delete(
{@required String module, String sqlName, @required int id}) async {
sqlName ??= 'delete';
- await runRequest(module, sqlName, 'delete', body: '{":${module}_id":$id}');
+ await runRequest(module, sqlName, 'delete', body: '{":${module}_id":$id}',
+ headers: jsonHeader);
}
@override
sqlName ??= 'insert';
var rc = 0;
final data2 = data == null ? '{}' : convert.jsonEncode(data);
- final answer = await runRequest(module, sqlName, 'insert', body: data2);
+ final answer = await runRequest(
+ module, sqlName, 'insert', body: data2, headers: jsonHeader);
if (answer.isNotEmpty) {
final map = convert.jsonDecode(answer);
rc = map['id'];
sqlName ??= 'list';
Iterable<dynamic> rc;
final body = params == null ? '{}' : convert.jsonEncode(params);
- final answer = await runRequest(module, sqlName, 'list', body: body);
+ final answer = await runRequest(
+ module, sqlName, 'list', body: body, headers: jsonHeader);
if (answer.isNotEmpty) {
rc = convert.jsonDecode(answer);
}
sqlName ??= 'record';
Map rc;
final answer = await runRequest(module, sqlName, 'record',
- body: '{":${module}_id":$id}');
+ body: '{":${module}_id":$id}', headers: jsonHeader);
if (answer.isNotEmpty) {
rc = convert.jsonDecode(answer);
}
sqlName ??= 'record';
Map rc;
final answer = await runRequest(module, sqlName, 'record',
- body: convert.jsonEncode(parameters));
+ body: convert.jsonEncode(parameters), headers: jsonHeader);
if (answer.isNotEmpty) {
rc = convert.jsonDecode(answer);
}
import 'package:flutter/material.dart';
-import '../page/application_data.dart';
-import '../page/configuration/configuration_list_page.dart';
-import '../page/demo_page.dart';
-import '../page/menu/menu_list_page.dart';
-import '../page/role/role_list_page.dart';
-import '../page/user/user_list_page.dart';
-import '../page/user/user_login_page.dart';
+import '../page/menu/menu_converter.dart';
import 'bsettings.dart';
class MenuItem {
MenuItem(this.title, this.page, this.icon);
- static StatefulWidget pageByName(
- String name, ApplicationData applicationData) {
- var rc;
- switch (name) {
- case 'user.login':
- rc = UserLoginPage(applicationData);
- break;
- case 'user.list':
- rc = UserListPage(applicationData);
- break;
- case 'role.list':
- rc = RoleListPage(applicationData);
- break;
- case 'configuration.list':
- rc = ConfigurationListPage(applicationData);
- break;
- case 'menu.list':
- rc = MenuListPage(applicationData);
- break;
- case 'demo':
- rc = DemoPage(applicationData);
- break;
- }
- return rc;
- }
-
- static List<MenuItem> menuItems() {
+ static List<MenuItem> menuItems(MenuConverter converter) {
final settings = BSettings.lastInstance;
+ final logger = settings.logger;
return <MenuItem>[
- MenuItem('Login', () => pageByName('user.login', settings.pageData),
- Icons.account_box_outlined),
- MenuItem('Rollen', () => pageByName('role.list', settings.pageData),
- Icons.account_box_outlined),
- MenuItem('Benutzer', () => pageByName('user.list', settings.pageData),
- Icons.account_box_outlined),
+ MenuItem(
+ 'Login',
+ () => converter.pageByName('user.login', settings.pageData),
+ converter.iconByName('login_outlined', logger)),
+ MenuItem(
+ 'Rollen',
+ () => converter.pageByName('role.list', settings.pageData),
+ converter.iconByName('account_circle_outlined', logger)),
+ MenuItem(
+ 'Benutzer',
+ () => converter.pageByName('user.list', settings.pageData),
+ converter.iconByName('account_box_outlined', logger)),
MenuItem(
'Konfiguration',
- () => pageByName('configuration.list', settings.pageData),
- Icons.account_box_outlined),
- MenuItem('Startmenü', () => pageByName('menu.list', settings.pageData),
- Icons.account_box_outlined),
- MenuItem('Demo', () => pageByName('demo', settings.pageData),
- Icons.account_box_outlined),
+ () => converter.pageByName('configuration.list', settings.pageData),
+ converter.iconByName('build_outlined', logger)),
+ MenuItem(
+ 'Startmenü',
+ () => converter.pageByName('menu.list', settings.pageData),
+ converter.iconByName('menu_open_outlined', logger)),
+ MenuItem('Demo', () => converter.pageByName('demo', settings.pageData),
+ converter.iconByName('article_outlined', logger)),
];
}
}
static BonesDrawer builder(dynamic context) => BonesDrawer(context);
static Widget buildGrid(context) {
- final list = MenuItem.menuItems();
+ final converter = MenuConverter();
+ final list = MenuItem.menuItems(converter);
final rc = Card(
child: GridView.count(
- crossAxisCount: 2,
- crossAxisSpacing: 16.0,
- children: list
- .map((item) => GridTile(
+ crossAxisCount: 2,
+ crossAxisSpacing: 16.0,
+ children: list
+ .map((item) =>
+ GridTile(
child: new InkResponse(
enableFeedback: true,
child: Card(
}
static Widget buildListView(context) {
- final list = MenuItem.menuItems();
+ final converter = MenuConverter();
+ final list = MenuItem.menuItems(converter);
final rc = Card(
child: ListView(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
children: list
- .map((item) => ListTile(
- title: Text(item.title),
- onTap: () {
- // What happens after you tap the navigation item
- Navigator.push(
+ .map((item) =>
+ ListTile(
+ title: Text(item.title),
+ onTap: () {
+ // What happens after you tap the navigation item
+ Navigator.push(
context,
MaterialPageRoute(
builder: (context) => item.page()));
models.add(model);
}
}
- models.add(model);
}
/// Builds the SQL parameters of all members of the [widgets].
import '../model/page_model.dart';
import '../model/widget_model.dart';
import '../page/application_data.dart';
-import 'view.dart';
import 'model_list.dart';
+import 'view.dart';
import 'widget_validators.dart';
typedef RedrawCallbackFunction = Function(RedrawReason reason,
class PageControllerBones implements ValidatorController {
final ModuleModel moduleModel;
String primaryColumn;
- ModelList widgetList;
+ ModelList modelList;
final RedrawCallbackFunction redrawCallback;
final GlobalKey<FormState> globalKey;
final String pageName;
/// [initialRow] is null or a map with the field values,
/// e.g. { 'role_name': 'admin', ...}
void buildModelList([Map initialRow]) {
- widgetList.clear();
+ modelList.clear();
page.widgets.forEach((model) {
if (initialRow != null && model is FieldModel) {
model.valueFromRow(initialRow);
model.value = value;
}
completeModels(model);
- widgetList.addModel(name, model);
+ modelList.addModel(name, model);
});
page.fields.forEach((element) => prepareModel(element));
}
rc = () {
if (globalKey.currentState.validate()) {
globalKey.currentState.save();
- final params = widgetList.buildSqlParams(this);
+ final params = modelList.buildSqlParams(this);
PageModelType pageType =
- moduleModel.pageByName(pageName).pageModelType;
+ moduleModel
+ .pageByName(pageName)
+ .pageModelType;
switch (pageType) {
case PageModelType.create:
applicationData.persistence
///
List<Widget> getWidgets() {
List<Widget> rc;
- rc = View(moduleModel.logger).modelsToWidgets(widgetList.models, this);
+ rc = View(moduleModel.logger).modelsToWidgets(modelList.models, this);
return rc ?? [];
}
/// This method must be called early after the constructor.
void initialize() {
page = moduleModel.pageByName(pageName);
- widgetList = ModelList('${page.fullName()}.widgets', moduleModel.logger);
+ modelList = ModelList('${page.fullName()}.widgets', moduleModel.logger);
buildModelList();
if (page?.pageModelType == PageModelType.list) {
buildRows();
/// Copies the values of [initialRow] into the values of the fields.
void initializeFields(Map initialRow) {
- widgetList.models.forEach((model) {
+ modelList.models.forEach((model) {
if (model is FieldModel && initialRow.containsKey(model.name)) {
- page.fieldByName(model.name)?.value = initialRow[model.name];
+ page
+ .fieldByName(model.name)
+ ?.value = initialRow[model.name];
}
});
}
if (lastInstance.controller is String) {
lastInstance.initState();
lastInstance.build(context);
- final models = lastInstance.controller.widgetList.models;
+ final models = lastInstance.controller.modelList.models;
expect(models.length, equals(3));
}
});