From cfa0a2c611df281ae62a594e5d4c8571d306f856 Mon Sep 17 00:00:00 2001 From: Hamatoma Date: Mon, 24 Jan 2022 20:11:35 +0100 Subject: [PATCH] Refactoring, installation of a derived project * Benchmark: new birthday * widget: ** attended_page: fix: condition for icon ** new: date_form_field and date_time_form_field * PageGenerator: Fix: wrong substition for #REQ_RECORD * Tools: ** metatool/Compile: using absolute path for better understanding ** InitProject: many fixes ** PackRestServer: fix in output --- SvRS | 7 + X | 8 + .../benchmarks/edit_benchmark_custom.dart | 21 +- .../mapping_rolestarter_custom.00.dart | 183 +++++++++++ .../mapping_rolestarter_custom.01.dart | 304 ++++++++++++++++++ lib/page/start_page.dart | 3 +- lib/widget/attended_page.dart | 2 +- lib/widget/date_form_field.dart | 153 +++++++++ lib/widget/date_time_form_field.dart | 180 +++++++++++ metatool/Compile | 5 +- metatool/bin/page_generator.dart | 2 +- metatool/rest_server/data/sql/roles.sql.yaml | 32 -- metatool/rest_server/data/sql/users.sql.yaml | 34 -- metatool/test/helper_test.dart | 250 -------------- metatool/test/validators_test.dart | 67 ---- tools/InitProject | 152 +++++---- tools/PackRestServer | 5 +- 17 files changed, 956 insertions(+), 452 deletions(-) create mode 100755 SvRS create mode 100755 X create mode 100644 lib/page/rolestarter/mapping_rolestarter_custom.00.dart create mode 100644 lib/page/rolestarter/mapping_rolestarter_custom.01.dart create mode 100644 lib/widget/date_form_field.dart create mode 100644 lib/widget/date_time_form_field.dart delete mode 100644 metatool/rest_server/data/sql/roles.sql.yaml delete mode 100644 metatool/rest_server/data/sql/users.sql.yaml delete mode 100644 metatool/test/helper_test.dart delete mode 100644 metatool/test/validators_test.dart diff --git a/SvRS b/SvRS new file mode 100755 index 0000000..21a171a --- /dev/null +++ b/SvRS @@ -0,0 +1,7 @@ +#! /bin/bash +MODULE=rolestarter +MODULE2=rolestarter +PAGE=mapping +cd lib/page/$MODULE +cp -a ${PAGE}_${MODULE2}_custom.dart ${PAGE}_${MODULE2}_custom.01.dart +ls -ld ${PAGE}_${MODULE2}_custom.01.dart diff --git a/X b/X new file mode 100755 index 0000000..0545cf0 --- /dev/null +++ b/X @@ -0,0 +1,8 @@ +#! /bin/bash +./ReCreateMetaTool +cd lib/page +find -name "*custom.dart" -a ! -name "list_benchmark*.dart" -a ! -name "mapping_*.dart" -delete +#find -name "*custom.dart" -delete +#rm edit_user_custom.dart +cd ../.. +./Meta update-modules-files | grep custom | grep -v "override" diff --git a/lib/page/benchmarks/edit_benchmark_custom.dart b/lib/page/benchmarks/edit_benchmark_custom.dart index de6c688..158d443 100644 --- a/lib/page/benchmarks/edit_benchmark_custom.dart +++ b/lib/page/benchmarks/edit_benchmark_custom.dart @@ -10,6 +10,7 @@ import '../../persistence/persistence.dart'; import '../../services/global_widget.dart'; import '../../setting/global_data.dart'; import '../../widget/attended_page.dart'; +import '../../widget/date_form_field.dart'; import '../../widget/message_line.dart'; import '../../widget/widget_form.dart'; import 'edit_benchmark_page.dart'; @@ -30,7 +31,12 @@ class EditBenchmarkCustom extends State with MessageLine { final birthdayController = TextEditingController(); final weightController = TextEditingController(); final incomeController = TextEditingController(); + final birthdayData = DateData( + initialDate: DateTime(1970), + firstDate: DateTime(1900), + lastDate: DateTime(DateTime.now().year)); EditBenchmarkCustom(this.primaryKey); + @override Widget build(BuildContext context) { final rc = Scaffold( @@ -57,6 +63,7 @@ class EditBenchmarkCustom extends State with MessageLine { birthdayController.text = asString(_fieldData.birthday, dateOnly: true); weightController.text = asString(_fieldData.weight); incomeController.text = asString(_fieldData.income); + birthdayData.setInitialDate(_fieldData.birthday); final formItems = [ FormItem( TextFormField( @@ -80,8 +87,10 @@ class EditBenchmarkCustom extends State with MessageLine { onSaved: (value) => _fieldData.email = value ?? ''), weight: 6), FormItem( - TextFormField( - controller: birthdayController, + DateFormField( + context: context, + dateData: birthdayData, + dateController: birthdayData.dateController, decoration: InputDecoration(labelText: i18n.tr('Birthday')), validator: (input) => notEmpty(input), onSaved: (value) => _fieldData.birthday = @@ -171,10 +180,6 @@ class EditBenchmarkCustom extends State with MessageLine { super.initState(); } - void requestRecord() => _futureDbData = globalData.restPersistence.query( - what: 'query', - data: {'module': 'Users', 'sql': 'byId', ':id': primaryKey}); - void onStore() { final parameters = { 'module': 'Benchmarks', @@ -197,6 +202,10 @@ class EditBenchmarkCustom extends State with MessageLine { onStore(); } } + + void requestRecord() => _futureDbData = globalData.restPersistence.query( + what: 'query', + data: {'module': 'Benchmarks', 'sql': 'byId', ':id': primaryKey}); } class _FieldData { diff --git a/lib/page/rolestarter/mapping_rolestarter_custom.00.dart b/lib/page/rolestarter/mapping_rolestarter_custom.00.dart new file mode 100644 index 0000000..aeddd0f --- /dev/null +++ b/lib/page/rolestarter/mapping_rolestarter_custom.00.dart @@ -0,0 +1,183 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/widget_form.dart'; +import '../../persistence/persistence.dart'; +import 'mapping_rolestarter_page.dart'; + +final i18n = I18N(); + +class MappingRoleStarterCustom extends State { + final globalData = GlobalData(); + late Future _futureDbDataMember; + late Future _futureDbDataNotMember; + AttendedPage? attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateRole'); + final textController = TextEditingController(); + MappingRoleStarterCustom(); + @override + Widget build(BuildContext context) { + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('#LABEL')), + drawer: globalData.drawerBuilder(context), + body: SafeArea( + child: FutureBuilder>( + future: Future.wait([_futureDbDataMember, _futureDbDataNotMember]), + builder: (context, AsyncSnapshot> snapshot) { + Widget rc; + if (snapshot.connectionState != ConnectionState.done) { + rc = const CircularProgressIndicator(); + } else { + if (snapshot.hasData) { + final rowsMembers = attendedPage!.getRows( + dbData: snapshot.data![0], + columnList: 'starter_name;starter_link', + onDone: () => setState(() => 1), + routeEdit: '', + context: context); + final rowsNotMembers = attendedPage!.getRows( + dbData: snapshot.data![1], + columnList: 'starter_name;starter_link', + onDone: () => setState(() => 1), + routeEdit: '', + context: context); + rc = buildFrame( + rowsMembers: rowsMembers, rowsNotMembers: rowsNotMembers); + } else if (snapshot.hasError) { + rc = Text('Backend problem: ${snapshot.error}'); + } else { + rc = const CircularProgressIndicator(); + } + } + return rc; + }, + )), + ); + return rc; + } + + Widget buildFrame( + {required JsonList rowsMembers, required JsonList rowsNotMembers}) { + final padding = GlobalThemeData.padding; + final itemsRoles = >[]; + final formItems = [ + FormItem( + DropdownButtonFormField( + value: itemsRoles.length == 1 ? 0 : _fieldData.role, + items: itemsRoles, + isExpanded: true, + decoration: InputDecoration(labelText: i18n.tr('Role')), + onChanged: (value) => _fieldData.role = value ?? 0, + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => search(), child: Text(i18n.tr('Search'))), + weight: 12, + gapAbove: padding), + ]; + final form = Form( + key: _formKey, + child: Card( + color: GlobalThemeData.formBackgroundColor, + elevation: GlobalThemeData.formElevation, + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid(formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding)))); + final tableMembers = DataTable( + columns: [ + DataColumn( + label: Text(i18n.tr('Id')), + ), + DataColumn( + label: Text(i18n.tr('Name')), + ), + ], + rows: rowsMembers as List, + ); + final tableNotMembers = DataTable( + columns: [ + DataColumn( + label: Text(i18n.tr('Id')), + ), + DataColumn( + label: Text(i18n.tr('Name')), + ), + ], + rows: rowsNotMembers as List, + ); + final frameWidget = ListView(children: [ + form, + Text(i18n.tr('The following items are assigned. Click it to remove.')), + SizedBox(height: padding), + tableMembers, + SizedBox(height: padding), + Text( + i18n.tr('The following items are not assigned. Click it to assign.')), + SizedBox(height: padding), + tableNotMembers, + ]); + return frameWidget; + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + requestRecords(); + } + + @override + void dispose() { + helperDummyUsage(DataType.string); + globalWidgetDummyUsage(); + textController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + } + + void requestRecords() { + _futureDbDataMember = + globalData.restPersistence.query(what: 'query', data: { + 'module': 'RoleStarter', + 'sql': 'members', + ':role': _fieldData.role, + }); + _futureDbDataNotMember = + globalData.restPersistence.query(what: 'query', data: { + 'module': 'RoleStarter', + 'sql': 'notmembers', + ':role': _fieldData.role, + }); + } + + void search() { + attendedPage!.pageStates.dbDataState.clear(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + requestRecords(); + setState(() => 1); + } + } +} + +class _FieldData { + int role = 0; +} diff --git a/lib/page/rolestarter/mapping_rolestarter_custom.01.dart b/lib/page/rolestarter/mapping_rolestarter_custom.01.dart new file mode 100644 index 0000000..c03e7da --- /dev/null +++ b/lib/page/rolestarter/mapping_rolestarter_custom.01.dart @@ -0,0 +1,304 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../persistence/persistence.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/widget_form.dart'; +import 'mapping_rolestarter_page.dart'; + +final i18n = I18N(); + +class CommonInfo { + final List columns; + final List members = []; + CommonInfo({required this.columns}); +} + +class MappingRoleStarterCustom extends State { + final globalData = GlobalData(); + late Future _futureDbDataCommon; + late Future _futureDbDataMember; + late Future _futureDbDataConnection; + var membersOfCommon = >{}; + late AttendedPage attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateRole'); + final textController = TextEditingController(); + final commonColumns = ['role_name']; + final memberColumns = ['starter_name', 'starter_route']; + final commonInfos = {}; + + /// Members of the current common module: + final memberInfos = []; + + final notMemberInfos = []; + JsonList membersRows = []; + JsonList commonRows = []; + JsonList connectionRows = []; + MappingRoleStarterCustom(); + + @override + Widget build(BuildContext context) { + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('Role/Starter Assignment')), + drawer: globalData.drawerBuilder(context), + body: SafeArea( + child: FutureBuilder>( + future: Future.wait([ + _futureDbDataMember, + _futureDbDataCommon, + _futureDbDataConnection + ]), + builder: (context, AsyncSnapshot> snapshot) { + Widget rc; + if (snapshot.connectionState != ConnectionState.done) { + rc = const CircularProgressIndicator(); + } else { + if (snapshot.hasData) { + commonRows = snapshot.data![0].recordList ?? []; + membersRows = snapshot.data![1].recordList ?? []; + connectionRows = snapshot.data![2].recordList ?? []; + handleConnectionRows(); + rc = buildFrame(); + } else if (snapshot.hasError) { + rc = Text('Backend problem: ${snapshot.error}'); + } else { + rc = const CircularProgressIndicator(); + } + } + return rc; + }, + )), + ); + return rc; + } + + /// Builds the items of the common module combobox from the database records. + List> buildCommonItems() { + final rc = >[]; + for (var record in commonRows) { + rc.add(DropdownMenuItem( + value: record['role_id'], child: Text(record['role_name']))); + } + return rc; + } + + Widget buildFrame() { + final padding = GlobalThemeData.padding; + final itemsRoles = >[]; + final formItems = [ + FormItem( + DropdownButtonFormField( + value: itemsRoles.length == 1 ? 0 : _fieldData.role, + items: buildCommonItems(), + isExpanded: true, + decoration: InputDecoration(labelText: i18n.tr('Role')), + onChanged: (value) => _fieldData.role = value ?? 0, + ), + weight: 6), + FormItem( + ElevatedButton(onPressed: () => save(), child: Text(i18n.tr('Save'))), + weight: 12, + gapAbove: padding), + ]; + final form = Form( + key: _formKey, + child: Card( + color: GlobalThemeData.formBackgroundColor, + elevation: GlobalThemeData.formElevation, + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid(formItems, + screenWidth: attendedPage.pageStates.screenWidth, + padding: padding)))); + final tableMembers = buildMemberTable(); + final tableNotMembers = buildNotMemberTable(); + final frameWidget = ListView(children: [ + form, + Text(i18n.tr('The following items are assigned. Click it to remove.')), + SizedBox(height: padding), + tableMembers, + SizedBox(height: padding), + Text( + i18n.tr('The following items are not assigned. Click it to assign.')), + SizedBox(height: padding), + tableNotMembers, + ]); + return frameWidget; + } + + buildMemberTable() { + final rows = buildTableItems( + commonInfos[_fieldData.role]!.members, 'rolestarter_id'); + final headers = []; + for (var column in commonInfos[_fieldData.role]!.columns) { + final label = + attendedPage.moduleMetaData.propertyByColumnName(column)?.label ?? + i18n.tr('Info'); + headers.add(DataColumn(label: Text(label))); + } + final rc = DataTable( + columns: headers, + rows: rows, + ); + return rc; + } + + buildNotMemberTable() { + final rows = buildTableItems( + commonInfos[_fieldData.role]!.members, 'rolestarter_id'); + final headers = []; + for (var column in commonInfos[_fieldData.role]!.columns) { + final label = + attendedPage.moduleMetaData.propertyByColumnName(column)?.label ?? + i18n.tr('Info'); + headers.add(DataColumn(label: Text(label))); + } + final rc = DataTable( + columns: headers, + rows: rows, + ); + return rc; + } + + /// Build the [notMemberInfos] list of items not being members of the common + /// module with [commonId]. + void buildNotMembers(int commonId) { + notMemberInfos.clear(); + int order = 10; + for (var record in membersRows) { + final id = record['rolestarter_starter']; + if (record['rolestarter_role'] == commonId && !hasMember(id)) { + notMemberInfos.add(MemberInfo( + memberId: id, position: order++, columns: memberColumns)); + } + } + } + + buildTableItems(List members, String primary) { + members.map((MemberInfo element) { + final cells = []; + final record = findRecord(membersRows, primary, element.memberId); + if (record != null) { + for (var column in element.columns) { + cells.add(DataCell(Text(record[column]))); + } + } + return DataRow(cells: cells); + }); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + requestRecords(); + } + + @override + void dispose() { + helperDummyUsage(DataType.string); + globalWidgetDummyUsage(); + textController.dispose(); + super.dispose(); + } + + /// Finds a record in a list of records by a given [id] in a given [column]. + JsonMap? findRecord(JsonList rows, String column, int id) { + JsonMap? rc; + for (var record in rows) { + if (record[column] == id) { + rc = record; + break; + } + } + return rc; + } + + /// Inspects the [connectionRows] and build the internal structures. + void handleConnectionRows() { + commonInfos.clear(); + for (var record in commonRows) { + int common = record['role_id']; + commonInfos[common] = CommonInfo(columns: commonColumns); + } + for (var record in connectionRows) { + int common = record['rolestarter_role']; + if (!commonInfos.containsKey(common)) { + commonInfos[common] = CommonInfo(columns: commonColumns); + } + commonInfos[common]!.members.add(MemberInfo( + memberId: record['rolestarter_starter'], + columns: memberColumns, + position: record['rolestarter_position'])); + } + for (var key in commonInfos.keys) { + commonInfos[key]!.members.sort((a, b) => a.position - b.position); + } + } + + /// Returns whether the given [memberId] is part of [memberInfos]. + bool hasMember(int memberId) { + bool rc = false; + for (var item in memberInfos) { + if (item.memberId == memberId) { + rc = true; + break; + } + } + return rc; + } + + @override + void initState() { + super.initState(); + } + + void requestRecords() { + _futureDbDataMember = + globalData.restPersistence.query(what: 'query', data: { + 'module': 'Starters', + 'sql': 'all', + }); + _futureDbDataCommon = + globalData.restPersistence.query(what: 'query', data: { + 'module': 'Roles', + 'sql': 'all', + }); + _futureDbDataConnection = + globalData.restPersistence.query(what: 'query', data: { + 'module': 'RoleStarter', + 'sql': 'all', + }); + } + + void save() { + attendedPage.pageStates.dbDataState.clear(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + requestRecords(); + setState(() => 1); + } + } +} + +class MemberInfo { + final int memberId; + final int position; + final List columns; + MemberInfo( + {required this.memberId, required this.position, required this.columns}); +} + +class _FieldData { + int role = 0; +} diff --git a/lib/page/start_page.dart b/lib/page/start_page.dart index 845dc5c..129f8d4 100644 --- a/lib/page/start_page.dart +++ b/lib/page/start_page.dart @@ -96,7 +96,8 @@ class StartPageState extends State { RestPersistence.fromConfig(configuration, logger), logger); globalData.initializeAsync().then((value) { - globalData.navigate(context, '/RoleStarter/mapping'); + // globalData.navigate(context, '/RoleStarter/mapping'); + globalData.navigate(context, '/Benchmarks/list'); }); } }); diff --git a/lib/widget/attended_page.dart b/lib/widget/attended_page.dart index 7ddf1d1..638c379 100644 --- a/lib/widget/attended_page.dart +++ b/lib/widget/attended_page.dart @@ -122,7 +122,7 @@ class AttendedPage extends ChangeNotifier { ? Icons.beenhere_outlined : Icons.first_page_outlined; } else if (ix == chipCount - 1) { - icon = currentPage == 1 + icon = currentPage == pageCount ? Icons.beenhere_outlined : Icons.last_page_outlined; } else if (ix == currentIndex) { diff --git a/lib/widget/date_form_field.dart b/lib/widget/date_form_field.dart new file mode 100644 index 0000000..8533d8b --- /dev/null +++ b/lib/widget/date_form_field.dart @@ -0,0 +1,153 @@ +import 'package:flutter/material.dart'; + +import '../base/helper.dart'; +import '../base/i18n.dart'; +import '../setting/global_data.dart'; + +final i18n = I18N(); + +/// Manages the main attributes of a DateFormField. +class DateData { + DateTime? initialDate; + late final DateTime firstDate; + late final DateTime lastDate; + DateTime? selectedDate; + final Function? onSelected; + final dateController = TextEditingController(); + + /// Constructor. + /// + /// [inititialDate]: the date that is displayed while starting the date picker. + /// + /// [firstDate]: the oldest date showed in the date picker. + /// + /// [lastDate]: the youngest date showed in the date picker. + /// + /// [onSelected]: this function is called after a date is selected. + DateData( + {DateTime? initialDate, + DateTime? firstDate, + DateTime? lastDate, + this.onSelected}) { + final now = DateTime.now(); + this.initialDate = initialDate ?? now; + this.lastDate = lastDate ?? DateTime(now.year + 1); + this.firstDate = firstDate ?? DateTime(now.year - 1); + selectedDate = now; + } + + /// Handles the "button pressed" event in DateFormField. + onButtonPressed(BuildContext context, + {required Function(DateTime selected) storeSelected}) async { + final DateTime? picked = await showDatePicker( + context: context, + initialDate: initialDate ?? DateTime(1970), // Refer step 1 + firstDate: firstDate, + lastDate: lastDate, + ); + if (picked != null) { + selectedDate = picked; + dateController.text = asString(picked, dateOnly: true); + if (onSelected != null) { + onSelected!(); + } + } + } + + /// Sets the initial date to [dateTime]. + void setInitialDate(DateTime? dateTime) { + initialDate = dateTime; + dateController.text = + dateTime == null ? '' : asString(dateTime, dateOnly: true); + } +} + +/// Manages a text field with a button to call a date picker. +class DateFormField extends Container { + final DateData dateData; + final TextEditingController dateController; + DateFormField( + {required BuildContext context, + required this.dateData, + required this.dateController, + Key? key, + FocusNode? focusNode, + InputDecoration? decoration = const InputDecoration(), + TextInputType? keyboardType = TextInputType.datetime, + TextInputAction? textInputAction, + TextStyle? style, + StrutStyle? strutStyle, + TextAlign textAlign = TextAlign.start, + TextAlignVertical? textAlignVertical, + bool autofocus = false, + bool readOnly = false, + ToolbarOptions? toolbarOptions, + bool? showCursor, + bool autocorrect = true, + SmartDashesType? smartDashesType, + SmartQuotesType? smartQuotesType, + bool enableSuggestions = true, + bool autovalidate = false, + bool maxLengthEnforced = true, + bool expands = false, + int? maxLength, + ValueChanged? onChanged, + GestureTapCallback? onTap, + VoidCallback? onEditingComplete, + ValueChanged? onFieldSubmitted, + FormFieldSetter? onSaved, + FormFieldValidator? validator, + bool? enabled, + double cursorWidth = 2.0, + double? cursorHeight, + Radius? cursorRadius, + Color? cursorColor, + Brightness? keyboardAppearance, + EdgeInsets scrollPadding = const EdgeInsets.all(20.0), + bool enableInteractiveSelection = true, + TextSelectionControls? selectionControls, + InputCounterWidgetBuilder? buildCounter, + ScrollPhysics? scrollPhysics, + Iterable? autofillHints, + AutovalidateMode? autovalidateMode, + ScrollController? scrollController, + String? restorationId, + bool enableIMEPersonalizedLearning = true, + double? gapWidth, + DateTime? initialDate}) + : super( + child: Row(children: [ + Expanded( + child: TextFormField( + onTap: onTap, + controller: dateController, + onEditingComplete: onEditingComplete, + onFieldSubmitted: onFieldSubmitted, + onSaved: onSaved, + validator: validator, + enabled: enabled, + cursorWidth: cursorWidth, + cursorHeight: cursorHeight, + cursorRadius: cursorRadius, + cursorColor: cursorColor, + keyboardAppearance: keyboardAppearance, + scrollPadding: scrollPadding, + enableInteractiveSelection: enableInteractiveSelection, + selectionControls: selectionControls, + buildCounter: buildCounter, + scrollPhysics: scrollPhysics, + autofillHints: autofillHints, + autovalidateMode: autovalidateMode, + scrollController: scrollController, + restorationId: restorationId, + enableIMEPersonalizedLearning: enableIMEPersonalizedLearning, + )), + SizedBox(width: gapWidth ?? GlobalThemeData.padding), + ElevatedButton( + onPressed: () => + dateData.onButtonPressed(context, storeSelected: (selected) { + dateData.selectedDate = selected; + }), + child: Icon(Icons.calendar_today_outlined)), + ])); +} diff --git a/lib/widget/date_time_form_field.dart b/lib/widget/date_time_form_field.dart new file mode 100644 index 0000000..e9fc3fb --- /dev/null +++ b/lib/widget/date_time_form_field.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; +import 'package:sprintf/sprintf.dart'; + +import '../base/helper.dart'; +import '../base/i18n.dart'; +import '../setting/global_data.dart'; + +final i18n = I18N(); + +/// Manages the main attributes of a DateFormField. +class DateTimeData { + DateTime? initialDate; + TimeOfDay? initialTime; + late final DateTime firstDate; + late final DateTime lastDate; + DateTime? selectedDate; + TimeOfDay? selectedTime; + final Function? onSelected; + final dateController = TextEditingController(); + + /// Constructor. + /// + /// [inititialDate]: the date that is displayed while starting the date picker. + /// [inititialDate]: the date that is displayed while starting the date picker. + /// + /// [firstDate]: the oldest date showed in the date picker. + /// + /// [lastDate]: the youngest date showed in the date picker. + /// + /// [onSelected]: this function is called after a date is selected. + DateTimeData( + {DateTime? initialDateTime, + DateTime? initialDate, + TimeOfDay? initialTime, + DateTime? firstDate, + DateTime? lastDate, + this.onSelected}) { + final now = DateTime.now(); + if (initialDateTime != null) { + this.initialDate = DateTime( + initialDateTime.year, initialDateTime.month, initialDateTime.day); + this.initialTime = + TimeOfDay(hour: initialDateTime.hour, minute: initialDateTime.minute); + } else { + this.initialDate = initialDate; + this.initialTime = initialTime; + } + this.initialDate = initialDate ?? now; + this.initialTime = initialTime ?? TimeOfDay(hour: 8, minute: 0); + this.lastDate = lastDate ?? DateTime(now.year + 1); + this.firstDate = firstDate ?? DateTime(now.year - 1); + selectedDate = initialDate; + } + + /// Handles the "button pressed" event in DateFormField. + onButtonPressed(BuildContext context, + {required Function(DateTime selected) storeSelected}) async { + final TimeOfDay? picked = await showTimePicker( + context: context, + initialTime: initialTime ?? TimeOfDay(hour: 8, minute: 0), + ); + if (picked != null) { + selectedTime = picked; + dateController.text = asString(selectedDate, dateOnly: true) + + sprintf(' %02d:%02d', [picked.hour, picked.minute]); + if (onSelected != null) { + onSelected!(); + } + } + } + + /// Sets the initial date to [dateTime]. + void setInitialDate(DateTime? dateTime) { + if (dateTime == null) { + dateController.text = ''; + initialDate = null; + initialTime = null; + } else { + initialDate = DateTime(dateTime.year, dateTime.month, dateTime.day); + dateController.text = asString(dateTime, dateOnly: true); + } + } +} + +/// Manages a text field with a button to call a date picker. +class DateTimeFormField extends Container { + final DateTimeData dateData; + final TextEditingController dateController; + DateTimeFormField( + {required BuildContext context, + required this.dateData, + required this.dateController, + Key? key, + FocusNode? focusNode, + InputDecoration? decoration = const InputDecoration(), + TextInputType? keyboardType = TextInputType.datetime, + TextInputAction? textInputAction, + TextStyle? style, + StrutStyle? strutStyle, + TextAlign textAlign = TextAlign.start, + TextAlignVertical? textAlignVertical, + bool autofocus = false, + bool readOnly = false, + ToolbarOptions? toolbarOptions, + bool? showCursor, + bool autocorrect = true, + SmartDashesType? smartDashesType, + SmartQuotesType? smartQuotesType, + bool enableSuggestions = true, + bool autovalidate = false, + bool maxLengthEnforced = true, + bool expands = false, + int? maxLength, + ValueChanged? onChanged, + GestureTapCallback? onTap, + VoidCallback? onEditingComplete, + ValueChanged? onFieldSubmitted, + FormFieldSetter? onSaved, + FormFieldValidator? validator, + bool? enabled, + double cursorWidth = 2.0, + double? cursorHeight, + Radius? cursorRadius, + Color? cursorColor, + Brightness? keyboardAppearance, + EdgeInsets scrollPadding = const EdgeInsets.all(20.0), + bool enableInteractiveSelection = true, + TextSelectionControls? selectionControls, + InputCounterWidgetBuilder? buildCounter, + ScrollPhysics? scrollPhysics, + Iterable? autofillHints, + AutovalidateMode? autovalidateMode, + ScrollController? scrollController, + String? restorationId, + bool enableIMEPersonalizedLearning = true, + double? gapWidth, + DateTime? initialDate}) + : super( + child: Row(children: [ + Expanded( + child: TextFormField( + onTap: onTap, + controller: dateController, + onEditingComplete: onEditingComplete, + onFieldSubmitted: onFieldSubmitted, + onSaved: onSaved, + validator: validator, + enabled: enabled, + cursorWidth: cursorWidth, + cursorHeight: cursorHeight, + cursorRadius: cursorRadius, + cursorColor: cursorColor, + keyboardAppearance: keyboardAppearance, + scrollPadding: scrollPadding, + enableInteractiveSelection: enableInteractiveSelection, + selectionControls: selectionControls, + buildCounter: buildCounter, + scrollPhysics: scrollPhysics, + autofillHints: autofillHints, + autovalidateMode: autovalidateMode, + scrollController: scrollController, + restorationId: restorationId, + enableIMEPersonalizedLearning: enableIMEPersonalizedLearning, + )), + SizedBox(width: gapWidth ?? GlobalThemeData.padding), + ElevatedButton( + onPressed: () => + dateData.onButtonPressed(context, storeSelected: (selected) { + dateData.selectedDate = selected; + }), + child: Icon(Icons.calendar_today_outlined)), + SizedBox(width: gapWidth ?? GlobalThemeData.padding), + ElevatedButton( + onPressed: () => + dateData.onButtonPressed(context, storeSelected: (selected) { + dateData.selectedDate = selected; + }), + child: Icon(Icons.lock_clock_outlined)), + ])); +} diff --git a/metatool/Compile b/metatool/Compile index 4fb1079..43dd5c8 100755 --- a/metatool/Compile +++ b/metatool/Compile @@ -1,5 +1,4 @@ #! /bin/bash APP=meta_tool -/usr/bin/dart compile exe bin/$APP.dart -o ../tools/$APP - - +OUT=$(dirname $(pwd))/tools +/usr/bin/dart compile exe bin/$APP.dart -o $OUT/$APP diff --git a/metatool/bin/page_generator.dart b/metatool/bin/page_generator.dart index 982d8c9..519d72d 100644 --- a/metatool/bin/page_generator.dart +++ b/metatool/bin/page_generator.dart @@ -1068,7 +1068,7 @@ StatefulWidget? customPageByRoute(String route) { break; } var rc = replaceVariables(templateRecordCustom, page) - .replaceFirst('#REQ_RECORD', requestRecord) + .replaceFirst('#REQ_RECORD', replaceVariables(requestRecord, page)) .replaceFirst('#DIDCHANGE', didChangeDependencies) .replaceFirst('#DEF_CONTROLLER', buildDefinitionControllers(page)) .replaceFirst('#INIT_COMBO', buildInitializeComboBoxes(page)) diff --git a/metatool/rest_server/data/sql/roles.sql.yaml b/metatool/rest_server/data/sql/roles.sql.yaml deleted file mode 100644 index 3f68681..0000000 --- a/metatool/rest_server/data/sql/roles.sql.yaml +++ /dev/null @@ -1,32 +0,0 @@ ---- -# DO NOT CHANGE. This file is created by the meta_tool -# SQL statements of the module "Roles": - -module: Roles -list: - type: list - parameters: [] - sql: "SELECT - t0.* - FROM Roles t0 - - ;" -byId: - type: record - parameters: [ "id" ] - sql: "SELECT * FROM Roles WHERE role_id=:id;" -delete: - type: delete - parameters: [ "id" ] - sql: "DELETE * FROM Roles WHERE role_id=:id;" -update: - type: update - parameters: [":id",":name",":changedBy"] - sql: "UPDATE Roles SET - role_id=:id,role_name=:name,role_changedby=:changedBy,role_changed=NOW() - WHERE role_id=:id;" -insert: - type: insert - parameters: [":id",":name",":createdBy"] - sql: "INSERT INTO Roles(role_id,role_name,role_createdby,role_created) - VALUES(:id,:name,:createdBy,NOW());" diff --git a/metatool/rest_server/data/sql/users.sql.yaml b/metatool/rest_server/data/sql/users.sql.yaml deleted file mode 100644 index 85a06af..0000000 --- a/metatool/rest_server/data/sql/users.sql.yaml +++ /dev/null @@ -1,34 +0,0 @@ ---- -# DO NOT CHANGE. This file is created by the meta_tool -# SQL statements of the module "Users": - -module: Users -list: - type: list - parameters: [] - sql: "SELECT - t0.*,t1.role_name AS role - FROM Users t0 - JOIN roles t1 ON t1.role_id=t0.user_role - ;" -byId: - type: record - parameters: [ "id" ] - sql: "SELECT * FROM Users WHERE user_id=:id;" -delete: - type: delete - parameters: [ "id" ] - sql: "DELETE * FROM Users WHERE user_id=:id;" -update: - type: update - parameters: [":id",":name",":displayName",":email",":role",":changedBy"] - sql: "UPDATE Users SET - user_id=:id,user_name=:name,user_displayname=:displayName,user_email=:email, - user_role=:role,user_changedby=:changedBy,user_changed=NOW() - WHERE user_id=:id;" -insert: - type: insert - parameters: [":id",":name",":displayName",":email",":role",":createdBy"] - sql: "INSERT INTO Users(user_id,user_name,user_displayname,user_email, - user_role,user_createdby,user_created) - VALUES(:id,:name,:displayName,:email,:role,:createdBy,NOW());" diff --git a/metatool/test/helper_test.dart b/metatool/test/helper_test.dart deleted file mode 100644 index df176d6..0000000 --- a/metatool/test/helper_test.dart +++ /dev/null @@ -1,250 +0,0 @@ -import 'package:dart_bones/dart_bones.dart'; -import 'package:test/test.dart'; -//import 'package:path/path.dart'; - -import '../lib/base/defines.dart'; -import '../lib/base/helper.dart'; -import '../lib/base/i18n.dart'; - -final i18n = I18N(); - -void main() { - final logger = MemoryLogger(LEVEL_FINE); - I18N.internal(logger); - FileSync.initialize(logger); - //final fileSync = FileSync(); - //final baseDir = init(logger); - //final targetDir = join(baseDir, nodeTarget); - //fileSync.ensureDirectory(targetDir); - group('secondsAsTime', () { - test('days', () { - expect(secondsAsTime(3 * 86400 + 5 * 3600 + 14 * 60 + 32), '3:05:14:32'); - }); - test('hours', () { - expect(secondsAsTime(23 * 3600 + 9 * 60 + 4), '23:09:04'); - }); - test('minutes', () { - expect(secondsAsTime(3 * 60 + 19), '03:19'); - }); - test('seconds', () { - expect(secondsAsTime(59), '59'); - }); - test('days-millisecnds', () { - expect( - secondsAsTime((3 * 86400 + 5 * 3600 + 14 * 60 + 32) * 1000 + 49, - isMilliSeconds: true), - '3:05:14:32.049'); - }); - }); - group('jsonToObject', () { - test('bool', () { - expect(jsonToObject('T', dataType: DataType.bool, defaultValue: false), - isTrue); - expect(jsonToObject('F', dataType: DataType.bool, defaultValue: true), - isFalse); - expect(jsonToObject('x', dataType: DataType.bool, defaultValue: true), - isTrue); - expect(jsonToObject('y', dataType: DataType.bool, defaultValue: false), - isFalse); - }); - test('datetime', () { - expect( - jsonToObject('2021-8-3 2:4', - dataType: DataType.datetime, defaultValue: false), - DateTime(2021, 8, 3, 2, 4)); - }); - test('date', () { - expect( - jsonToObject('2021-10-3', - dataType: DataType.date, defaultValue: false), - DateTime(2021, 10, 3)); - }); - test('int-nat-reference', () { - expect(jsonToObject(332211, dataType: DataType.nat), 332211); - expect(jsonToObject('332209', dataType: DataType.int), 332209); - expect(jsonToObject('220944', dataType: DataType.reference), 220944); - expect(jsonToObject(2209443, dataType: DataType.reference), 2209443); - expect(jsonToObject('xy', dataType: DataType.reference), isNull); - }); - }); - group('fromString', () { - test('bool', () { - expect(fromString('T', dataType: DataType.bool, defaultValue: false), - isTrue); - expect(fromString('F', dataType: DataType.bool, defaultValue: true), - isFalse); - expect( - fromString(i18n.tr('Yes'), - dataType: DataType.bool, defaultValue: false), - isTrue); - expect( - fromString(i18n.tr('No'), - dataType: DataType.bool, defaultValue: true), - isFalse); - expect(fromString('', dataType: DataType.bool, defaultValue: false), - isFalse); - expect( - fromString('', dataType: DataType.bool, defaultValue: true), isTrue); - }); - test('int', () { - expect(fromString('123', dataType: DataType.int, defaultValue: -1), 123); - expect( - fromString('-1234', dataType: DataType.int, defaultValue: -1), -1234); - expect(fromString('', dataType: DataType.int, defaultValue: -1), -1); - expect(fromString('a15', dataType: DataType.int, defaultValue: -1), -1); - }); - test('nat', () { - expect(fromString('123', dataType: DataType.nat, defaultValue: -1), 123); - expect(fromString('-1234', dataType: DataType.nat, defaultValue: -1), -1); - expect(fromString('', dataType: DataType.nat, defaultValue: -1), -1); - expect(fromString('a15', dataType: DataType.nat, defaultValue: -1), -1); - }); - test('reference', () { - expect(fromString('123', dataType: DataType.reference, defaultValue: -1), - 123); - expect( - fromString('-1234', dataType: DataType.reference, defaultValue: -1), - -1234); - expect( - fromString('', dataType: DataType.reference, defaultValue: -1), -1); - expect(fromString('a15', dataType: DataType.reference, defaultValue: -1), - -1); - }); - test('float', () { - expect(fromString('123.76', dataType: DataType.float, defaultValue: -1), - 123.76); - expect(fromString('-4123.76', dataType: DataType.float, defaultValue: -1), - -4123.76); - expect(fromString('', dataType: DataType.float, defaultValue: -99999999), - -99999999); - expect( - fromString('Nothing', - dataType: DataType.float, defaultValue: -99999999), - -99999999); - }); - test('currency', () { - expect( - fromString('123.76', dataType: DataType.currency, defaultValue: -1), - 123.76); - expect( - fromString('-4123.76', dataType: DataType.currency, defaultValue: -1), - -4123.76); - expect( - fromString('', dataType: DataType.currency, defaultValue: -99999999), - -99999999); - expect( - fromString('Nothing', - dataType: DataType.currency, defaultValue: -99999999), - -99999999); - }); - test('date', () { - expect(fromString('7.3.1987', dataType: DataType.date), - DateTime(1987, 3, 7)); - expect(fromString('17.12.2035', dataType: DataType.date), - DateTime(2035, 12, 17)); - expect(fromString('2012.6.2', dataType: DataType.date), - DateTime(2012, 6, 2)); - expect(fromString('1923.10.31', dataType: DataType.date), - DateTime(1923, 10, 31)); - expect(fromString('17.12.21', dataType: DataType.date), isNull); - }); - test('datetime', () { - expect(fromString('17.12.2035', dataType: DataType.datetime), - DateTime(2035, 12, 17)); - expect(fromString('7.3.1987', dataType: DataType.datetime), - DateTime(1987, 3, 7)); - expect(fromString('2012.6.2', dataType: DataType.datetime), - DateTime(2012, 6, 2)); - expect(fromString('1923.10.31', dataType: DataType.datetime), - DateTime(1923, 10, 31)); - expect(fromString('17.12.21', dataType: DataType.datetime), isNull); - expect(fromString('7.3.1987T2:44', dataType: DataType.datetime), - DateTime(1987, 3, 7, 2, 44)); - expect(fromString('17.12.2035 13:59:22', dataType: DataType.datetime), - DateTime(2035, 12, 17, 13, 59, 22)); - expect(fromString('2012.6.2/23:59:59', dataType: DataType.datetime), - DateTime(2012, 6, 2, 23, 59, 59)); - expect(fromString('1923.10.31-3:4', dataType: DataType.datetime), - DateTime(1923, 10, 31, 3, 4)); - }); - }); - group('asPattern', () { - test('unchanged', () { - expect(asPattern('A test!123'), 'A test!123%'); - }); - test('with *', () { - expect(asPattern('*Wu*ff'), '%Wu%ff%'); - }); - test('empty', () { - expect(asPattern(''), '%'); - }); - test('with ?', () { - expect(asPattern('M??r'), 'M__r%'); - }); - test('mixed', () { - expect(asPattern('*M?i*r'), '%M_i%r%'); - }); - }); - group('asString', () { - test('bool', () { - expect(asString(true), i18n.tr('Yes')); - expect(asString(false), i18n.tr('No')); - expect(asString(true, dbFormat: true), 'T'); - expect(asString(false, dbFormat: true), 'F'); - }); - test('int', () { - expect(asString(12345), '12345'); - expect(asString(-33), '-33'); - expect(asString(-33, dbFormat: true), '-33'); - expect(asString(884433, dbFormat: true), '884433'); - }); - test('double', () { - expect(asString(7733.0), '7733.00'); - expect(asString(-123.77), '-123.77'); - expect(asString(1E-99), '.00'); - expect(asString(7733.0, dbFormat: true), '7733.00'); - expect(asString(-123.77, dbFormat: true), '-123.77'); - }); - test('Date', () { - expect(asString(DateTime(2021, 10, 3), dateOnly: true), '03.10.2021'); - expect( - asString(DateTime(2021, 10, 3, 9, 33), dateOnly: true), '03.10.2021'); - expect(asString(DateTime(2021, 10, 3, 9, 33), dateOnly: false), - '03.10.2021 09:33'); - expect(asString(DateTime(2021, 10, 3, 9, 33, 14), dateOnly: false), - '03.10.2021 09:33'); - expect( - asString(DateTime(2021, 10, 3, 9, 33, 14), - dateOnly: false, withSeconds: true), - '03.10.2021 09:33:14'); - expect(asString(DateTime(2021, 7, 3), dbFormat: true, dateOnly: true), - '2021-07-03'); - expect( - asString(DateTime(2021, 10, 3, 9, 33), - dbFormat: true, dateOnly: true), - '2021-10-03'); - expect( - asString(DateTime(2021, 7, 3, 9, 33), - dbFormat: true, dateOnly: false), - '2021-07-03 09:33:00'); - expect( - asString(DateTime(2021, 10, 3, 9, 33, 14), - dbFormat: true, dateOnly: false), - '2021-10-03 09:33:14'); - expect( - asString(DateTime(2021, 10, 3, 9, 33, 14), - dbFormat: true, dateOnly: false, withSeconds: true), - '2021-10-03 09:33:14'); - }); - test('string', () { - expect(asString('A test!123'), 'A test!123'); - expect(asString('A test!123', dbFormat: true), 'A test!123'); - }); - test('string', () { - expect(asString('A test!123'), 'A test!123'); - }); - test('string', () { - expect(asString('A test!123'), 'A test!123'); - }); - }); -} diff --git a/metatool/test/validators_test.dart b/metatool/test/validators_test.dart deleted file mode 100644 index fa5c35e..0000000 --- a/metatool/test/validators_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:dart_bones/dart_bones.dart'; -import 'package:test/test.dart'; - -import '../lib/base/validators.dart' as validators; -import '../lib/base/i18n.dart'; - -final i18n = I18N(); - -void main() { - final logger = MemoryLogger(LEVEL_FINE); - I18N.internal(logger); - FileSync.initialize(logger); - group('isEmail', () { - test('standard', () { - expect(validators.isEmail('abc@example.com'), isNull); - expect(validators.isEmail(null), isNull); - }); - test('wrong char', () { - expect(validators.isEmail('/abc@example.com'), 'Illegal character "/" in email address'); - }); - test('wrong syntax', () { - expect(validators.isEmail('abc@example'), 'Not an email address: abc@example'); - }); - }); - group('isInt', () { - test('OK', () { - expect(validators.isInt('123456'), isNull); - expect(validators.isInt('-123456'), isNull); - expect(validators.isInt(null), isNull); - }); - test('errors', () { - expect(validators.isInt('x'), 'Not an integer: x'); - expect(validators.isInt('123.77'), 'Not an integer: 123.77'); - }); - }); - group('isNat', () { - test('OK', () { - expect(validators.isNat('123456'), isNull); - expect(validators.isNat('0'), isNull); - expect(validators.isNat(null), isNull); - }); - test('errors', () { - expect(validators.isNat('-123456'), 'Not negative integer expected, not: -123456'); - expect(validators.isNat('x'), 'Not an integer: x'); - expect(validators.isNat('123.77'), 'Not an integer: 123.77'); - }); - }); - group('notEmpty', () { - test('OK', () { - expect(validators.notEmpty('Go'), isNull); - }); - test('error', () { - expect(validators.notEmpty(''), 'Please fill in.'); - expect(validators.notEmpty(null), 'Please fill in.'); - }); - }); - group('validateMultiple', () { - test('OK', () { - expect(validators.validateMultiple('abc@example.com', [(x) => validators.notEmpty(x), - (x) => validators.isEmail(x)]), isNull); - }); - test('Error', () { - expect(validators.validateMultiple('0x72z', [(x) => validators.notEmpty(x), - (x) => validators.isInt(x)]), 'Not an integer: 0x72z'); - }); - }); -} diff --git a/tools/InitProject b/tools/InitProject index 4ff2bfa..5fbfaa3 100755 --- a/tools/InitProject +++ b/tools/InitProject @@ -11,9 +11,11 @@ function Usage(){ echo "+++ $*" } function MkDirs(){ - for dir in tools rest_server/data; do - mkdir -p $dir - done + cd $APP + for dir in tools rest_server/data; do + test -d $dir || mkdir -p $dir + done + cd .. } function EnsureDir(){ local dir=$1 @@ -22,12 +24,13 @@ function EnsureDir(){ mkdir -p $dir fi } +# Copy many files from exhibition. function CopyFiles(){ + cd $APP local projDir=$(pwd) cd ../exhibition local srcDir=$(pwd) - for file in lib/base/*.dart \ - lib/meta/module_meta_data.dart \ + for file in lib/meta/module_meta_data.dart \ lib/meta/modules.dart \ rest_server/pubspec.yaml \ tools/PackRestServer \ @@ -36,62 +39,68 @@ function CopyFiles(){ if [ -z "$DO_UPDATE" -o ! -e $file ]; then local dir=$(dirname $file) EnsureDir $dir - echo "creating $file" - cp -a ../exhibition/$file $file + #echo "creating $file" + cp -av $srcDir/$file $file fi cd $srcDir done cd $projDir + cd .. } -function CopyFile(){ +# Copy one file. +function CopyAndReplaceOne(){ local projDir=$1 local file=$2 local srcDir=$3 cd $projDir local dir=$(dirname $file) EnsureDir $dir - local file2=${file/exhibition/$APP} - echo "copy and replace $file -> $(basename $file2)" - sed <../exhibition/$file >$file2 -e "s/exhibition/$APP/g" -e "s/Exhibition/$APP2/g" - chmod --reference=../exhibition/$file $file2 + local fileTrg=${file/exhibition/$APP} + echo "copy and replace $file -> $(basename $fileTrg)" + sed <../exhibition/$file >$fileTrg -e "s/exhibition/$APP/g" -e "s/Exhibition/$APP2/g" + chmod --reference=../exhibition/$file $fileTrg cd $srcDir } +# Copy many files and replaces variables in the file content. function CopyAndReplace(){ + cd $APP local projDir=$(pwd) cd ../exhibition local srcDir=$(pwd) local filesNewOnly=$(echo pubspec.yaml \ + lib/base/*.dart \ + lib/common/*.dart \ + lib/meta/*_meta.dart \ lib/persistence/*.dart \ lib/page/*.dart \ - lib/main.dart \ - lib/meta/*_meta.dart \ - bin/*.dart \ + lib/page/benchmarks/*.dart \ + lib/page/roles/*.dart \ + lib/page/rolestarter/*.dart \ + lib/page/starters/*.dart \ + lib/page/structures/*.dart \ + lib/page/users/*.dart \ + lib/services/*.dart \ + lib/setting/*.dart \ + lib/widget/*.dart \ + lib/*.dart ) local filesAlways=$(echo rest_server/lib/*.dart \ rest_server/bin/*.dart \ rest_server/tools/project.inc \ rest_server/CR ) - - if [ -z "$DO_UPDATE" ]; then - for file in lib/setting/*.dart \ - pubspec.yaml \ - lib/persistence/*.dart \ - lib/page/*.dart \ - rest_server/lib/*.dart rest_server/bin/*.dart rest_server/tools/project.inc \ - rest_server/CR \ - lib/main.dart \ - lib/meta/*_meta.dart \ - bin/*.dart \ - ; do - CopyFile $projDir $file $srcDir - done - else - fi + local files=$filesAlways + test -z "$DO_UPDATE" && files="$files $filesNewOnly" + for file in $files; do + CopyAndReplaceOne $projDir $file $srcDir + done cd $projDir + cd .. } +# Creates symbolic links to the exhibition directory. function SymbolicLinks(){ + cd $APP for links in ReCreateMetaTool:. Meta:. dart_tools:. \ ; do local src=../exhibition/${links%:*} @@ -104,59 +113,92 @@ function SymbolicLinks(){ ln -s $src $trg2 fi done - for links in dart_tools/tools/i18n_text_parser:tools \ + for link in dart_tools/tools/i18n_text_parser:tools \ dart_tools/tools/yaml_merger:tools \ ; do - local src=../../exhibition/${links%:*} - local trg=${links#*:} - local trg2=$trg - test $trg = . && trg2=$(basename $src) - echo "trg: $trg2" + local src=../../exhibition/${link%:*} + local trg=${link#*:} + local trg2=$trg/$(basename $src) + #echo "trg: $trg2" if [ ! -L $trg2 ]; then - echo "linking $src -> $trg2" - ln -s $src $trg2 + #echo "linking $src -> $trg2" + ln -sv $src $trg2 fi done + cd .. } +# Executes scripts in exhibition/tools function PrepareTools(){ local tool - local curDir=$(pwd) - echo "PrepareTools: pwd=$curDir" - for tool in i18n_text_parser:CompileI18n \ - yaml_merger:CompileMerge; do - local exe=${tool%:*} - local script=${tool#*:} - if [ ! -e ../exhibition/dart_tools/tools/$exe ]; then - cd ../exhibition/dart_tools - echo "executing $script" - tools/$script - fi - cd $curDir - done + if [ ! -d exhibition ]; then + echo "+++ wrong current directory: missing exhibition" + else + local baseDir=$( pwd) + cd exhibition/dart_tools + local curDir=$( pwd) + for tool in i18n_text_parser:CompileI18n \ + yaml_merger:CompileMerge; do + local exe=${tool%:*} + local script=${tool#*:} + if [ -e tools/$exe ]; then + echo "already exists: $exe" + else + echo "executing $script" + tools/$script + fi + cd $curDir + done + cd $baseDir + fi +} +# Copies and links files of the metatool directory. +function CreateMetaData(){ + cd $APP + mkdir -p metatool/lib/base metatool/lib/meta + cd metatool/lib/base + ln -sv ../../../../exhibition/metatool/lib/base/* . + rm -f application_name.dart + cat <application_name.dart +const theApplicationName = '$APP'; +const theVariantName = '$APP'; +EOS + cd ../.. + ln -vs ../../exhibition/metatool/bin . + cp -av ../../exhibition/metatool/lib/meta/* lib/meta + ln -vs ../../exhibition/metatool/Compile . + ln -vs ../../exhibition/metatool/pubspec.yaml . + cp -av ../../exhibition/metatool/local.properties . + cp -av ../../exhibition/metatool/metatool.iml . + cd ../.. } +# Initializes the base directory with flutter function Flutter(){ local app=$1 flutter create $app cd $app flutter config linux + cd .. } function Finish(){ + cd $APP dart pub upgrade + cd .. } if [ -z "$APP" ]; then Usage "missing PROJECT" -elif [ -n $DO_UPDATE -a $DO_UPDATE != '--update' ]; then +elif [ -n "$DO_UPDATE" -a "$DO_UPDATE" != '--update' ]; then Usage "Unknown option: $DO_UPDATE" -elif [ -d $APP ]; then +elif [ -n "$DO_UPDATE" -a -d $APP ]; then Usage "PROJECT already exists." elif [ ! -d exhibition/dart_tools ]; then Usage "wrong current directory: Please go into the base folder of the project." else - test -n "$DO_UPDATE" && Flutter $APP + test -z "$DO_UPDATE" && Flutter $APP PrepareTools MkDirs CopyFiles CopyAndReplace SymbolicLinks + CreateMetaData Finish fi diff --git a/tools/PackRestServer b/tools/PackRestServer index 3fc61f4..28592e5 100755 --- a/tools/PackRestServer +++ b/tools/PackRestServer @@ -19,11 +19,12 @@ function DoIt(){ cat <$BASE_DIR/INSTALL.TXT # ------------ # Installation: -./InstallRestServer +cd /tmp +sudo ./InstallRestServer # or manually: DIR=\$(pwd) mkdir -p /usr/share/$PROJECT && cd /usr/share/$PROJECT -tar xzf \DIR/$TAR_NODE +tar xzf \$DIR/$TAR_NODE # ./$EXE install ./$EXE install /usr/share/$PROJECT/$EXE $PROJECT # see /usr/share/$PROJECT and /etc/$PROJECT -- 2.39.5