Files
trail-mate/docs/specification/UI_PRESENTATION_ARCHITECTURE_SPEC.md
vicliu 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

3.0 KiB

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

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:

ChatService
ContactService
LocationService
MeshService
ConfigService
DeviceStatusService

App services must not know:

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:

ChatWorkspaceModel
MapWorkspaceModel
SettingsWorkspaceModel
DeviceStatusModel
GpsStatusModel
MeshStatusModel

Presentation models may know:

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:

lv_obj_t
GtkWidget
ncurses WINDOW
stdout
framebuffer
RadioLib
sx1262
GPS UART
board pin maps

Renderer and Shell

Renderers know concrete UI technology:

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:

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:

embedded compact shell
single UI owner task/thread
small-screen layout profile
button/touch/encoder/keyboard inputs depending on target

ASCII/TUI:

terminal shell
single terminal output owner
keyboard input
stable text canvas or panel model

GTK:

desktop-class workbench shell
GTK main loop owner
keyboard/pointer input
wide layout profile

CLI:

command shell
stateless or short-lived command execution
stdout/stderr output

Headless:

no renderer
only API/log/snapshot exposure

Forbidden Couplings

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

Renderer -> PresentationModel snapshot
Renderer -> PresentationModel action
PresentationModel -> AppService snapshot/action API
AppService -> UseCase/Domain/Protocol/Ports
CompositionRoot -> concrete renderer and service graph