Files
trail-mate/docs/specification/UI_PRESENTATION_ARCHITECTURE_SPEC.md
T
vicliuandGitHub bf7068b02b 0.1.26-alpha release
* refactor: render chat rows from presentation state

* Fix Meshtastic channel sync and add MeshCore CN preset

* Add granular chat notification settings

* Add SD settings backup and restore

* Prepare 0.1.26-alpha release

---------

Co-authored-by: vicliu624 <vicliu@outlook.com>
2026-05-19 16:04:42 +08:00

175 lines
3.0 KiB
Markdown

# UI Presentation Architecture Specification
Trail Mate supports embedded LVGL, ASCII/TUI, GTK, CLI, and headless product
targets. UI code must therefore be split by responsibility rather than by the
first toolkit that implemented a page.
## Three UI Layers
```text
App Service
Business state and business actions.
Presentation Model
UI-independent page/workspace state and actions.
Shell / Renderer
LVGL / ASCII / GTK / CLI / Headless concrete rendering and input.
```
## App Service
App services own business-facing state and actions.
Examples:
```text
ChatService
ContactService
LocationService
MeshService
ConfigService
DeviceStatusService
```
App services must not know:
```text
LVGL
GTK
terminal handles
screen size
font objects
button widgets
layout widgets
framebuffers
```
## Presentation Model
Presentation models convert app-service state into displayable workspace state.
Examples:
```text
ChatWorkspaceModel
MapWorkspaceModel
SettingsWorkspaceModel
DeviceStatusModel
GpsStatusModel
MeshStatusModel
```
Presentation models may know:
```text
selected conversation
abstract list cursor
current workspace action set
field formatting policy
row/column/panel concepts
compact/desktop/terminal presentation profile
```
Presentation models must not know:
```text
lv_obj_t
GtkWidget
ncurses WINDOW
stdout
framebuffer
RadioLib
sx1262
GPS UART
board pin maps
```
## Renderer and Shell
Renderers know concrete UI technology:
```text
LVGL renderer: Presentation snapshot -> lv_obj_t tree
ASCII renderer: Presentation snapshot -> text grid / ANSI output
GTK renderer: Presentation snapshot -> GtkWidget tree
CLI renderer: command result -> stdout/stderr
Headless shell: snapshot/log/API export only
```
Renderer rules:
```text
Renderer consumes PresentationModel snapshots.
Renderer sends UI actions.
Renderer does not own business state.
Renderer does not call platform radio/GPS/storage adapters directly.
Renderer does not mutate app-service internals.
```
## UI Shell Roles
LVGL:
```text
embedded compact shell
single UI owner task/thread
small-screen layout profile
button/touch/encoder/keyboard inputs depending on target
```
ASCII/TUI:
```text
terminal shell
single terminal output owner
keyboard input
stable text canvas or panel model
```
GTK:
```text
desktop-class workbench shell
GTK main loop owner
keyboard/pointer input
wide layout profile
```
CLI:
```text
command shell
stateless or short-lived command execution
stdout/stderr output
```
Headless:
```text
no renderer
only API/log/snapshot exposure
```
## Forbidden Couplings
```text
lvgl_chat_page.cpp implements message deduplication
gtk_map_page.cpp parses GPS NMEA
ascii_mesh_view.cpp reads peer key store directly
AppService includes lv_obj_t or GtkWidget
PresentationModel stores terminal handles
Renderer writes direct to radio or GPS driver
```
## Allowed Couplings
```text
Renderer -> PresentationModel snapshot
Renderer -> PresentationModel action
PresentationModel -> AppService snapshot/action API
AppService -> UseCase/Domain/Protocol/Ports
CompositionRoot -> concrete renderer and service graph
```