From a733b8bcf596a2efa9823868aa990e3ca8ba334e Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Fri, 2 Oct 2026 14:23:15 +0200 Subject: [PATCH] docs(solo): bring the docs up to date with the L1 refresh - Home pages as they are now (Status, quick panels, Map page), the Status screen's tabs instead of Diagnostics / GPS / Sensors, lock clock Big / Compact and the hint on a key press, battery curve on L1 and L2, "+ Send" and a failed send, trail pin, vector map behind -D MAP_VECTOR. - Developer guide: drawScreenHeader, soft frames, InfoKit, TabBar, a status bar without blinking, toast and millis() rules; ui-core status; build flags (GPS_SKYVIEW, MAP_VECTOR, HIST_ARCHIVE added, ui-tiny-only ones out). - New simulator screenshots: the clock page and the Status page. Co-Authored-By: Claude Opus 5.5 --- docs/solo/README.md | 9 +-- docs/solo/developer/build-flags.md | 10 ++-- docs/solo/developer/ui-core.md | 4 +- docs/solo/developer/ui-framework.md | 90 +++++++++++++++++++--------- docs/solo/getting-started.md | 22 ++++++- docs/solo/img/oled-clock.png | Bin 1196 -> 1512 bytes docs/solo/img/oled-messages.png | Bin 1547 -> 0 bytes docs/solo/img/oled-status.png | Bin 0 -> 2145 bytes docs/solo/lock.md | 16 +++-- docs/solo/messages.md | 11 ++-- docs/solo/navigation.md | 18 +++--- docs/solo/settings.md | 11 +++- docs/solo/tools.md | 50 +++++++++------- 13 files changed, 157 insertions(+), 84 deletions(-) delete mode 100644 docs/solo/img/oled-messages.png create mode 100644 docs/solo/img/oled-status.png diff --git a/docs/solo/README.md b/docs/solo/README.md index 4e5d02ae..42faf766 100644 --- a/docs/solo/README.md +++ b/docs/solo/README.md @@ -19,7 +19,8 @@ still connects as with the stock firmware, over Bluetooth or USB. - **Nearby nodes**: who's around, signal and distance, ping, and remote admin of your repeaters and rooms. - **Tools**: clock with alarm, timer and stopwatch, a remote bot that answers - commands over the mesh, repeater mode, a ringtone editor, diagnostics. + commands over the mesh, repeater mode, a ringtone editor, and a status + screen with the radio, GPS, battery and mesh counters. - **Screen lock** with an optional PIN. - **On the Wio Tracker L2**: an offline map, message history on the SD card, the SD card as a USB drive, updates over WiFi. @@ -40,7 +41,7 @@ These docs mark the differences with notes like this: | OLED / e-ink | | Wio Tracker L2 | | :---: | :---: | :---: | -| ![Clock page](./img/oled-clock.png) | ![Messages](./img/oled-messages.png) | ![Home screen](./img/l2-home.png) | +| ![Clock page](./img/oled-clock.png) | ![Status page](./img/oled-status.png) | ![Home screen](./img/l2-home.png) | The joystick and keyboard devices share one interface, sized for small OLED and e-ink screens. The Wio Tracker L2 has its own, built for a 320 × 240 @@ -49,11 +50,11 @@ history on the SD card and updates over WiFi. ## Pages -- [Getting started](./getting-started.md): controls, the home screen, the phone app, updates +- [Getting started](./getting-started.md): controls, the home screen and its quick panels, the phone app, updates - [Messages](./messages.md): channels, direct messages, rooms, typing - [Contacts](./contacts.md): nearby nodes, favourites, remote admin - [Navigation](./navigation.md): GPS, trail, waypoints, compass, sharing your location, the map -- [Tools](./tools.md): clock tools, bot, repeater, ringtones, diagnostics +- [Tools](./tools.md): clock tools, bot, repeater, ringtones, the Status screen - [Settings](./settings.md): what is where - [Screen lock](./lock.md): locking, auto-lock, PIN - [Hardware](./hardware.md): external keyboards and joysticks, e-ink, SD card, WiFi diff --git a/docs/solo/developer/build-flags.md b/docs/solo/developer/build-flags.md index f68edf2b..3c40c7db 100644 --- a/docs/solo/developer/build-flags.md +++ b/docs/solo/developer/build-flags.md @@ -31,7 +31,7 @@ per-user. Listed here so the rest of this page can assume them. | `TRAIL_CAPACITY=` | Points the GPS trail holds (16 B each). Default 512 for the nRF52's RAM; the L2 sets 32768 in PSRAM. At most 65535 (the save format's count). | | `TRAIL_SIMPLIFY=0` | Keeps every trail sample instead of storing straight stretches as their two ends. For boards with the memory for it (the L2). | | `TRAIL_FIXED_MIN_DELTA_M=` | A fixed distance between trail points instead of the Point spacing setting, which is then hidden (the L2: 5 m, against GPS jitter). | -| `UI_SENSORS_PAGE=1` | Enables the on-device sensors dashboard page. | +| `UI_SENSORS_PAGE=1` | Only the default Home page order in the solo UI: sensor readings are on the Status screen's Power tab whenever the board has sensors. | | `BLE_PIN_CODE=` | See below — not a plain fixed value in practice. | | `DISPLAY_CLASS=` | Selects the display driver (e.g. `SSD1306Display`, `GxEPDDisplay`, `ST7789Display` — see `src/helpers/ui/` for the full set). Fixed by whatever panel the board actually has; only relevant if you're wiring on a *different* display than stock, in which case the matching driver's `.cpp` also needs adding to `build_src_filter`. | @@ -56,7 +56,6 @@ existing `solo//platformio.ini` for what's already claimed). | `UI_HAS_JOYSTICK=1` + `UI_HAS_JOYSTICK_UPDOWN=1` (optional) + `JOYSTICK_UP` / `JOYSTICK_DOWN` / `JOYSTICK_LEFT` / `JOYSTICK_RIGHT` + `PIN_USER_BTN` + `PIN_BACK_BTN` | A wired joystick (four direction contacts + a press contact for Enter). Replaces single-button navigation entirely once enabled. See [External Keyboard & Joystick](../hardware.md#external-keyboard-and-joystick). | | `PIN_GPIO1` .. `PIN_GPIO4` | Up to four general-purpose pins, each independently switchable between Off / Input / Output (GPIO1/GPIO2 also get an Analog step, if wired to an ADC-capable pin) from Tools › GPIO, and via the `!gpio1`..`!gpio4` bot commands. Not restricted to any particular board — works anywhere the pins are actually free. See [Tools › GPIO](../tools.md#gpio). | | `PIN_HALL_SENSOR` + `HALL_ACTIVE_HIGH=1` (optional) | A Hall-effect or reed sensor for a magnetic flip cover: closing locks and blanks the screen instantly, opening unlocks and wakes it, no combo either way. `HALL_ACTIVE_HIGH` is only for a module wired to pull the pin high (rather than low) when the magnet is near. See [Screen lock › Magnetic cover](../lock.md#magnetic-cover). | -| `PIN_GPS_SWITCH` | A physical on/off switch for GPS power, read alongside the software GPS toggle — the Tools screen shows `gps off(hw)` / `gps off(sw)` when the two disagree, instead of silently trusting one over the other. | --- @@ -75,9 +74,7 @@ existing `solo//platformio.ini` for what's already claimed). | --- | --- | | `ENV_INCLUDE_GPS=1` | Compiles in GPS support (NMEA parsing, location provider) at all. | | `GPS_BAUD_RATE=` | Baud rate for the GPS module's serial link (`Serial1`). Match your module's default. | - -`PIN_GPS_SWITCH` (above) is independent of both — it's a hardware kill switch -layered on top of GPS support, not a requirement for it. +| `GPS_SKYVIEW` | Keeps every satellite in view (constellation, elevation, azimuth, signal) for the Status screen's Sky tab and the L2's GPS app (~1.5 KB RAM). Set on the Wio Tracker L1 and L2. | --- @@ -90,7 +87,6 @@ layered on top of GPS support, not a requirement for it. | `ENABLE_SCREENSHOT` | Lets the site's [USB tools](https://solo.marekzegarek.com/#pc-tools) (or `tools/screenshot.py`) capture the screen over USB. A colour screen (the L2) renders a fresh frame and sends it as RGB565. | | `KEEP_DISPLAY_ON_USB` | Refreshes the auto-off deadline continuously while externally (USB) powered, so the auto-off timer only starts counting once power is actually removed. Off by default because OLED panels burn in quickly with a permanently-lit screen — only worth enabling for an LCD/e-ink target, or a display you don't mind replacing. | | `AUTO_OFF_MILLIS=` | How long the display stays on before auto-off. Default 15000 (15s); `0` disables auto-off entirely. | -| `UI_RECENT_LIST_SIZE=` | How many entries the recent-activity lists show before scrolling. Default 4. | --- @@ -116,4 +112,6 @@ values above that are set from the phone app or the CLI. | Flag | Meaning | | --- | --- | | `ADVERT_NAME='"name"'` | Sets the default node name baked into a fresh device, instead of the hex of the first 4 bytes of its public key. Note the doubled quoting — it's a C string literal passed through a build flag. | +| `MAP_VECTOR` | Wio Tracker L2: turns on the unfinished vector map (regions from `tools/maps/osm_vector.py`). Without it the vector map stays off whatever was saved. | +| `HIST_ARCHIVE` | Wio Tracker L2: message history also kept on the SD card (`ui-lvgl/HistoryStore.h`). Set in its solo build. | | `MESHCORE_VERSION='"x.y"'` | Overrides the upstream MeshCore base-version string shown in diagnostics, for boards whose port hasn't been rebased onto the latest yet. Cosmetic only — doesn't change protocol behaviour. | diff --git a/docs/solo/developer/ui-core.md b/docs/solo/developer/ui-core.md index e90d3cf5..a71b0b6c 100644 --- a/docs/solo/developer/ui-core.md +++ b/docs/solo/developer/ui-core.md @@ -1,6 +1,6 @@ # UI Core + frontends — design -Status: 📋 draft for review (2026-09-24). Branch: `wio-tracker-l2`. +Status: written 2026-09-24 as the design; steps 0–3, 5 and 6 are done (marked ✅ below); step 4 in part (ui-new's Settings shows the schema's rows inside its own sections). Branch: `wio-tracker-l2`. ## Why @@ -110,7 +110,7 @@ call the same ones, so e.g. "marking a channel read" has one implementation. ### 5. Declarative settings schema -`ui-core/SettingsSchema.h` holds five pages -- map options (trail, live share, arrival alert; ui-lvgl opens it from the map's tools), advert (auto-advert; in ui-lvgl's Nearby advert popup), display & power (brightness, screen off, wake on message, lock screen, battery display, battery shutdown, GPS power saving, time zone, 12-hour clock, clock seconds, units) messages & contacts (DM resends, contact expiry, favourites first) and sound (volume, the sound for direct messages / channels / adverts, advert sound scope). An entry is a one-byte index by default, or a `values` table over a 1/2/4-byte field (seconds, millivolts, an hour offset, `{1, 0}` for a field stored inverted); side effects run through `UiCore` (`applyGpsInterval()`, `host()->applyDisplayPrefs()`). ui-lvgl renders each page (`schemaRows()` draws a page's rows into any container, a screen or a popup); ui-new still uses its own screens. Radio settings are not schema rows (preset list, typed frequency, radio side effects): `ui-core/RadioControl.h` applies them (`applyParams`, `applyTxPower`, `applyApc`, presets = built-ins + user slots) for both ui-new's Settings > Radio and ui-lvgl's Radio screen. Channel management is `ui-core/ChannelControl.h` (`chanctl::`): add Public / Hashtag / Private (passphrase or 32-hex key), rename, delete, notifications / favourite / scope, and `onRemoved()` -- the cleanup of every channel-keyed pref, run by `UiCore::onChannelRemoved` whoever deleted the channel (this device or the app); contacts get the same through `UiCore::cleanupContactPrefs`. Favourites dial slots: `ui-core/Favourites.h` (`pinContact` / `pinChannel` move an entry that is already on another slot; the slot's name is `contactctl::favName`). The schema's display page also carries the lock screen (`auto_lock`) and the 12-hour clock, which ui-lvgl implements (a slide-to-unlock card after the screen turns off). Remote admin is `ui-core/AdminSession.h` (`UiCore::admin`): login with the saved password (forgotten on a wrong password or a silent timeout), CLI round trips with timeouts, the field table (`admin::`), typed values; results come out one at a time through `take()`. `UiCore` offers login answers and CLI replies to it first; only room logins it wasn't waiting for reach the frontend. ui-new's Tools > Admin and ui-lvgl's Admin screen are views over it. The bot's settings are a table too, `ui-core/BotConfig.h` (`botcfg::`: tabs, rows, the NodePrefs flag / text / hour behind each, reply placeholders); ui-new's Tools > Bot and ui-lvgl's Bot screen render it, the bot itself runs in MyMesh. Room servers: `ui-core/RoomSessions.h` (`UiCore::rooms`) keeps who is logged in this session, the one login in flight (with a timeout) and the saved passwords (saved on success, forgotten on failure); `open(contact)` says whether to go straight in, wait for a background login or ask for a password, and outcomes come out through `take()`. Per-contact helpers are `ui-core/ContactControl.h` (`contactctl::`: DM notification / melody overrides, favourite flag, the `@[name] ` reply prefix, splitting a room post into author and text, naming a message's path hops). ui-new's Messages and ui-lvgl's Chats / thread use both. Diagnostics rows are `ui-core/Diagnostics.h` (`diag::`: live counters, system card, font card, counter reset), shown by ui-new's Tools > Diagnostics and ui-lvgl's Home > Diagnostics. Auto-advert is a schema row (`advert_auto_interval_sec`, sent by MyMesh); ui-new keeps its Tools > Auto-Advert screen over the same pref. The compass (ui-lvgl Home > Compass, ui-new Tools > Compass) reads `UiCore::course`. Saving / deleting the user's radio presets is `radioctl::saveUserPreset` / `deleteUserPreset` (ui-new's preset picker and ui-lvgl's Radio > My presets); the scope list is edited through MyMesh (`addScope` / `renameScope` / `removeScope` / `setDefaultScope`), which ui-lvgl's Radio > Scopes and ui-new's Settings > Radio > Scope call directly. The battery percentage (LiPo curve, empty at the shutdown voltage) and the display mode are `ui-core/Battery.h`, used by both status bars; the schema carries Battery display and Clock seconds. The companion's own repeater mode is `ui-core/RepeaterControl.h` (`rptctl::`: on / off with its radio, RX power-save and APC side effects, Current / Custom network with the profile seeded from the chat params, the profile's preset, the filters' ranges and labels, the extra scopes mask); ui-new's Tools > Repeater and ui-lvgl's Home > Repeater use it, MyMesh does the relaying. Sound is `ui-core/SoundControl.h` (`soundctl::`: the On / Off / Auto mode over `buzzer_quiet` + `buzzer_auto`, the volume with its preview, the built-in sounds, the two user melodies as an editable note list) and `ui-core/SoundNotifier.h` (which sound a message / advert plays: global choice, per-contact / per-channel alert and melody overrides); the schema's Sound page holds the volume and the PLAYS FOR choices, the channel melody override is `chanctl::melody`. Both frontends drive a `genericBuzzer`: a PWM piezo on L1, the ES8311 codec on the L2 (`BUZZER_I2S`: an audio task synthesises the notes and counts samples, the board powers the amp through `buzzerAmpPower()`). Outgoing text is `ui-core/MessageText.h` (`msgtext::`: the ten quick messages, the placeholders on offer -- `{loc}`, `{time}`, `{batt}`, live sensor readings -- and expanding them at send time, keeping a reply's `@[name] ` prefix as typed); ui-new's Messages / keyboard and ui-lvgl's compose "+" use it. `UiCore::markAllRead()` clears every unread counter; `MyMesh::advertFlood()` (formerly sim-only) sends the self-advert through repeaters, `advert()` zero-hop. ui-lvgl's screens share their widgets from `UITask.cpp`: `segmented()` (a one-of-N button row; `radioview::rowSegmented` puts one at the right of a settings row), `textField()` (a one-line field padded to exactly one line), `listRow`, `switchRow`, `headerButton`. +`ui-core/SettingsSchema.h` holds five pages -- map options (trail, live share, arrival alert; ui-lvgl opens it from the map's tools), advert (auto-advert; in ui-lvgl's Nearby advert popup), display & power (brightness, screen off, wake on message, lock screen, battery display, battery shutdown, GPS power saving, time zone, 12-hour clock, clock seconds, units) messages & contacts (DM resends, contact expiry, favourites first) and sound (volume, the sound for direct messages / channels / adverts, advert sound scope). An entry is a one-byte index by default, or a `values` table over a 1/2/4-byte field (seconds, millivolts, an hour offset, `{1, 0}` for a field stored inverted); side effects run through `UiCore` (`applyGpsInterval()`, `host()->applyDisplayPrefs()`). ui-lvgl renders each page (`schemaRows()` draws a page's rows into any container, a screen or a popup); ui-new puts a schema section's rows into its own accordion sections (`SCHEMA_DISPLAY`, `SCHEMA_SYSTEM`, … in `SettingsScreen.h`), next to the rows it still draws itself (radio, keyboard, home pages, quick messages). Radio settings are not schema rows (preset list, typed frequency, radio side effects): `ui-core/RadioControl.h` applies them (`applyParams`, `applyTxPower`, `applyApc`, presets = built-ins + user slots) for both ui-new's Settings > Radio and ui-lvgl's Radio screen. Channel management is `ui-core/ChannelControl.h` (`chanctl::`): add Public / Hashtag / Private (passphrase or 32-hex key), rename, delete, notifications / favourite / scope, and `onRemoved()` -- the cleanup of every channel-keyed pref, run by `UiCore::onChannelRemoved` whoever deleted the channel (this device or the app); contacts get the same through `UiCore::cleanupContactPrefs`. Favourites dial slots: `ui-core/Favourites.h` (`pinContact` / `pinChannel` move an entry that is already on another slot; the slot's name is `contactctl::favName`). The schema's display page also carries the lock screen (`auto_lock`) and the 12-hour clock, which ui-lvgl implements (a slide-to-unlock card after the screen turns off), and ui-new's lock clock look (`lock_compact`, Big / Compact), which ui-lvgl leaves out of its rows. Remote admin is `ui-core/AdminSession.h` (`UiCore::admin`): login with the saved password (forgotten on a wrong password or a silent timeout), CLI round trips with timeouts, the field table (`admin::`), typed values; results come out one at a time through `take()`. `UiCore` offers login answers and CLI replies to it first; only room logins it wasn't waiting for reach the frontend. ui-new's Tools > Admin and ui-lvgl's Admin screen are views over it. The bot's settings are a table too, `ui-core/BotConfig.h` (`botcfg::`: tabs, rows, the NodePrefs flag / text / hour behind each, reply placeholders); ui-new's Tools > Bot and ui-lvgl's Bot screen render it, the bot itself runs in MyMesh. Room servers: `ui-core/RoomSessions.h` (`UiCore::rooms`) keeps who is logged in this session, the one login in flight (with a timeout) and the saved passwords (saved on success, forgotten on failure); `open(contact)` says whether to go straight in, wait for a background login or ask for a password, and outcomes come out through `take()`. Per-contact helpers are `ui-core/ContactControl.h` (`contactctl::`: DM notification / melody overrides, favourite flag, the `@[name] ` reply prefix, splitting a room post into author and text, naming a message's path hops). ui-new's Messages and ui-lvgl's Chats / thread use both. Diagnostics rows are `ui-core/Diagnostics.h` (`diag::`: live counters, font card, counter reset), shown by ui-new's Home > Status screen (Mesh and System tabs) and ui-lvgl's Home > Diagnostics. Auto-advert is a schema row (`advert_auto_interval_sec`, sent by MyMesh); ui-new keeps its Tools > Auto-Advert screen over the same pref. The compass (ui-lvgl Home > Compass, ui-new Tools > Compass) reads `UiCore::course`. Saving / deleting the user's radio presets is `radioctl::saveUserPreset` / `deleteUserPreset` (ui-new's preset picker and ui-lvgl's Radio > My presets); the scope list is edited through MyMesh (`addScope` / `renameScope` / `removeScope` / `setDefaultScope`), which ui-lvgl's Radio > Scopes and ui-new's Settings > Radio > Scope call directly. The battery percentage (the built-in LiPo curve or the user's `batt_curve_mv`, empty at the shutdown voltage) and the display mode are `ui-core/Battery.h`, used by both status bars; the schema carries Battery display and Clock seconds. The companion's own repeater mode is `ui-core/RepeaterControl.h` (`rptctl::`: on / off with its radio, RX power-save and APC side effects, Current / Custom network with the profile seeded from the chat params, the profile's preset, the filters' ranges and labels, the extra scopes mask); ui-new's Tools > Repeater and ui-lvgl's Home > Repeater use it, MyMesh does the relaying. Sound is `ui-core/SoundControl.h` (`soundctl::`: the On / Off / Auto mode over `buzzer_quiet` + `buzzer_auto`, the volume with its preview, the built-in sounds, the two user melodies as an editable note list) and `ui-core/SoundNotifier.h` (which sound a message / advert plays: global choice, per-contact / per-channel alert and melody overrides); the schema's Sound page holds the volume and the PLAYS FOR choices, the channel melody override is `chanctl::melody`. Both frontends drive a `genericBuzzer`: a PWM piezo on L1, the ES8311 codec on the L2 (`BUZZER_I2S`: an audio task synthesises the notes and counts samples, the board powers the amp through `buzzerAmpPower()`). Outgoing text is `ui-core/MessageText.h` (`msgtext::`: the ten quick messages, the placeholders on offer -- `{loc}`, `{time}`, `{batt}`, live sensor readings -- and expanding them at send time, keeping a reply's `@[name] ` prefix as typed); ui-new's Messages / keyboard and ui-lvgl's compose "+" use it. `UiCore::markAllRead()` clears every unread counter; `MyMesh::advertFlood()` (formerly sim-only) sends the self-advert through repeaters, `advert()` zero-hop. ui-lvgl's screens share their widgets from `UITask.cpp`: `segmented()` (a one-of-N button row; `radioview::rowSegmented` puts one at the right of a settings row), `textField()` (a one-line field padded to exactly one line), `listRow`, `switchRow`, `headerButton`. Replaces the per-item code in `SettingsScreen`: diff --git a/docs/solo/developer/ui-framework.md b/docs/solo/developer/ui-framework.md index 93f6c33a..d6bb1390 100644 --- a/docs/solo/developer/ui-framework.md +++ b/docs/solo/developer/ui-framework.md @@ -63,7 +63,9 @@ public: Only screens needing a *parameter* at entry add a typed call after it (e.g. `gotoRingtoneEditor` → `selectSlot(slot)`, `gotoMapScreen` → `showMapView()`). 4. Reach it from somewhere — usually a row in `ToolsScreen.h` (add an `Action` - enum value, a row in the right section table, and a `dispatch()` case). + enum value, a row in the right section table, and a `run()` case). The + Tools home page lists the last two tools used; give the new one a state + in `HomeScreen::toolState()` (`UITask.cpp`) if it has one worth showing. That's the whole contract. Steps 1, 3 and 4 are compiler-checked (a mismatch won't link); only a forgotten step 2 can slip through — every screen pointer is @@ -95,14 +97,19 @@ pixel sizes** — derive everything from these: Drawing helpers (all clip/measure for you): -- `drawCenteredHeader(title, menu_hint=false, menu_open=false)` — plain centered - title + separator. -- `drawInvertedHeader(label, menu_hint=false, menu_open=false)` — filled title - bar (used by detail views). -- Both take an optional `menu_hint`: pass `true` on a screen with a Hold-Enter - context menu to reserve a `≡` glyph (`menuHintWidth()`/`drawContextMenuHint()`) - in the header, so the menu is discoverable without already knowing the - shortcut; `menu_open` highlights it while the menu is actually up. +- `drawScreenHeader(d, title, page=-1, pages=0, menu_hint=false, menu_open=false)` + (`ui-new/icons.h`) — every screen's title bar: the title (title case, no + icon) centred over the separator, page dots at the right for a screen with + views (`page` of `pages`, e.g. Trail's Summary / Map / List), and the `≡` + hint when the screen has a Hold-Enter menu, so the menu is discoverable + without knowing the shortcut; `menu_open` highlights it while the menu is + up. A title too long to centre goes left and ends in an ellipsis. +- `drawInvertedHeader(label, menu_hint=false, menu_open=false)` — a filled + title bar, kept for the node detail and Navigate views. +- `drawSoftRect` / `fillSoftRect` — a box with its corner pixels left out; + every frame and fill in the UI uses them (selections, pills, buttons). + `drawPanel(x, y, w, h)` is a box floating over the view (alert, popup, + hint): it clears a 1 px moat, fills dark and draws the soft border. - `drawSelectionRow(x, y, w, h, sel)` — the highlight bar behind a list row. - `drawTextEllipsized(x, y, max_w, str, selected=false)` — truncates with `…`; **use this for any user string** (names, labels) so long/UTF-8 text can't @@ -160,6 +167,8 @@ calculator (`scrollIndicatorReserve`) are exposed for hand-laid lists. | `DigitEditor` | `DigitEditor.h` | scroll-edit one number, digit by digit | | `FullscreenMsgView` | `FullscreenMsgView.h` | scrollable full-message reader + word wrap | | `NavView` | `NavView.h` | bearing/distance/ETA "navigate to a point" view | +| `TabBar` | `TabBar.h` | a row of tabs: the current one a soft pill, whole tabs only, ◂ ▸ where more are off screen | +| `info::` rows and blocks | `InfoKit.h` | settings rows, data screens (below) | All follow the same shape: a `begin(...)` to open, an `active` flag, a `handleInput(c)` returning a small `Result` enum, and a `render()`/`draw()`. @@ -211,6 +220,24 @@ to pick, Enter to insert via the shared `insertGlyph()` helper, Cancel to dismiss. Holding a letter with no variants, or any T9/alt-alphabet/symbols cell, is a no-op. +**InfoKit** (`ui-new/InfoKit.h`, namespace `info`) is the shared look of +settings and data screens. Rows (drawn after `drawRowSelection()`, in its +ink): `valueRow(d, y, label, value, sel, reserve, x0)` — label left, value +flush right with its unit after a space ("50 m"), cut and marquee-scrolled +when selected; `switchRow` — a yes/no setting as an on/off switch +(`toggle()`); `listRow` — picks between the two for a formatter that returns +exactly "ON" / "OFF". `rowWrapped` gives a long value its own line instead of +an ellipsis nobody can scroll. Blocks for data screens: `section` (a centred +"··· Font ···" divider), `meter`, `battery`, `chip`, `big` (a 2× number with +its unit), `History` + `spark` (a sparkline), `rule` / `vrule`. `Flow` +places blocks top-down, skips the ones scrolled off and tells whether more +are below, which gives the scroll indicator for free (see `StatusScreen.h`). + +Other drawing helpers in `icons.h`: `drawButton` (a push button, soft pill, +filled while selected), `drawDisclosure` (▸ / ▾ on an accordion section), +`drawPageDots`, `drawLoadingDots` (the waiting animation), `drawSignalBars` +(SNR as four bars). + `FullscreenMsgView::wrapLines()` is a standalone pixel-accurate word-wrapper (O(n), variable-width-font aware) reusable by any multi-line layout; it writes into the shared `s_wrap_trans` / `s_wrap_lines` scratch (single-threaded render, @@ -260,21 +287,19 @@ MINI_ICON(ICON_FOO, 5, ``` Draw with `miniIconDraw(display, x, topY, ICON_FOO)` (auto-scaled & centered), -`miniIconDrawTop` (exact placement), or the boxed/slot variants -(`drawBoxedIcon` = lit when active, `drawSlotIcon` = plain). Bigger page glyphs -use `BIG_ICON` / `bigIconDraw`. The home status bar composes these right-to-left -with a `blinkOn()` cadence for "leave it on and forget" broadcasts (auto-advert, -Live Share, trail, repeater) — follow that pattern when adding an indicator: -always shown on e-ink, blinking on OLED. +`miniIconDrawTop` (exact placement), `miniIconDrawCentered`, or `drawSlotIcon` +(centred in a status-bar slot). Use icons sparingly: headers and the Tools +list have none, the Home page row is the main place for them. -Icons are drawn from a fixed priority-ordered table (`HomeScreen::renderBatteryIndicator()`, -`UITask.cpp`); once the row runs out of horizontal space the loop just stops, -so the lowest-priority icons silently drop first rather than the whole bar -crushing the node name. A blinking icon still reserves its width on the -off-phase of its blink, so the row's layout can't visibly shift width as icons -blink in and out. +The home status bar (`HomeScreen::renderBatteryIndicator()`, `UITask.cpp`) +draws plain glyphs right to left from a fixed, priority-ordered table, with +no boxes and no blinking: each icon tells a state by its shape (Bluetooth only +while a phone is connected, the GPS reticle broken until a fix, a pin while +the trail records). Once the row runs out of room the loop stops, so the +lowest-priority icons drop first instead of the bar crushing the time. Add an +indicator as one more row in that table, at its priority. -Screens with a Hold-Enter context menu (Nodes, Bot, Admin, Diagnostics, …) pass +Screens with a Hold-Enter context menu (Nodes, Messages, Bot, Admin, …) pass `menu_hint=true` to their header call (see §2) so a `≡` glyph advertises the menu; `KEY_CONTEXT_MENU` (Hold-Enter) opens it. @@ -363,7 +388,13 @@ with `resolvePersonPos()` (live `[LOC]` share, else last-advertised fix). `chanctl::onRemoved()` (ui-core/ChannelControl.h). New per-contact or per-channel state should clear there too. - **Toasts:** `_task->showAlert("msg", duration_ms)` overlays a transient banner - over any screen; no redraw plumbing needed. + over any screen (not over the keyboard); no redraw plumbing needed. Use one + only for what the screen doesn't already show: a failure ("Send failed", + "Contacts full") or an outcome somewhere else. No echo of an action whose + result is in view ("Sent", "Deleted", "Counters reset"). +- **Time:** `millis()` wraps after ~49.7 days. Compare deadlines as + `(int32_t)(millis() - deadline) >= 0`, never `millis() >= deadline`, and use + 0 as "now / none" (`UITask::refreshDue()`, `alertShowing()`). - **Strings:** always `strncpy`+NUL or `snprintf`; treat every name/label as untrusted-length and render through `drawTextEllipsized`. @@ -374,7 +405,8 @@ with `resolvePersonPos()` (live `[LOC]` share, else last-advertised fix). ```cpp // ui-new/MyToolScreen.h — included by UITask.cpp near the other screens #pragma once -#include "icons.h" // drawList + mini-icons +#include "icons.h" // drawList, drawScreenHeader, mini-icons +#include "InfoKit.h" // valueRow / switchRow #include "../NodePrefs.h" class MyToolScreen : public UIScreen { @@ -389,13 +421,15 @@ public: int render(DisplayDriver& d) override { d.setTextSize(1); - d.drawCenteredHeader("MY TOOL"); + drawScreenHeader(d, "My tool"); + int next = 500; drawList(d, ROWS, _sel, _scroll, [&](int i, int y, bool sel, int reserve) { drawRowSelection(d, y, sel, reserve); - d.setCursor(4, y); - d.print(i == 0 ? "Alpha" : i == 1 ? "Bravo" : "Charlie"); + static const char* const L[ROWS] = { "Alpha", "Bravo", "Charlie" }; + const int m = info::valueRow(d, y, L[i], "50 m", sel, reserve); // value flush right + if (m > 0 && m < next) next = m; // a marquee moving }); - return 500; + return next; } bool handleInput(char c) override { diff --git a/docs/solo/getting-started.md b/docs/solo/getting-started.md index 0bfb1ce1..9e771ac4 100644 --- a/docs/solo/getting-started.md +++ b/docs/solo/getting-started.md @@ -26,10 +26,26 @@ combinations), Enter and Esc. [Hardware](./hardware.md) has the key maps. ## Home screen The home screen is a row of pages. On joystick devices, **Left / Right** steps -through them and **Enter** opens the one shown: +through them (on Favourites it moves between the slots first). The default +order: -Clock, Recent, Radio, Bluetooth, Advert, GPS, Sensors, Tools, Shutdown, -Settings, Messages, Favourites, Map. +| Page | Shows | +| ---- | ----- | +| **Clock** | The time, the date and up to three fields of your choice; Enter opens the clock tools | +| **Favourites** | Six slots for the conversations you open most ([Contacts](./contacts.md#favourites)) | +| **Status** | Radio, GPS, battery and mesh at a glance; Enter opens the [Status screen](./tools.md#status) | +| **Bluetooth** | Bluetooth on / off and the phone: connected, or the pairing PIN | +| **Advert** | Send an advert now, and the auto-advert interval | +| **Settings** | Brightness, GPS on / off, then all settings | +| **Map** | Your position, the trail, people sharing theirs and the target ([Navigation](./navigation.md#map)) | +| **Tools** | The two tools you used last with their state, then all tools | +| **Messages** | The two latest conversations with their unread counts, then all messages | +| **Shutdown** | Lock the screen, or hibernate (with the battery level) | + +Most pages are **quick panels**: a few rows and a last one that opens the +full screen. **Up / Down** picks a row and **Enter** acts on it. A value row +(brightness, auto-advert) goes into editing: **Left / Right** change it while +you watch, **Enter** or **Back** keeps it. Settings › Home Pages sets their order and hides the ones you don't use; Settings and Messages are always shown. diff --git a/docs/solo/img/oled-clock.png b/docs/solo/img/oled-clock.png index 22c9a776774782230ec43aedd0638219a8d854e1..c9d219a9e0efbbf0f30708d9bbd9a19594b8384d 100644 GIT binary patch literal 1512 zcmeAS@N?(olHy`uVBq!ia0y~yU}9llU}WK70*c(|*d4>bz`EYk#WAGf*4w+@eRHfB z+AiJ?)L%R8ZnbiA*pie67Q*+{)aQ>U&dk`k~5K*Cq&*GGhF%_`SazMeZ0vTX$%b#3<_)v9gGY~Q09?Z zwh6WC64{Lr-bB)mg{g2aogrmyxq-~_#CRRcwloyezy>?C?K{8VYw3>7F_&|B?*Htw zmf_d#eXH}kcHLuaF7Nm*>9B|Yz`g@S`wFOI!;GLVM+Pj8R(O3s{lTxo?fCZpeSN?6pPe(Ip&^jX_Hm8SgLC_jhyK5V#W5YfdA1dNuXN9kYqq&% z9CYs3s_Qd)%Ir_A`kj6C?F>n1z-~-)cvkuCV#f2i=k5Go7e6iEzW>|j7x!<*8~@{h z1(w4a$&{Ygo90)|f0c1P;C(^ewrBTRH{X9-+E?9Ps{dUQ$*>8P=kl+uk)QLoMs3eL z+sX0$_1|YmR{FTr{?@fiKTb@To6r7C`eq~dZk=)xECHvSG;P*?&h>s?_PU$TZoa=3qrLaD<(K8> zxaa@P>rPJIa(?rr!lE*pD>CZ-y$frz;M!*X=6Uze=d9(~<>z|eJ$qOAQ0({KXE$~f z_3eK4zDV9}*SecqEb5-!S`K%_uJw{BkDtGd@V@a`V#Bn6|9jn}51W2l2}?2)Qs?jM_h2c7!MFML6=v=1zu3w!&~H2xYS|e6-PkMKn^tD#*S!mUw7;z~8og zNt$)|v4hr=ZR^>7--TIvA}O0K{GPJap{S#??GMNNmPJSbW7?+nTwcppW(HXC)L;^8 zTyXc@p6`haaJ$z?F1cU%VRtr=*$3;) zVTD=JSq1&I+FO3ymEG1{cnl#9D@TE;VbzrL&yz(!cHg+0|5?*?-~aBnhQJb>!PC{x JWt~$(6952SLe&5O literal 1196 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 literal 0 HcmV?d00001 diff --git a/docs/solo/lock.md b/docs/solo/lock.md index 13cbe9e5..d8c33a1a 100644 --- a/docs/solo/lock.md +++ b/docs/solo/lock.md @@ -6,14 +6,22 @@ messages still arrive, alarms still ring and the phone app still connects. ## Locking and unlocking **Hold Back and press Enter three times** within 3 seconds; the same locks -and unlocks. A hint on the lock screen counts the presses. With a CardKB, -**Fn+Esc** does it in one press. +and unlocks. With a CardKB, **Fn+Esc** does it in one press. **Settings › Display › Lock screen** locks the device whenever the screen turns off by itself. -The lock screen shows the time, the date and the first two of the Clock -page's fields, but not the device's name. +The lock screen has the status bar on top and one of two looks, set in +Settings › Display › **Lock clock**: + +- **Big**: the time in large digits, the date, and how many messages are + unread. +- **Compact**: a smaller time with the date beside it, and the Clock page's + fields as rows below (unread messages too, if no field shows them). + +The key that wakes the screen does nothing else, so a glance shows the data. +A key pressed on the lit lock screen brings up the unlock hint at the bottom +for a few seconds; it counts the presses. On e-ink the hint stays up. > [!NOTE] > **Wio Tracker L2:** with **Lock screen** on (Settings › Display), waking diff --git a/docs/solo/messages.md b/docs/solo/messages.md index 363b47a3..7e90ab06 100644 --- a/docs/solo/messages.md +++ b/docs/solo/messages.md @@ -11,9 +11,10 @@ Unread counts show on each conversation, on the list and on the home screen. ## Reading Open a conversation to see its history as chat bubbles: yours on the right, -received ones on the left, newest at the bottom. Each bubble shows the sender, -its age and a small hop count: on a received message, how many repeaters it -came through; on your own, how many repeaters were heard passing it on. +received ones on the left, newest at the bottom. Each bubble shows its age +and a small hop count: on a received message, how many repeaters it came +through; on your own, how many repeaters were heard passing it on. In +channels and rooms it also names the sender. **Enter** on a message opens it full screen; **Left / Right** there pages to the older and newer one. @@ -44,10 +45,12 @@ haven't read, its unread count gets a **+** (for example `48+`). ## Writing -Open a conversation and choose **[+ send]** (or Enter at the bottom of the +Open a conversation and choose **+ Send** (or Enter at the bottom of the history). Pick a quick message or **Custom message** for the keyboard. - **Quick messages**: ten of your own, edited in Settings › Messages. +- If a message can't be sent, you stay where you were: the keyboard keeps + the text (its label reads **Not sent**), so you can send it again. - **Placeholders** fill in live data when the message is sent: `{loc}` (your GPS position), `{time}`, `{batt}`, and the readings of any sensor the device has: `{temp}`, `{hum}`, `{pres}`, `{alt}`, `{lux}`, diff --git a/docs/solo/navigation.md b/docs/solo/navigation.md index 3c1a3ef2..38dde92c 100644 --- a/docs/solo/navigation.md +++ b/docs/solo/navigation.md @@ -7,7 +7,7 @@ hardware is needed. Distances and speeds follow Settings › System › Units ## Trail **Tools › Trail** records your route in the background while you use the rest -of the device (a blinking **G** in the status bar). Straight stretches are +of the device (a pin in the status bar). Straight stretches are stored as their two ends, so the 512 points cover a long route. **Left / Right** switches between the **Summary** (distance, time, speed or pace), the **Map** (your route, waypoints, people sharing their position, the target) and the @@ -110,9 +110,11 @@ in one step. The target shows as a flag on the map. ## Map -The **Map** home page shows your position, the trail, waypoints, people -sharing their position and the target. **Enter** opens the trail map; -**hold Enter** shares your position. +The **Map** home page shows a small map on the left (your position, the +trail, people sharing their position and the target) and four lines beside +it: GPS, the trail's distance, live shares, and the distance to the target +(or the waypoint count when there is none). +**Enter** opens the trail map; **hold Enter** shares your position. > [!NOTE] > **Wio Tracker L2:** a real map with offline tiles on the SD card. Drag to @@ -122,8 +124,10 @@ sharing their position and the target. **Enter** opens the trail map; > Downloaded areas can be renamed, refreshed or deleted. > - **Live tiles**: with WiFi on, tiles for where you look are fetched and > cached, up to the size set in Settings › Storage. -> - **Vector regions**: whole regions as packs made with -> `tools/maps/osm_vector.py`, copied to the card. +> - **Vector regions** (only in a build with `-D MAP_VECTOR`, unfinished): +> whole regions as packs made with `tools/maps/osm_vector.py`, copied to +> the card. > > The minimap on the home screen shows your surroundings at a glance; tap it -> for the full map. The **Nodes** map shows every node with a position. +> for the full map. The **Nodes** map is the same map with every node that +> has a position on it; Back returns to Nodes. diff --git a/docs/solo/settings.md b/docs/solo/settings.md index 518fdaae..fdece2af 100644 --- a/docs/solo/settings.md +++ b/docs/solo/settings.md @@ -7,11 +7,11 @@ board supports are shown. | Section | What's there | | ------- | ------------ | -| **Display** | Brightness, auto-off, lock screen and [PIN](./lock.md), battery as icon / % / volts, clock format and seconds, wake on message; on e-ink also rotation and full refresh | +| **Display** | Brightness, auto-off, wake on message, lock screen, the lock clock's look and the [PIN](./lock.md), battery as icon / % / volts, time zone, clock format and seconds; on e-ink also rotation and full refresh | | **Sound** | Buzzer on / off / auto (quiet while the app is connected), volume, quiet hours, the melody for messages, channels and adverts | | **Home Pages** | Order of the home pages, and which are shown | | **Radio** | TX power, preset, frequency, SF / BW / CR, saved presets, Auto pwr, the scope list | -| **System** | Device name, time zone, low-battery shutdown, GPS power saving, units, reboot | +| **System** | Device name, low-battery shutdown, GPS power saving, units, the battery curve, reboot | | **Keyboard** | ABC or T9 layout, the two scripts, CardKB mode | | **Contacts** | Show all or favourites only (DMs, channels, rooms), favourites on top, contact expiry and prune | | **Messages** | Automatic resend of direct messages, the ten quick messages | @@ -27,12 +27,17 @@ A few notes: types the same name gets the same scope; it isn't encryption. - **Low battery** shuts the device down at the voltage you choose, which is also 0 % on the battery indicator. +- **Batt curve** sets the cell voltage at 0, 10 … 100 % for a battery that + doesn't follow the usual LiPo curve: **Left / Right** move a point by + 10 mV, **Reset** goes back to LiPo. The current voltage is shown, so a point + can be set against what the battery reads. > [!NOTE] > **Wio Tracker L2:** one list of pages: > > - **Device**: Display (including the lock and **Tap to wake**), Home apps, -> Power (battery, GPS), Sound (with the melody editor), Keyboard, Messages +> Power (battery, GPS, and the **Battery curve** as a chart whose points you +> drag), Sound (with the melody editor), Keyboard, Messages > & contacts. > - **Connections**: Radio, Bluetooth, WiFi, GPS. > - **Map & data**: Map (trail, live sharing and arrival alert options), diff --git a/docs/solo/tools.md b/docs/solo/tools.md index 75122853..938f896c 100644 --- a/docs/solo/tools.md +++ b/docs/solo/tools.md @@ -1,8 +1,10 @@ # Tools On joystick devices, the tools are in **Tools**, grouped into Location, Comms -and System. The navigation tools are on the [Navigation](./navigation.md) -page, Nodes and Admin on [Contacts](./contacts.md). +and System; the Tools home page keeps the two you used last. The navigation +tools are on the [Navigation](./navigation.md) page, Nodes and Admin on +[Contacts](./contacts.md); the [Status](#status) screen opens from its own +home page. > [!NOTE] > **Wio Tracker L2:** the tools are apps on the home screen: Messages, Nodes, @@ -12,8 +14,9 @@ page, Nodes and Admin on [Contacts](./contacts.md). ## Clock -The **Clock** home page shows the time, the date and up to three fields you -choose (hold Enter): battery, temperature, humidity, pressure, altitude +The **Clock** home page shows the time with a bar under it that fills with +the seconds (Settings › Display › Clock seconds), the date, and up to three +fields you choose (hold Enter): battery, temperature, humidity, pressure, altitude (barometric or GPS), light, CO₂, GPS position, satellites, contacts, unread messages. The time comes from GPS or the phone app; the time zone is in Settings. @@ -73,7 +76,7 @@ it off; **Network = Current** relays on your own frequency instead. Optional filters keep a mobile repeater from adding noise: skip adverts, a maximum hop count, **Yield** (let fixed repeaters go first), a minimum SNR, drop duplicates already relayed by someone else, and relay only your -**scopes**. Diagnostics shows how much it forwards. +**scopes**. The Status screen's **Mesh** tab shows how much it forwards. ## Ringtones @@ -84,31 +87,32 @@ single contact or channel from its options. > [!NOTE] > **Wio Tracker L2:** the melody editor is under Settings › Sound. -## Diagnostics +## Status -**Tools › Diagnostics** shows live counters (packets received and sent by -type, forwarded, errors), memory, the radio's noise floor and the last -packet's signal; a **System** tab with the firmware and radio settings; and a -**Font** tab with a sample of every script the font covers. Hold Enter on the -live tab to reset the counters. +The **Status** home page sums up the radio, GPS, battery and mesh in four +tiles; **Enter** opens the Status screen, one tab per subject (**Left / +Right** between them, **Up / Down** scrolls): + +| Tab | Shows | +| --- | ----- | +| **Radio** | Frequency, SF / BW / CR, TX power, the noise floor over the last half hour, the last packet's signal | +| **GPS** | On / off (**Enter** switches it), fix, satellites, position, altitude, speed, precision, time to first fix | +| **Sky** | The satellites on a sky plot, or each one's signal as bars (**Enter** swaps them); Wio Tracker L1 | +| **Power** | Battery level, voltage, source and trend, then the readings of any sensors | +| **Mesh** | Packets received and sent with a traffic line, forwarded, nodes heard, contacts; **hold Enter** resets the counters | +| **System** | Uptime, firmware, device, memory, the send queue, errors, and a sample of every script the font covers | + +**GPS pwr** in Settings › System turns the GPS off between fixes to save +battery; anything that needs your position (the trail, live share, the +locator) keeps it on. > [!NOTE] > **Wio Tracker L2:** the Diagnostics app, with a **Noise** tab that -> measures the noise floor over time. +> measures the noise floor over time, and the **GPS** app, which draws a sky +> plot of the satellites and each one's signal strength. ## GPIO *Wio Tracker L1 only.* **Tools › GPIO** sets four spare pins as input, output or (GPIO1–2) analog input, shows their level and switches outputs. The bot's `!gpio1`…`!gpio4` commands read and set the same pins. - -## GPS and sensors - -The **GPS** home page shows the fix and satellites; **Sensors** shows the -readings of the sensors the board has. **GPS pwr** in Settings › System turns -the GPS off between fixes to save battery; anything that needs your position -(the trail, live share, the locator) keeps it on. - -> [!NOTE] -> **Wio Tracker L2:** the **GPS** app draws a sky plot of the satellites and -> each one's signal strength.