Exhibition-Workflow: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
K (→Workflow) |
|||
(5 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 52: | Zeile 52: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
= | = Important Locations = | ||
* | * Application menu page: lib/setting/drawer_xxx.dart: Definition route + Icon | ||
* | * Starting route: lib/page/start_page.dart: globalData.navigate(context, '/Users/list'); | ||
= Typical Adaptions = | |||
* all *_custom.dart: | |||
** buildFrame(): formular elements (widgets) | |||
** build(): "rows = attendedPage.getRows(...)": column list, column adaptions (onColumnOfRecord) | |||
** requestRecords(): parameters of the database query | |||
* list_user_custom.dart: | |||
** buildFrame(): table headers | |||
= Handling of a Combobox = | |||
* all *_custom.dart: | |||
<pre> | |||
buildFrame(){ | |||
... | |||
comboRolesFromBackend(attendedPage: attendedPage, onDone: () => setState(() => 1)); | |||
final itemsRoles = | |||
comboRoles(i18n.trDyn(GlobalTranslations.comboboxSelect), attendedPage); | |||
... | |||
FormItem( | |||
DropdownButtonFormField<int>( | |||
value: itemsRoles == null || itemsRoles.length == 1 ? 0 : _fieldData.role, | |||
items: itemsRoles, | |||
isExpanded: true, | |||
decoration: InputDecoration(labelText: i18n.tr('Role')), | |||
onChanged: (value) => _fieldData.role = value ?? 0, | |||
), | |||
weight: 6), | |||
... | |||
} | |||
class _FieldData { | |||
... | |||
int role; | |||
... | |||
} | |||
</pre> | |||
= I18N = | |||
== Coding == | |||
<pre> | |||
// in each source file using I18N: | |||
final i18n = I18N(); | |||
... | |||
// Usage in any expression: | |||
// Simple without parameters: | |||
final msg = i18n.tr('Please wait'); | |||
// Singular/plural case: | |||
final msg = i18n.ntr('Hi user', 'Hi users', countUsers); | |||
// Dynamic key (not a string constant): | |||
comboUsers(i18n.trDyn(GlobalTranslations.comboboxSelect), ...); | |||
// String with placeholder(s): | |||
rc = i18n.trArgs('Not a Date: {0}', '!global', [input]); | |||
</pre> | |||
== Workflow == | |||
=== For the First Time === | |||
<pre> | |||
cd $BASE_PROJECT | |||
mkdir -p i18n | |||
tools/i18n_text_parser parse lib i18n | |||
vi i18n/project.i18n.yaml | |||
# Adapt the data in the yaml file | |||
# Than run again: | |||
tools/i18n_text_parser parse lib i18n | |||
tools/i18n_text_parser msg-init i18n '!globals' de_DE | |||
</pre> | |||
* In the directory i18n will be created some *.pot files (one for each module) | |||
* Translate them with babel | |||
= Android Configuration = | |||
* android/app/src/debug/AndroidManifest.xml + android/app/src/profile/AndroidManifest.xml: | |||
<pre> | |||
<uses-permission android:name="android.permission.INTERNET" /> | |||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | |||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> | |||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | |||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | |||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> | |||
</manifest> | |||
</pre> | |||
* android/app/src/main/AndroidManifest.xml: | |||
<pre> | |||
... | |||
package="de.hamatoma.exhibition"> | |||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | |||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | |||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> | |||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | |||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> | |||
<uses-permission android:name="android.permission.INTERNET" /> | |||
<uses-permission android:name="android.permission.CAMERA" /> | |||
<application> | |||
... | |||
</pre> | |||
* android/app/build.gradle | |||
<pre> | |||
defaultConfig { | |||
... | |||
multiDexEnabled true | |||
} | |||
... | |||
</pre> | |||
=== After the First Time === | |||
<pre> | |||
tools/i18n_text_parser parse lib i18n | |||
</pre> |
Aktuelle Version vom 4. Februar 2022, 21:14 Uhr
Links[Bearbeiten]
Workflow[Bearbeiten]
We use the module "Users" as example
- Create a metadata description: lib/meta/users_meta.dart
import 'module_meta_data.dart';
class UserMeta extends ModuleMetaData {
static UserMeta instance = UserMeta.internal();
UserMeta.internal() : super('Users',
[
PropertyMetaData('id', DataType.reference, ':primary:', 'combo'),
PropertyMetaData('name', DataType.string, ':notnull:', '', size: 64),
PropertyMetaData('displayName', DataType.string, ':unique:notnull:', '', size: 32),
PropertyMetaData('email', DataType.string, ':unique:notnull:', '', size: 255),
PropertyMetaData('role', DataType.reference, ':notnull:', ''),
PropertyMetaData('created', DataType.datetime, '', ''),
PropertyMetaData('createdBy', DataType.string, '', '', size: 32),
PropertyMetaData('changed', DataType.datetime, '', ''),
PropertyMetaData('changedBy', DataType.string, '', '', size: 32),
],
tableName: 'loginusers',
);
factory UserMeta(){
return instance;
}
}
- Create some source files: (for example: the module "Users")
# precondition: the current directory is the base folder of the dev-app.
mkdir -p lib/meta/users
# The following call works without meta data. It works without recreation of the tool:
./Meta show-modules Users >lib/meta/modules.dart
# Now we need a new instance of the meta_tool (to realize the meta data changes):
./ReCreateMetaTool
./Meta show-data >lib/page/users/user_data.dar
# Show the SQL definition:
./Meta show-table Users
- Create all source files:
# precondition: the current directory is the base folder of the dev-app.
# The following call works without meta data. It works without recreation of the tool:
./Meta update-modules-names
# Now we need a new instance of the ./Meta (to realize the meta data changes):
./ReCreateMetaTool
./Meta update-modules-files
./Meta update-sql
Important Locations[Bearbeiten]
- Application menu page: lib/setting/drawer_xxx.dart: Definition route + Icon
- Starting route: lib/page/start_page.dart: globalData.navigate(context, '/Users/list');
Typical Adaptions[Bearbeiten]
- all *_custom.dart:
- buildFrame(): formular elements (widgets)
- build(): "rows = attendedPage.getRows(...)": column list, column adaptions (onColumnOfRecord)
- requestRecords(): parameters of the database query
- list_user_custom.dart:
- buildFrame(): table headers
Handling of a Combobox[Bearbeiten]
- all *_custom.dart:
buildFrame(){ ... comboRolesFromBackend(attendedPage: attendedPage, onDone: () => setState(() => 1)); final itemsRoles = comboRoles(i18n.trDyn(GlobalTranslations.comboboxSelect), attendedPage); ... FormItem( DropdownButtonFormField<int>( value: itemsRoles == null || itemsRoles.length == 1 ? 0 : _fieldData.role, items: itemsRoles, isExpanded: true, decoration: InputDecoration(labelText: i18n.tr('Role')), onChanged: (value) => _fieldData.role = value ?? 0, ), weight: 6), ... } class _FieldData { ... int role; ... }
I18N[Bearbeiten]
Coding[Bearbeiten]
// in each source file using I18N: final i18n = I18N(); ... // Usage in any expression: // Simple without parameters: final msg = i18n.tr('Please wait'); // Singular/plural case: final msg = i18n.ntr('Hi user', 'Hi users', countUsers); // Dynamic key (not a string constant): comboUsers(i18n.trDyn(GlobalTranslations.comboboxSelect), ...); // String with placeholder(s): rc = i18n.trArgs('Not a Date: {0}', '!global', [input]);
Workflow[Bearbeiten]
For the First Time[Bearbeiten]
cd $BASE_PROJECT mkdir -p i18n tools/i18n_text_parser parse lib i18n vi i18n/project.i18n.yaml # Adapt the data in the yaml file # Than run again: tools/i18n_text_parser parse lib i18n tools/i18n_text_parser msg-init i18n '!globals' de_DE
- In the directory i18n will be created some *.pot files (one for each module)
- Translate them with babel
Android Configuration[Bearbeiten]
- android/app/src/debug/AndroidManifest.xml + android/app/src/profile/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> </manifest>
- android/app/src/main/AndroidManifest.xml:
... package="de.hamatoma.exhibition"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <application> ...
- android/app/build.gradle
defaultConfig { ... multiDexEnabled true } ...
After the First Time[Bearbeiten]
tools/i18n_text_parser parse lib i18n