"Custom" and "Apps" Workflow types added. Fixed paginate error (20 rows max).

This commit is contained in:
2026-07-16 14:00:33 +02:00
parent f6f999a153
commit ac68a6de28
21 changed files with 688 additions and 630 deletions
+39 -31
View File
@@ -76,11 +76,11 @@ Everything is data-driven. New buttons, screens, and branching logic are configu
| function_id | behaviour |
|---|---|
| `show_call_confirm` | Shows a confirm/cancel screen. Emits `confirmed`. Cancel always ends the workflow. |
| `show_speaker_choice` | Shows speakerphone vs normal choice. Emits `speakerphone` or `normal`. |
| `call_contact` | Dials `phone` from `parameter_json`. Reads `speakerphone` from `parameter_json` (bool), falls back to `lastResultCode == "speakerphone"`. |
| `show_reminder` | Renders `ContentScreen` with the step's `content_block` list. Advances with `null` when the patient taps the button. |
| `show_tutorial` | Same as `show_reminder` — mechanically identical. Both render `ContentScreen`. |
| `open_app` | Launches `package_name` from `parameter_json` via `packageManager.getLaunchIntentForPackage`. Advances with `null`. Shows a toast if the app isn't installed. |
| `show_content` | Renders `ContentScreen` with the step's `content_block` list (heading/text/image/button). A button block advances with its own `result_code`; `result_code == "cancel"` always ends the workflow regardless of step type. With no button block, a default "Next" button advances with `null`. |
| `show_app_list` | Renders `AppListScreen` — a scrolling grid of every `workflow_type == "app"` workflow for the device (the equivalent of a stock launcher's swipe-up app drawer). Tapping a tile starts that workflow directly, same as a home-grid button. |
| `if` | Checks `lastResultCode == if_result_code`. Jumps to `then_step` if true, `else_step` if false. Falls back to next by sort_order if targets not set. |
| `label` | No-op. Used as a named jump target for `if` steps. Advances to next step by sort_order. |
@@ -90,8 +90,7 @@ Everything is data-driven. New buttons, screens, and branching logic are configu
| result_code | emitted by |
|---|---|
| `confirmed` | `show_call_confirm` (user tapped confirm) |
| `cancelled` | `show_call_confirm` or `show_speaker_choice` (user tapped cancel) |
| `cancel` | any `show_content` button tagged as cancel, or `show_speaker_choice` (user tapped cancel) — always ends the workflow |
| `speakerphone` | `show_speaker_choice` |
| `normal` | `show_speaker_choice` |
@@ -167,22 +166,26 @@ Everything is data-driven. New buttons, screens, and branching logic are configu
| function_id | name |
|---|---|
| `show_call_confirm` | Show Call Confirm |
| `show_speaker_choice` | Show Speaker Choice |
| `call_contact` | Call Contact |
| `open_app` | Open App |
| `show_content` | Show Content |
| `show_app_list` | Show App List |
| `if` | If / Branch |
| `label` | Label |
---
### `workflow` — one per home screen button per device
### `workflow` — one per home screen button per device, or one per auto-synced installed app
| field | type | notes |
|---|---|---|
| `name` | string | e.g. "Call Sandro" |
| `name` | string | e.g. "Call Sandro", or the app's label for `workflow_type == "app"` |
| `homepage_position` | integer / null | 1-indexed position in the 2-column grid; null = not on home screen |
| `button_span` | integer | 1 = normal (1 cell), 2 = wide (full row); default 1 |
| `is_active` | boolean | |
| `workflow_type` | select | `custom` (default, caregiver-authored) or `app` (auto-synced from an installed app) |
| `package_name` | string / null | set only for `workflow_type == "app"`; matched against on re-sync so a caregiver's added tutorial step or homepage_position always survives |
| `is_active` | boolean | for `app` workflows: set to `false` on uninstall instead of deleting, so a reinstall reactivates the same row rather than duplicating it |
| `device` | belongsTo → devices | |
| `workflow_steps` | hasMany → workflow_step | fetched via `workflow_steps` append |
@@ -253,8 +256,7 @@ The caregiver web app dashboard groups these rows by device user → workflow
| sort_order | function_id | parameter_json |
|---|---|---|
| 1 | `show_call_confirm` | |
| 2 | `call_contact` | `{"phone": "+41768224400"}` |
| 1 | `call_contact` | `{"phone": "+41768224400"}` |
Steps run in order. No transitions, no if steps needed.
@@ -264,15 +266,14 @@ Steps run in order. No transitions, no if steps needed.
| sort_order | function_id | parameter_json | if_result_code | then_step | else_step |
|---|---|---|---|---|---|
| 1 | `show_call_confirm` | — | — | — | — |
| 2 | `show_speaker_choice` | — | — | — | — |
| 3 | `if` | — | `speakerphone` | → step 4 | → step 5 |
| 4 | `label` | — | — | — | — |
| 5 | `call_contact` | `{"phone":"…","speakerphone":true}` | — | — | — |
| 6 | `label` | — | — | — | — |
| 7 | `call_contact` | `{"phone":"…","speakerphone":false}` | — | — | — |
| 1 | `show_speaker_choice` | — | — | — | — |
| 2 | `if` | — | `speakerphone` | → step 3 | → step 4 |
| 3 | `label` | — | — | — | — |
| 4 | `call_contact` | `{"phone":"…","speakerphone":true}` | — | — | — |
| 5 | `label` | — | — | — | — |
| 6 | `call_contact` | `{"phone":"…","speakerphone":false}` | — | — | — |
Step 3 reads `lastResultCode` from step 2. If it equals `"speakerphone"`, jumps to step 4 (label) → step 5 (call with speaker). Otherwise jumps to step 6 (label) → step 7 (normal call).
Step 2 reads `lastResultCode` from step 1. If it equals `"speakerphone"`, jumps to step 3 (label) → step 4 (call with speaker). Otherwise jumps to step 5 (label) → step 6 (normal call).
---
@@ -281,18 +282,25 @@ Step 3 reads `lastResultCode` from step 2. If it equals `"speakerphone"`, jumps
```
app/src/main/java/com/example/ichwillheim/
├── MainActivity.kt — entry point, navigation state, workflow runner, call utilities
├── HomeScreen.kt — patient home screen (clock, workflow buttons)
├── ContentScreen.kt data-driven content renderer for show_reminder / show_tutorial steps
├── PreCallStepsScreen.kt — WorkflowConfirmScreen (show_call_confirm)
├── SpeakerChoiceScreen.kt — WorkflowSpeakerChoiceScreen, SpeakerOptionHalf
├── PinScreen.kt — PIN entry screen
├── LauncherSettingsScreen.kt — SettingsMenuScreen, LauncherSettingsScreen, LanguagePicker
├── CallOverlayService.kt — foreground service for call overlay
├── WorkflowModels.kt — Workflow, WorkflowStep, ContentBlock
├── WorkflowEngine.kt — WorkflowRunState: advance(), param(), start()
├── SettingsRepository.kt — AppSettings + SharedPreferences
└── RemoteConfigRepository.kt — Ktor HTTP client; fetches workflows from NocoBase
├── MainActivity.kt — entry point, step dispatcher (the `when` block), call utilities
├── ui/
│ ├── HomeScreen.kt — patient home screen (clock, workflow buttons)
│ ├── ContentScreen.kt data-driven content renderer for show_content steps
├── SpeakerChoiceScreen.kt — WorkflowSpeakerChoiceScreen, SpeakerOptionHalf
├── PinScreen.kt — PIN entry screen
├── LauncherSettingsScreen.kt — SettingsMenuScreen, LauncherSettingsScreen, LanguagePicker
│ └── theme/ — Color.kt, Theme.kt, Type.kt
├── viewmodel/
│ └── LauncherViewModel.kt — screen state + navigation flags, survives config changes
├── domain/
│ ├── WorkflowModels.kt — Workflow, WorkflowStep, ContentBlock
│ └── WorkflowEngine.kt — WorkflowRunState: advance(), param(), start()
├── data/
│ ├── SettingsRepository.kt — AppSettings + SharedPreferences
│ ├── RemoteConfigRepository.kt — Ktor HTTP client; fetches workflows from NocoBase
│ └── InstalledApps.kt — LauncherApps enumeration of launchable apps
└── service/
└── CallOverlayService.kt — foreground service for call overlay
```
---