{"id":50677006,"url":"https://github.com/jankstar/tryton_flutter_client","last_synced_at":"2026-06-08T16:04:47.965Z","repository":{"id":362125954,"uuid":"1257478614","full_name":"jankstar/tryton_flutter_client","owner":"jankstar","description":"flutter client for tryton ERP 8.0","archived":false,"fork":false,"pushed_at":"2026-06-02T18:53:13.000Z","size":293,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-02T20:24:04.739Z","etag":null,"topics":["client","flutter","tryton","tryton-erp"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jankstar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":"COPYRIGHT","agents":null,"dco":null,"cla":null}},"created_at":"2026-06-02T18:06:05.000Z","updated_at":"2026-06-02T18:53:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jankstar/tryton_flutter_client","commit_stats":null,"previous_names":["jankstar/tryton_flutter_client"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/jankstar/tryton_flutter_client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jankstar%2Ftryton_flutter_client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jankstar%2Ftryton_flutter_client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jankstar%2Ftryton_flutter_client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jankstar%2Ftryton_flutter_client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jankstar","download_url":"https://codeload.github.com/jankstar/tryton_flutter_client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jankstar%2Ftryton_flutter_client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34069500,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client","flutter","tryton","tryton-erp"],"created_at":"2026-06-08T16:04:45.361Z","updated_at":"2026-06-08T16:04:47.951Z","avatar_url":"https://github.com/jankstar.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tryton_Flutter_Client\n\nA Flutter client for the [Tryton ERP system](https://www.tryton.org/), providing a native cross-platform interface that communicates with a Tryton server using the same JSON-RPC 2.0 protocol as the official [SAO web client](https://foss.heptapod.net/tryton/sao).\n\n## Features\n\n### Authentication \u0026 Session\n- Login with database selection, MFA support, and device cookie (\"stay logged in\")\n- Server URL and last-used database persisted across app restarts\n- Automatic session renewal on 401 — compact re-login dialog (username + password only), original request retried transparently\n- Persistent session: app reconnects on next start without requiring a full login\n- Server-side language applied after login (`reloadContext()`) — Tryton translates all field labels and selection values server-side\n\n### Shell \u0026 Multi-Tab Navigation\n- Tab-based AppShell: each menu action opens in its own tab with an independent Navigator stack (`IndexedStack`)\n- Toggleable sidebar (animated, 250 px) with the full Tryton menu tree\n- Tab close button (×); welcome screen shown when no tab is open\n- `tabsProvider` (Riverpod `StateNotifierProvider`) manages tab lifecycle with UUID-keyed `AppTab` entries\n\n### Menu \u0026 Navigation\n- Full Tryton menu tree loaded from the server with expand/collapse\n- SVG icons from `ir.ui.icon` with Material Design fallback for `LOCAL_ICONS`\n- Action domain filtering via PYSON evaluation (`ir.action.act_window.pyson_domain`)\n- User info chip (top right): name, currency, avatar initials, dropdown with Preferences / Help / Sign out\n\n### List Views (Tree)\n- Server-driven columns from `fields_view_get` with correct order and labels\n- Hierarchical tree views with lazy expand/collapse (`field_childs`)\n  - Primary source: `field_childs` attribute from `fields_view_get`\n  - Fallback: direct query of `ir.ui.view` ordered by priority — picks the first tree view that sets `field_childs`\n  - Auto-detection of self-referential models when `field_childs` is not configured\n- Explicit search button (no request on every keystroke — like SAO)\n- SAO-style toolbar: Switch (⇄), New, Reload, Duplicate, Delete, Attachment, Action, Relate, Print, Email, Close\n- Buttons enabled only when a record is selected (except Reload, New, Close)\n- Record navigation context for Prev/Next in form view\n- Many2One name resolution with session-level batch cache (`listEquals` comparison to prevent redundant reloads)\n\n### Form Views\n- Server-driven layout from XML arch (`fields_view_get`): grid, groups, notebooks, tabs\n- PYSON states evaluation for `invisible`, `readonly`, `required` per field and per notebook page\n- Required fields shown with red asterisk `*`\n- SAO-style toolbar: Prev/Next record, New, Save, Reload, Duplicate, Delete, View Logs, Attachment (badge), Note, Action, Relate, Print, Email, Close\n- Translated model name from `ir.model` shown in AppBar\n- Record position indicator (e.g. `3 / 47`)\n- Binary fields (e.g. avatar) excluded from `read()` to avoid non-JSON responses\n- **Responsive layout**: form width scales proportionally with the window (horizontal padding = 3 % of width, clamped 12–40 px); no fixed maximum width\n- **Minimum field width** (160 px): grid columns wrap to the next line rather than shrinking below this threshold\n- **Sticky footer**: root-level form buttons (from `\u003cbutton\u003e` elements at form root) rendered in a permanently visible footer below the scroll area — PYSON `invisible`/`readonly` states evaluated per button\n\n### Field Types\n- `char`, `text`, `integer`, `float`, `numeric` — text input; `on_change` RPC triggered on focus loss only (not on every keystroke, like SAO)\n- `selection` — dropdown; static list (`[[key, label], ...]`) or method-based (classmethod name as string); method-based options pre-loaded during form initialisation (`getSelectionOptions`); `on_change` triggered immediately\n- `date`, `datetime` — date/time pickers\n- `boolean` — checkbox\n- `many2one` — autocomplete search, **open-in-form button** (uses local tab Navigator, not GoRouter), clear button, async `rec_name` loading\n- `one2many`, `many2many` — inline embedded tree with Add, Switch, Undelete, Delete; strikethrough for pending deletions (committed on parent save)\n\n### Performance\n- `on_change` RPC only on field blur (focus loss), not on every keystroke\n- `listEquals` for collection parameters in `didUpdateWidget` — prevents spurious reloads\n- Session-level caches: Many2One names, model display names, icons, currency symbols\n- Binary fields skipped in `read()` to avoid non-JSON server responses\n- Selection options pre-loaded with `Future.wait` in parallel during form load\n\n### Internationalisation\n- 11 languages: English, German, French, Spanish, Portuguese, Polish, Danish, Dutch, Swedish, Finnish, Russian\n- Language selector on the login screen; persisted via `shared_preferences`\n- All UI strings via Flutter `AppLocalizations` (ARB files in `lib/l10n/`)\n- Server-side translations activated by sending the selected language in the RPC context\n\n## Platforms\n\nTargets all Flutter platforms. Tested on **macOS**. iOS, Android, Web, Linux, and Windows are also configured.\n\n## Architecture\n\nClean Architecture in three layers:\n\n```\nlib/\n├── core/\n│   ├── icons/          # SVG icon cache + TrytonIcon widget\n│   ├── l10n/           # LocaleProvider, BuildContext.l10n extension\n│   ├── pyson/          # PYSON expression evaluator (Eval, Not, Bool, Equal, In, …)\n│   ├── rpc/            # JSON-RPC 2.0 client (dio), ReAuthService, exception types\n│   ├── serialization/  # Tryton ↔ Dart type conversion (DateTime, Decimal, Bytes)\n│   ├── session/        # Session management, device cookie, persistence\n│   ├── theme/          # AppTheme, ThemeProvider (light/dark)\n│   └── xml/            # fields_view_get parsing, form/tree XML parser\n├── features/\n│   ├── actions/        # Action executor (act_window, report, wizard)\n│   ├── auth/           # Login, re-login dialog, session provider, user preferences\n│   ├── model/          # ModelService CRUD, FieldDefinition, TrytonRecord, TrytonToolbar\n│   ├── shell/          # AppShell (tab bar + sidebar), TabManager (tabsProvider)\n│   ├── tabs/           # ModelBrowserSidebar, UserChip\n│   └── views/          # DynamicFormScreen, ListViewScreen, EmbeddedTreeWidget,\n│                       # NavigationContext (Prev/Next)\n├── l10n/               # ARB localisation files (11 languages)\n└── shared/\n    ├── utils/          # m2o_name_cache, symbol_cache, number_format_utils\n    └── widgets/        # FieldWidget, ToolbarDropdownButton\n```\n\n### Key providers (Riverpod)\n\n| Provider | Type | Purpose |\n|----------|------|---------|\n| `rpcClientProvider` | `Provider` | JSON-RPC 2.0 HTTP client |\n| `sessionProvider` | `Provider` | Active Tryton session (database, user, context) |\n| `modelServiceProvider` | `Provider` | CRUD + RPC calls (fieldsGet, read, write, …) |\n| `authProvider` | `StateNotifierProvider` | Login / logout / re-auth state |\n| `localeProvider` | `StateProvider` | Selected UI locale |\n| `navContextProvider` | `StateProvider` | Prev/Next record navigation state |\n| `userPreferencesProvider` | `FutureProvider` | Server-side user preferences |\n| `tabsProvider` | `StateNotifierProvider` | Open tabs, active tab index |\n\n**Navigation:** GoRouter handles top-level routes (`/login`, `/models`). Within each tab, a dedicated `Navigator` (`AppTab.navigatorKey`) handles sub-screens (`ListViewScreen` → `DynamicFormScreen`) so that each tab keeps an independent history stack.\n\n**HTTP:** dio + CookieJar  \n**SVG rendering:** flutter_svg  \n**Localisation:** flutter_localizations + gen_l10n\n\n## Protocol\n\nCommunicates with the Tryton server via JSON-RPC 2.0:\n\n```\nPOST /{database}/rpc/\n{ \"id\": 1, \"method\": \"model.party.party.search_read\", \"params\": [..., context] }\n```\n\nSpecial Tryton types handled by `TrytonSerializer`:\n\n| Tryton type | JSON encoding |\n|-------------|---------------|\n| `datetime`  | `{\"__class__\": \"datetime\", \"year\": ..., ...}` |\n| `date`      | `{\"__class__\": \"date\", ...}` |\n| `Decimal`   | `{\"__class__\": \"Decimal\", \"decimal\": \"123.45\"}` |\n| `bytes`     | `{\"__class__\": \"bytes\", \"base64\": \"...\"}` |\n\nError types handled: `UserError`, `UserWarning`, `ConcurrencyException`, `LoginException`, 503 retry with backoff, 401 automatic re-authentication.\n\n### Session Authentication (like SAO)\n\n| Layer | Mechanism | Storage |\n|-------|-----------|---------|\n| HTTP session cookie | Short-lived, per-request | CookieJar |\n| Device cookie | Long-lived, passwordless login | `shared_preferences` |\n| Session data | `database`, `login`, `user_id` | `shared_preferences` |\n\nOn 401: `ReAuthService` pauses the failed request, shows a compact re-login dialog, and retries automatically after success — identical to SAO's `Session.renew`.\n\n## Getting Started\n\n### Prerequisites\n\n- Flutter SDK ≥ 3.19 (Dart SDK ≥ 3.12)\n- A running Tryton server (8.x)\n- macOS entitlement `com.apple.security.network.client` is already set\n\n### Install dependencies\n\n```bash\nflutter pub get\n```\n\n### Generate localisations\n\n```bash\nflutter gen-l10n\n```\n\n### Run on macOS\n\n```bash\nflutter run -d macos\n```\n\n### Run on other platforms\n\n```bash\nflutter run -d ios        # requires Xcode\nflutter run -d android    # requires Android SDK\nflutter run -d chrome     # web\n```\n\n### Build\n\n```bash\nflutter build macos\nflutter build apk\nflutter build ios\n```\n\n## Configuration\n\nOn first launch, enter the Tryton server URL (e.g. `http://localhost:8000`), select the database, and log in. Server URL and database are persisted and pre-filled on subsequent starts. Only username and password need to be re-entered.\n\n## Key Dependencies\n\n| Package | Purpose |\n|---------|---------|\n| `dio` + `dio_cookie_manager` | HTTP client with cookie-based session |\n| `flutter_riverpod` | State management |\n| `go_router` | Top-level declarative navigation |\n| `xml` | XML arch parsing |\n| `flutter_svg` | SVG icon rendering |\n| `shared_preferences` | Session and locale persistence |\n| `flutter_localizations` | 11-language UI |\n| `intl` | Date/number formatting |\n| `uuid` | Tab identity (UUID v4) |\n| `url_launcher` | Help link |\n\n## Tryton Compatibility\n\nTested with Tryton **8.x**. The protocol implementation follows the [SAO web client](https://foss.heptapod.net/tryton/sao) version **8.0.0** as reference.\n\n## License\n\nGPL-3.0 — same as Tryton. See [LICENSE](LICENSE) and [COPYRIGHT](COPYRIGHT).\n\n## Third-Party Fonts\n\n### Lato\n\n**Designer:** Łukasz Dziedzic / tyPoland  \n**Source:** [Google Fonts — Lato](https://fonts.google.com/specimen/Lato)  \n**License:** [SIL Open Font License 1.1](https://openfontlicense.org/)\n\n\u003e Copyright (c) 2010–2014 by tyPoland Lukasz Dziedzic (team@latofonts.com)\n\u003e with Reserved Font Name \"Lato\".\n\u003e\n\u003e This Font Software is licensed under the SIL Open Font License, Version 1.1.\n\u003e This license is available with a FAQ at https://openfontlicense.org/\n\nLato covers Latin, Latin Extended, and Cyrillic character sets, supporting all\n11 application languages: English, German, French, Spanish, Portuguese, Polish,\nDanish, Dutch, Swedish, Finnish, and Russian.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjankstar%2Ftryton_flutter_client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjankstar%2Ftryton_flutter_client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjankstar%2Ftryton_flutter_client/lists"}