android/
ios/
web/
+linux/
# IntelliJ related
*.iml
# Obfuscation related
app.*.map.json
+/linux/
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';
+
+import 'src/helper/settings.dart';
+import 'src/page/login_page.dart';
+import 'src/page/role/role_change_page.dart';
+import 'src/page/role/role_create_page.dart';
+import 'src/page/role/role_list_page.dart';
+import 'src/private/bsettings.dart';
class BoneApp extends StatefulWidget {
@override
}
class BoneAppState extends State<BoneApp> {
-
@override
Widget build(BuildContext context) {
return MaterialApp(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
- initialRoute: '/role/list',
+ initialRoute: '/role/change',
onGenerateRoute: _getRoute,
);
}
-
}
Route<dynamic> _getRoute(RouteSettings settings) {
MaterialPageRoute route;
- if (settings.name == '/role/list') {
- route = MaterialPageRoute<void>(
- settings: settings,
- builder: (BuildContext context) =>
- RoleListPage(BSettings.instance.pageData),
- fullscreenDialog: false,
- );
- } else {
+ StatefulWidget page;
+ switch (settings.name) {
+ case '/role/list':
+ page = RoleListPage(BSettings.instance.pageData);
+ break;
+ case '/role/change':
+ page = RoleChangePage(BSettings.instance.pageData);
+ break;
+ case '/role/create':
+ page = RoleCreatePage(BSettings.instance.pageData);
+ break;
+ default:
+ page = LoginPage(BSettings.instance.pageData);
+ break;
+ }
+ if (page != null) {
route = MaterialPageRoute<void>(
settings: settings,
- builder: (BuildContext context) => LoginPage(BSettings.instance.pageData),
+ builder: (BuildContext context) => page,
fullscreenDialog: false,
);
}
export 'src/model/widget_model.dart';
export 'src/page/login_page.dart';
export 'src/page/page_data.dart';
-export 'src/page/role_create_page.dart';
+export 'src/page/role/role_create_page.dart';
export 'src/page/user_page.dart';
export 'src/widget/raised_button_bone.dart';
export 'src/widget/simple_form.dart';
+export 'src/widget/text_form_field_bone.dart';
export 'src/widget/view.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,
-}
typedef ButtonOnPressed = void Function(String name);
/// Describes a button widget.
-class ButtonModel extends WidgetModel {
+class ButtonModel extends WidgetModel implements ButtonCallbackController {
static final regExprOptions = RegExp(r'^(undef)$');
String text;
String name;
@override
String widgetName() => name;
+
+ @override
+ getOnHighlightChanged(
+ String customString, ButtonCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnLongPressed(String customString, ButtonCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnPressed(String customString, ButtonCallbackController controller) {
+ return onPressed;
+ }
}
enum ButtonModelType {
@override
String fullName() => '${table.name}.$name';
+ /// Tests whether a given [option] is part of [options].
+ bool hasOption(String option) {
+ 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);
@override
String fullName() => '${page.name}.$name';
+ /// Tests whether a given [option] is part of [options].
+ bool hasOption(String option) {
+ 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);
// on change: adapt StringHelper.fromString()
enum DataType {
- bool, currency, date, dateTime, float, int, reference, string,
+ bool,
+ currency,
+ date,
+ dateTime,
+ float,
+ int,
+ reference,
+ string,
+}
+enum FilterType {
+ dateFrom,
+ dateTil,
+ dateTimeFrom,
+ dateTimeTil,
+ pattern,
}
return rc;
}
+ /// Returns the main table of the module.
+ /// This is the first defined table.
+ TableModel mainTable() {
+ TableModel rc = tables.length == 0 ? null : tables[0];
+ return rc;
+ }
+
/// Returns a child page given by [name], null otherwise.
PageModel pageByName(String name) {
final found = pages.firstWhere((element) => element.name == name);
change,
create,
delete,
+ list,
overview,
}
checkSuperfluousAttributes(
map, 'children fields name options sectionType widgetType'.split(' '));
options = parseOptions('options', map);
+
checkOptionsByRegExpr(options, regExprOptions);
if (!map.containsKey('children')) {
logger.error('missing children in ${fullName()}');
}
enum SectionModelType {
+ changeForm,
+ createForm,
simpleForm,
- query,
+ filterPanel,
}
import 'package:flutter_bones/flutter_bones.dart';
class RoleModel extends ModuleModel {
- static final model = <String, dynamic>{
+ static final yamlMap = <String, dynamic>{
"module": "role",
"tables": [
{
"sectionType": "filterPanel",
"children": [
{
- "widgetType": "textfield",
- "searchMode": "pattern",
+ "widgetType": "textField",
+ "filterType": "pattern",
+ "name": "role_name",
}
]
}
],
};
- RoleModel(BaseLogger logger) : super(model, logger);
+ RoleModel(BaseLogger logger) : super(yamlMap, logger);
/// Returns the name including the names of the parent
@override
FormFieldSetter onSaved;
final Map<String, dynamic> map;
+ FilterType filterType;
TextFieldModel(
SectionModel section, PageModel page, this.map, BaseLogger logger)
super.parse();
checkSuperfluousAttributes(
map,
- 'dataType label maxSize name options rows toolTip value widgetType'
+ 'dataType filterType label maxSize name options rows toolTip value widgetType'
.split(' '));
maxSize = parseInt('maxSize', map, required: false);
rows = parseInt('rows', map, required: false);
+ filterType = parseEnum<FilterType>('filterType', map, FilterType.values);
switch (dataType) {
case DataType.int:
case DataType.reference:
--- /dev/null
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../widget/edit_form.dart';
+import 'role_controller.dart';
+
+class RoleChangePage extends StatefulWidget {
+ final PageData pageData;
+ final logger = Settings().logger;
+ RoleChangePageState lastState;
+
+ RoleChangePage(this.pageData, {Key key}) : super(key: key);
+
+ @override
+ RoleChangePageState createState() {
+ final rc = lastState = RoleChangePageState(pageData);
+ return rc;
+ }
+}
+
+class RoleChangePageState extends State<RoleChangePage> {
+ final PageData pageData;
+
+ final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+
+ RoleController controller;
+
+ RoleChangePageState(this.pageData);
+
+ @override
+ Widget build(BuildContext context) {
+ controller = controller ?? RoleController(_formKey, this);
+ return Scaffold(
+ appBar: pageData.appBarBuilder('Rolle ändern'),
+ drawer: pageData.drawerBuilder(context),
+ body: EditForm.editForm(
+ key: _formKey,
+ isCreateForm: false,
+ moduleController: controller,
+ configuration: pageData.configuration,
+ ));
+ }
+}
--- /dev/null
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../model/standard/role_model.dart';
+import '../../widget/module_controller.dart';
+
+class RoleController extends ModuleController {
+ RoleController(GlobalKey<FormState> formKey, State<StatefulWidget> parent)
+ : super(formKey, parent, RoleModel(Settings().logger)) {
+ moduleModel.parse();
+ }
+}
--- /dev/null
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../../widget/edit_form.dart';
+import 'role_controller.dart';
+
+class RoleCreatePage extends StatefulWidget {
+ final PageData pageData;
+ final logger = Settings().logger;
+ RoleCreatePageState lastState;
+
+ RoleCreatePage(this.pageData, {Key key}) : super(key: key);
+
+ @override
+ RoleCreatePageState createState() {
+ final rc = lastState = RoleCreatePageState(pageData);
+ return rc;
+ }
+}
+
+class RoleCreatePageState extends State<RoleCreatePage> {
+ final PageData pageData;
+
+ final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
+
+ RoleController controller;
+
+ RoleCreatePageState(this.pageData);
+
+ @override
+ Widget build(BuildContext context) {
+ controller = controller ?? RoleController(_formKey, this);
+ return Scaffold(
+ appBar: pageData.appBarBuilder('Neue Rolle'),
+ drawer: pageData.drawerBuilder(context),
+ body: EditForm.editForm(
+ key: _formKey,
+ isCreateForm: true,
+ moduleController: controller,
+ configuration: pageData.configuration,
+ ));
+ }
+}
--- /dev/null
+import 'package:flutter/material.dart';
+
+import '../../helper/settings.dart';
+import '../../model/model_types.dart';
+import '../../widget/filters.dart';
+import '../../widget/list_form.dart';
+import '../../widget/raised_button_bone.dart';
+import '../page_data.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;
+ }
+
+ Filters filters;
+
+ @override
+ Widget build(BuildContext context) {
+ final logger = Settings().logger;
+ if (filters == null) {
+ filters = Filters.ready(
+ _formKey,
+ this,
+ [
+ FilterItem(
+ name: 'role_name',
+ 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>[
+ RaisedButtonBone(
+ 'search', filters,
+ child: Text('Suchen'),
+ ),
+ ],
+ filters: filters,
+ ),
+ );
+ }
+}
+
+class Role {
+ int id;
+ String priority;
+ String name;
+}
+++ /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:dart_bones/dart_bones.dart';
+import 'package:flutter/material.dart';
+
+import 'module_controller.dart';
+import 'raised_button_bone.dart';
+
+typedef Function OnEditTap(Map<String, dynamic> row, int index);
+
+/// Contains helper functions for creating/changing data of a model based module.
+class EditForm {
+ /// Returns a widget with a form containing at least some input fields
+ /// and a save/cancel button.
+ /// [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 editForm({
+ @required Key key,
+ @required bool isCreateForm,
+ @required ModuleController moduleController,
+ @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>[
+ ...moduleController.getWidgets(isCreateForm),
+ SizedBox(
+ height: configuration.asFloat(
+ 'form.gap.field_button.height',
+ defaultValue: 16.0)),
+ ButtonBar(
+ children: <Widget>[
+ FlatButton(
+ child: Text('Abbruch'),
+ onPressed: moduleController.getOnPressed(
+ 'cancel', moduleController),
+ ),
+ RaisedButtonBone(
+ 'store',
+ moduleController,
+ child: Text('Speichern'),
+ ),
+ ],
+ ),
+ ],
+ ))),
+ );
+ }
+}
--- /dev/null
+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/list_form.dart';
+
+import 'text_form_field_bone.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.startsWith('*')
+ ? current.contains(value2.replaceAll('*', ''))
+ : 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
+ implements
+ TextCallbackController,
+ ButtonCallbackController,
+ TableCallbackController {
+ var filters = <FilterItem>[];
+ final BaseLogger logger;
+ final GlobalKey<FormState> globalKey;
+
+ State<StatefulWidget> parent;
+
+ Filters(this.globalKey, this.parent, this.logger);
+
+ Filters.ready(this.globalKey, this.parent, this.filters, this.logger);
+
+ void add(FilterItem item) => filters.add(item);
+
+ FilterItem byName(String name) =>
+ filters.firstWhere((element) => element.name == name);
+
+ @override
+ getOnChanged(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnEditingComplete(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnEditTap(String customString, TableCallbackController controller,
+ Map<String, dynamic> row) {
+ return null;
+ }
+
+ @override
+ getOnFieldSubmitted(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnHighlightChanged(String customString,
+ ButtonCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnLongPressed(String customString, ButtonCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnPressed(String customString, ButtonCallbackController controller) {
+ var rc;
+ if (customString == 'search') {
+ rc = () {
+ if (globalKey.currentState.validate()) {
+ globalKey.currentState.save();
+ parent.setState(() => null);
+ }
+ };
+ }
+ return rc;
+ }
+
+ @override
+ getOnSaved(String customString, TextCallbackController controller) {
+ return (input) {
+ byName(customString).value = input;
+ };
+ }
+
+ @override
+ getOnTap(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getValidator(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ /// Returns a list of widgets for the filter fields.
+ List<Widget> getWidgets() {
+ final rc = filters.map((filter) {
+ Widget rc = TextFormFieldBone(
+ filter.name,
+ this,
+ 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;
+ }
+}
import 'package:dart_bones/dart_bones.dart';
import 'package:flutter/material.dart';
-import '../helper/filters.dart';
+import 'filters.dart';
typedef Function OnEditTap(Map<String, dynamic> row, int index);
+abstract class TableCallbackController {
+ OnEditTap getOnEditTap(String customString,
+ TableCallbackController controller, Map<String, dynamic> row);
+}
+
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;"
/// [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.
+ /// If [showEditItems] is true the edit icon is shown in the additional first column.
+ /// If [sortIndex] is not null the rows will be sorted by this index.
static Widget table({
@required List<Widget> titles,
@required List<String> columnNames,
@required List<Map<String, dynamic>> rows,
bool showEditIcon = false,
- OnEditTap onEditTap,
+ int sortIndex,
+ TableCallbackController tableCallbackController,
+ String customString,
}) {
+ assert(titles.length == columnNames.length);
+ final titles2 = titles.map((item) => DataColumn(label: item)).toList();
+ if (showEditIcon) {
+ titles2.insert(0, DataColumn(label: SizedBox(width: 1)));
+ sortIndex = sortIndex == null ? null : sortIndex + 1;
+ }
Widget rc = Container(
margin: EdgeInsets.all(2),
child: DataTable(
showCheckboxColumn: true,
showBottomBorder: true,
- sortColumnIndex: 1,
- columns: titles.map((item) => DataColumn(label: item)).toList(),
+ sortColumnIndex: sortIndex,
+ columns: titles2,
rows: rows.map((row) {
final cells = <DataCell>[];
- int ix = -1;
+ if (showEditIcon) {
+ cells.add(DataCell(SizedBox(width: 1), showEditIcon: true));
+ }
for (var key in columnNames) {
- ix++;
cells.add(DataCell(
Text(row[key]),
- showEditIcon: showEditIcon && ix == 0,
- onTap: () => onEditTap == null ? null : onEditTap(row, ix),
+ onTap: () =>
+ tableCallbackController.getOnEditTap(
+ customString, tableCallbackController, row),
));
}
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.
- 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}) {
+ 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,
+ TableCallbackController tableCallbackController,
+ @required BaseConfiguration configuration,
+ String customString}) {
final padding =
- configuration.asFloat('form.card.padding', defaultValue: 16.0);
+ configuration.asFloat('form.card.padding', defaultValue: 16.0);
return Form(
key: key,
child: Card(
defaultValue: 16.0)),
...buttons,
table(
- titles: titles,
- columnNames: columnNames,
- rows: rows,
- showEditIcon: showEditIcon,
- onEditTap: onEditTap),
+ titles: titles,
+ columnNames: columnNames,
+ rows: rows,
+ showEditIcon: showEditIcon,
+ tableCallbackController: tableCallbackController,
+ customString: customString,
+ )
])),
));
}
--- /dev/null
+import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/widget_list.dart';
+
+import '../model/model_types.dart';
+import '../model/module_model.dart';
+import '../model/table_model.dart';
+import 'raised_button_bone.dart';
+import 'text_form_field_bone.dart';
+import 'widget_helper.dart';
+
+// This interface allows the generic handling of the edit form by a model driven module.
+class ModuleController
+ implements TextCallbackController, ButtonCallbackController {
+ final ModuleModel moduleModel;
+ String primaryColumn;
+ WidgetList createWidgets;
+ WidgetList changeWidgets;
+ final modelsMap = <String, ModelBase>{};
+ final dataTypes = <String, DataType>{};
+ final Map values = <String, dynamic>{};
+ final GlobalKey<FormState> globalKey;
+
+ State parent;
+
+ ModuleController(this.globalKey, this.parent, this.moduleModel) {
+ createWidgets = WidgetList(
+ '${moduleModel.fullName()}.createWidgets', moduleModel.logger);
+ changeWidgets = WidgetList(
+ '${moduleModel.fullName()}.changeWidgets', moduleModel.logger);
+ }
+
+ ModuleModel getModuleModel() => moduleModel;
+
+ @override
+ getOnChanged(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnEditingComplete(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnFieldSubmitted(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnHighlightChanged(
+ String customString, ButtonCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnLongPressed(String customString, ButtonCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getOnPressed(String customString, ButtonCallbackController controller) {
+ var rc;
+ if (customString == 'store') {
+ rc = () {
+ if (globalKey.currentState.validate()) {
+ globalKey.currentState.save();
+ moduleModel.logger.log('missing storage in onPressed');
+ }
+ };
+ }
+ return rc;
+ }
+
+ @override
+ getOnSaved(String customString, TextCallbackController controller) {
+ final rc = (input) {
+ values[customString] =
+ StringHelper.fromString(input, dataTypes[customString]);
+ };
+ return rc;
+ }
+
+ @override
+ getOnTap(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ @override
+ getValidator(String customString, TextCallbackController controller) {
+ return null;
+ }
+
+ /// Returns the widgets with at least the input fields of the form
+ ///
+ List<Widget> getWidgets(bool isCreateForm) {
+ List<Widget> rc;
+ if (isCreateForm) {
+ if (createWidgets == null || createWidgets.widgets.length == 0) {
+ modelToWidgets(moduleModel.mainTable(), this, createWidgets);
+ }
+ rc = createWidgets.widgets;
+ } else {
+ if (changeWidgets.widgets.length == 0) {
+ modelToWidgets(moduleModel.mainTable(), this, changeWidgets);
+ }
+ rc = changeWidgets.widgets;
+ }
+ return rc;
+ }
+
+ /// Reads the [tableModel] and creates the [widgetList] with all relevant
+ /// input fields.
+ void modelToWidgets(TableModel tableModel, ModuleController controller,
+ WidgetList widgetList) {
+ for (var column in tableModel.columns) {
+ if (!column.hasOption('hidden')) {
+ if (column.hasOption('primary')) {
+ primaryColumn = column.name;
+ }
+ Widget widget;
+ modelsMap[column.name] = column;
+ dataTypes[column.name] = column.dataType;
+ switch (column.dataType) {
+ case DataType.bool:
+ widget = null;
+ break;
+ default:
+ widget = WidgetHelper.toolTip(
+ TextFormFieldBone(
+ column.name,
+ controller,
+ decoration: InputDecoration(labelText: column.label),
+ ),
+ column.toolTip);
+ break;
+ }
+ if (widget != null) {
+ widgetList.addWidget(column.name, widget);
+ }
+ }
+ }
+ }
+}
import 'package:flutter/material.dart';
-import 'package:flutter_bones/flutter_bones.dart';
+/// Interface for a button specific callback controller.
+abstract class ButtonCallbackController {
+ ValueChanged<bool> getOnHighlightChanged(
+ String customString, ButtonCallbackController controller);
+
+ VoidCallback getOnLongPressed(
+ String customString, ButtonCallbackController controller);
+
+ VoidCallback getOnPressed(
+ String customString, ButtonCallbackController controller);
+}
+
+/// Implements a raised button with two additional properties:
+/// [customString] a string often used for a name needed in a callback method
+/// [customObject] an object known by the controller, often used in callback methods like onPressed
class RaisedButtonBone extends RaisedButton {
- final ButtonModel model;
+ final String customString;
+ final ButtonCallbackController callbackController;
- RaisedButtonBone(this.model,
- {ValueChanged<bool> onHighlightChanged,
- ButtonTextTheme textTheme,
+ RaisedButtonBone(this.customString, this.callbackController,
+ {ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Duration animationDuration,
Widget child})
: super(
- onPressed: model.onPressed,
- onLongPress: model.onLongPressed,
- onHighlightChanged: model.onHighlightChanged,
- textTheme: textTheme,
- textColor: textColor,
- disabledTextColor: disabledTextColor,
- color: color,
- disabledColor: disabledColor,
- focusColor: focusColor,
- hoverColor: hoverColor,
- highlightColor: highlightColor,
- splashColor: splashColor,
- colorBrightness: colorBrightness,
+ onPressed: callbackController.getOnPressed(
+ customString, callbackController),
+ onLongPress: callbackController.getOnLongPressed(
+ customString, callbackController),
+ onHighlightChanged: callbackController.getOnHighlightChanged(
+ customString, callbackController),
+ textTheme: textTheme,
+ textColor: textColor,
+ disabledTextColor: disabledTextColor,
+ color: color,
+ disabledColor: disabledColor,
+ focusColor: focusColor,
+ hoverColor: hoverColor,
+ highlightColor: highlightColor,
+ splashColor: splashColor,
+ colorBrightness: colorBrightness,
elevation: elevation,
focusElevation: focusElevation,
hoverElevation: hoverElevation,
import 'package:flutter/material.dart';
class SimpleForm {
- static Form simpleForm({@required Key key, @required List<Widget> fields,
- @required List<Widget> buttons, @required BaseConfiguration configuration} ) {
- final padding = configuration.asFloat('form.card.padding', defaultValue: 16.0);
+ static Form simpleForm(
+ {@required Key key,
+ @required List<Widget> fields,
+ @required List<Widget> buttons,
+ @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>[...fields,
- SizedBox(height: configuration.asFloat('form.gap.field_button.height', defaultValue: 16.0)),
- ...buttons]
- )),
- ));
+ margin: EdgeInsets.symmetric(vertical: padding, horizontal: padding),
+ child: Padding(
+ padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
+ child: ListView(children: <Widget>[
+ ...fields,
+ SizedBox(
+ height: configuration.asFloat(
+ 'form.gap.field_button.height',
+ defaultValue: 16.0)),
+ ...buttons
+ ])),
+ ));
}
-}
\ No newline at end of file
+}
--- /dev/null
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+/// Interface for a [TextFormField] specific callback controller.
+abstract class TextCallbackController {
+ ValueChanged<String> getOnChanged(
+ String customString, TextCallbackController controller);
+
+ VoidCallback getOnEditingComplete(
+ String customString, TextCallbackController controller);
+
+ ValueChanged<String> getOnFieldSubmitted(
+ String customString, TextCallbackController controller);
+
+ FormFieldSetter<String> getOnSaved(
+ String customString, TextCallbackController controller);
+
+ GestureTapCallback getOnTap(
+ String customString, TextCallbackController controller);
+
+ FormFieldValidator<String> getValidator(
+ String customString, TextCallbackController controller);
+}
+
+/// Implements a [TextFormField] with "outsourced" callbacks:
+/// [customString] a string mostly used for a name needed in the [customController]
+/// [callbackController] handles the callback methods.
+class TextFormFieldBone extends TextFormField {
+ final String customString;
+ final TextCallbackController callbackController;
+
+ TextFormFieldBone(
+ this.customString,
+ this.callbackController, {
+ Key key,
+ TextEditingController controller,
+ String initialValue,
+ FocusNode focusNode,
+ InputDecoration decoration = const InputDecoration(),
+ TextInputType keyboardType,
+ TextCapitalization textCapitalization = TextCapitalization.none,
+ TextInputAction textInputAction,
+ TextStyle style,
+ StrutStyle strutStyle,
+ TextDirection textDirection,
+ TextAlign textAlign = TextAlign.start,
+ TextAlignVertical textAlignVertical,
+ bool autofocus = false,
+ bool readOnly = false,
+ ToolbarOptions toolbarOptions,
+ bool showCursor,
+ String obscuringCharacter = '•',
+ bool obscureText = false,
+ bool autocorrect = true,
+ SmartDashesType smartDashesType,
+ SmartQuotesType smartQuotesType,
+ bool enableSuggestions = true,
+ bool maxLengthEnforced = true,
+ int maxLines = 1,
+ int minLines,
+ bool expands = false,
+ int maxLength,
+ List<TextInputFormatter> inputFormatters,
+ bool enabled,
+ double cursorWidth = 2.0,
+ double cursorHeight,
+ Radius cursorRadius,
+ Color cursorColor,
+ Brightness keyboardAppearance,
+ EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
+ bool enableInteractiveSelection = true,
+ InputCounterWidgetBuilder buildCounter,
+ ScrollPhysics scrollPhysics,
+ Iterable<String> autofillHints,
+ AutovalidateMode autovalidateMode,
+ }) : super(
+ controller: controller,
+ initialValue: initialValue,
+ focusNode: focusNode,
+ decoration: decoration,
+ keyboardType: keyboardType,
+ textCapitalization: textCapitalization,
+ textInputAction: textInputAction,
+ style: style,
+ strutStyle: strutStyle,
+ textDirection: textDirection,
+ textAlign: textAlign,
+ textAlignVertical: textAlignVertical,
+ autofocus: autofocus,
+ readOnly: readOnly,
+ toolbarOptions: toolbarOptions,
+ showCursor: showCursor,
+ obscuringCharacter: obscuringCharacter,
+ obscureText: obscureText,
+ autocorrect: autocorrect,
+ smartDashesType: smartDashesType,
+ smartQuotesType: smartQuotesType,
+ enableSuggestions: enableSuggestions,
+ maxLengthEnforced: maxLengthEnforced,
+ maxLines: maxLines,
+ minLines: minLines,
+ expands: expands,
+ maxLength: maxLength,
+ onChanged:
+ callbackController.getOnChanged(customString, callbackController),
+ onTap: callbackController.getOnTap(customString, callbackController),
+ onEditingComplete: callbackController.getOnEditingComplete(
+ customString, callbackController),
+ onFieldSubmitted: callbackController.getOnFieldSubmitted(
+ customString, callbackController),
+ onSaved:
+ callbackController.getOnSaved(customString, callbackController),
+ validator:
+ callbackController.getValidator(customString, callbackController),
+ inputFormatters: inputFormatters,
+ enabled: enabled,
+ cursorWidth: cursorWidth,
+ cursorHeight: cursorHeight,
+ cursorRadius: cursorRadius,
+ cursorColor: cursorColor,
+ keyboardAppearance: keyboardAppearance,
+ scrollPadding: scrollPadding,
+ enableInteractiveSelection: enableInteractiveSelection,
+ buildCounter: buildCounter,
+ scrollPhysics: scrollPhysics,
+ autofillHints: autofillHints,
+ autovalidateMode: autovalidateMode,
+ );
+}
/// Creates a button from the [model].
Widget button(ButtonModel model) {
final rc = RaisedButtonBone(
+ model.widgetName(),
model,
child: Text(model.text),
);
--- /dev/null
+import 'package:flutter/material.dart';
+
+/// Some little static helper methods round about [Widgets].
+class WidgetHelper {
+ /// If a [toolTip] is not empty the [widget] is completed with that.
+ /// Otherwise [widget] is returned.
+ static Widget toolTip(Widget widget, String toolTip) {
+ Widget rc;
+ if (toolTip == null || toolTip.isEmpty) {
+ rc = widget;
+ } else {
+ rc = Tooltip(message: toolTip, child: widget);
+ }
+ return rc;
+ }
+}
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/material.dart';
+
+/// Manages a list of named widgets.
+class WidgetList {
+ final String name;
+ final BaseLogger logger;
+ final widgetMap = <String, Widget>{};
+ final widgets = <Widget>[];
+
+ WidgetList(this.name, this.logger);
+
+ /// Adds a [widget] to the [widgets] behind the position of [predecessor].
+ /// If [predecessor] is null the widget will be the first in [widgets]
+ void addSuccessorOf(String predecessor, String name, Widget widget) {
+ if (predecessor == null) {
+ widgets.insert(0, widget);
+ } else {
+ if (!widgetMap.containsKey(predecessor)) {
+ logger
+ .error('$name.addSuccessorOf(): missing predecessor $predecessor');
+ } else {
+ final ix = widgets.indexOf(widgetMap[predecessor]);
+ widgets.insert(ix, widget);
+ }
+ }
+ addWidget(name, widget);
+ }
+
+ /// Adds a widget to the widget list.
+ void addWidget(String name, Widget widget) {
+ if (widgetMap.containsKey(name)) {
+ logger.error('$name.addWidget(): widget $name already defined');
+ } else {
+ widgetMap[name] = widget;
+ widgets.add(widget);
+ }
+ }
+
+ /// Returns the widget given by [name] or null if not found.
+ Widget byName(String name) {
+ final rc = widgetMap.containsKey(name) ? widgetMap[name] : null;
+ if (rc == null) {
+ logger.error('$name.byName(): missing widget $name');
+ }
+ return rc;
+ }
+}
--- /dev/null
+// This is a basic Flutter widget test.
+//
+// To perform an interaction with a widget in your test, use the WidgetTester
+// utility that Flutter provides. For example, you can send tap and scroll
+// gestures. You can also use WidgetTester to find child widgets in the widget
+// tree, read text, and verify that the values of widget properties are correct.
+
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/src/foundation/diagnostics.dart';
+import 'package:flutter/src/widgets/framework.dart' as x;
+import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/widget_helper.dart';
+import 'package:test/test.dart';
+
+void main() {
+ final logger = MemoryLogger();
+ final widgetConfiguration = BaseConfiguration({}, logger);
+ Settings(logger: logger, widgetConfiguration: widgetConfiguration);
+
+ group('WidgetHelper', () {
+ test('toolTip', () {
+ final widget = Text('Hi');
+ expect(WidgetHelper.toolTip(widget, null), equals(widget));
+ expect(WidgetHelper.toolTip(widget, ''), equals(widget));
+ Tooltip toolTip = WidgetHelper.toolTip(widget, 'Hi');
+ expect(toolTip.child, equals(widget));
+ });
+ });
+ group('ModuleController', () {
+ test('basic', () {
+ PageData pageData =
+ PageData(BaseConfiguration({}, logger), (title) {}, (context) {});
+ final role = RoleCreatePage(pageData);
+ if (role.lastState == null) {
+ role.createState();
+ }
+ expect(role, isNotNull);
+ BuildContext context = MyContext();
+ role.lastState.build(context);
+ final widgets = role.lastState.controller.getWidgets(true);
+ expect(widgets.length, equals(3));
+ });
+ });
+}
+
+class MyContext extends BuildContext {
+ @override
+ InheritedElement ancestorInheritedElementForWidgetOfExactType(
+ Type targetType) {
+ // TODO: implement ancestorInheritedElementForWidgetOfExactType
+ throw UnimplementedError();
+ }
+
+ @override
+ RenderObject ancestorRenderObjectOfType(x.TypeMatcher matcher) {
+ // TODO: implement ancestorRenderObjectOfType
+ throw UnimplementedError();
+ }
+
+ @override
+ State<StatefulWidget> ancestorStateOfType(x.TypeMatcher matcher) {
+ // TODO: implement ancestorStateOfType
+ throw UnimplementedError();
+ }
+
+ @override
+ Widget ancestorWidgetOfExactType(Type targetType) {
+ // TODO: implement ancestorWidgetOfExactType
+ throw UnimplementedError();
+ }
+
+ @override
+ // TODO: implement debugDoingBuild
+ bool get debugDoingBuild => throw UnimplementedError();
+
+ @override
+ InheritedWidget dependOnInheritedElement(InheritedElement ancestor,
+ {Object aspect}) {
+ // TODO: implement dependOnInheritedElement
+ throw UnimplementedError();
+ }
+
+ @override
+ T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>(
+ {Object aspect}) {
+ // TODO: implement dependOnInheritedWidgetOfExactType
+ throw UnimplementedError();
+ }
+
+ @override
+ DiagnosticsNode describeElement(String name,
+ {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty}) {
+ // TODO: implement describeElement
+ throw UnimplementedError();
+ }
+
+ @override
+ List<DiagnosticsNode> describeMissingAncestor({Type expectedAncestorType}) {
+ // TODO: implement describeMissingAncestor
+ throw UnimplementedError();
+ }
+
+ @override
+ DiagnosticsNode describeOwnershipChain(String name) {
+ // TODO: implement describeOwnershipChain
+ throw UnimplementedError();
+ }
+
+ @override
+ DiagnosticsNode describeWidget(String name,
+ {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty}) {
+ // TODO: implement describeWidget
+ throw UnimplementedError();
+ }
+
+ @override
+ T findAncestorRenderObjectOfType<T extends RenderObject>() {
+ // TODO: implement findAncestorRenderObjectOfType
+ throw UnimplementedError();
+ }
+
+ @override
+ T findAncestorStateOfType<T extends State<StatefulWidget>>() {
+ // TODO: implement findAncestorStateOfType
+ throw UnimplementedError();
+ }
+
+ @override
+ T findAncestorWidgetOfExactType<T extends Widget>() {
+ // TODO: implement findAncestorWidgetOfExactType
+ throw UnimplementedError();
+ }
+
+ @override
+ RenderObject findRenderObject() {
+ // TODO: implement findRenderObject
+ throw UnimplementedError();
+ }
+
+ @override
+ T findRootAncestorStateOfType<T extends State<StatefulWidget>>() {
+ // TODO: implement findRootAncestorStateOfType
+ throw UnimplementedError();
+ }
+
+ @override
+ InheritedElement
+ getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
+ // TODO: implement getElementForInheritedWidgetOfExactType
+ throw UnimplementedError();
+ }
+
+ @override
+ InheritedWidget inheritFromElement(InheritedElement ancestor,
+ {Object aspect}) {
+ // TODO: implement inheritFromElement
+ throw UnimplementedError();
+ }
+
+ @override
+ InheritedWidget inheritFromWidgetOfExactType(Type targetType,
+ {Object aspect}) {
+ // TODO: implement inheritFromWidgetOfExactType
+ throw UnimplementedError();
+ }
+
+ @override
+ // TODO: implement owner
+ BuildOwner get owner => throw UnimplementedError();
+
+ @override
+ State<StatefulWidget> rootAncestorStateOfType(x.TypeMatcher matcher) {
+ // TODO: implement rootAncestorStateOfType
+ throw UnimplementedError();
+ }
+
+ @override
+ // TODO: implement size
+ Size get size => throw UnimplementedError();
+
+ @override
+ void visitAncestorElements(bool Function(Element element) visitor) {
+ // TODO: implement visitAncestorElements
+ }
+
+ @override
+ void visitChildElements(visitor) {
+ // TODO: implement visitChildElements
+ }
+
+ @override
+ // TODO: implement widget
+ Widget get widget => throw UnimplementedError();
+}
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
-/*
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
+//import 'package:flutter/material.dart';
+//import 'package:flutter_bones/main.dart';
+//import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-*/
void main() {
- /*
- testWidgets('Counter increments smoke test', (WidgetTester tester) async {
- // Build our app and trigger a frame.
- await tester.pumpWidget(MyApp());
-
- // Verify that our counter starts at 0.
- expect(find.text('0'), findsOneWidget);
- expect(find.text('1'), findsNothing);
-
- // Tap the '+' icon and trigger a frame.
- await tester.tap(find.byIcon(Icons.add));
- await tester.pump();
-
- // Verify that our counter has incremented.
- expect(find.text('0'), findsNothing);
- expect(find.text('1'), findsOneWidget);
- });
- */
+ // testWidgets('Counter increments smoke test', (WidgetTester tester) async {
+ // // Build our app and trigger a frame.
+ // await tester.pumpWidget(MyApp());
+ //
+ // // Verify that our counter starts at 0.
+ // expect(find.text('0'), findsOneWidget);
+ // expect(find.text('1'), findsNothing);
+ //
+ // // Tap the '+' icon and trigger a frame.
+ // await tester.tap(find.byIcon(Icons.add));
+ // await tester.pump();
+ //
+ // // Verify that our counter has incremented.
+ // expect(find.text('0'), findsNothing);
+ // expect(find.text('1'), findsOneWidget);
+ // });
}