192 Commits
Author SHA1 Message Date
JakubandClaude Opus 5.5 ada5b8e545 refactor: one copy of shared logic and widgets; GPS is asked for, not switched on silently
Duplicates found between the L1 and L2 frontends, and inside the L2 one:
- geo::fmtLocShare / fmtLatLon / turnDeg / isAhead (GeoUtils.h): the [LOC]
  text was built in five places, the turn angle and its "ahead" threshold in
  both navigations, coordinates by hand in nine. Tested.
- LiveShareEngine::setEnabled: live share was switched in three places.
- L1 waypoint share uses WaypointModel::shareText; Trail's "Share my pos"
  goes through UITask::quickShareMyLocation, so it now sends to a running
  live-share session as the home Map page does.
- L2 Widgets.h: switchCreate (one switch size, was four), switchRow with a
  state and callback (16 hand-wired copies), switchRowOpens (Bluetooth, WiFi,
  GPS), primaryButton (one height for Save / Measure / New area / Update).

GPS: with it off, starting the trail, live share or track back, sharing or
marking a position, or centring the map asks first ("GPS is off") on both
L1 and L2; Cancel leaves it undone. A share or a mark waits for a fresh fix
(a switched-off module may still report its last one), which also fixes the
L1 "Share my pos" sending a stale position. SOS still turns the GPS on itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 10:32:23 +01:00
JakubandClaude Opus 5.5 781a480aef feat(l2): settings put in one consistent order and look
Settings: Name and Radio first, then Bluetooth, WiFi and GPS side by side
(a tap on each row opens its details: the pairing PIN, the networks, the GPS
screen with a new Options tab for power saving and the fixed position), then
Device, Mesh & data (Adverts & privacy now holds Auto-advert) and System.
Time & units, Power as one group. Row symbols get a column of their own, value
labels are as wide as their text, group headings are uppercase everywhere, the
auto-add node types show only with "By type". SOS in three groups, WiFi with
its switch, Map tools with the layers (Packet flow among them) under the trail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 09:54:08 +01:00
JakubandClaude Opus 5.5 d3baeadb40 feat: SOS (experimental), issue #56: a countdown, then the position to chosen channels and contacts, repeated until someone answers
L1: Tools > SOS, Back held 3 s. L2: the SOS app, the top button held 5 s
opens a slider over everything, the lock screen and a PIN too. Off by default.
The ACK word stops the repeats; who answered, what they wrote and when show on
Answered, and whoever answered needs no word after that. Beep plays
... --- ... at full volume until it's ended. While one runs the screen goes off
by 30 s, the GPS stays awake past its duty cycle until nothing more will be
sent, the repeater and the L2's WiFi rest. A received SOS gets a banner and a
place on the map, past Track loc, for 24 h.

The lock screen's slider restyled with it, shared as slideBar() / slidePoll();
the L2's Favourites and SOS pickers share pickContacts(). The engine is
ui-core/SosEngine.h, tested on the host. The message's format isn't final.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 23:27:33 +01:00
JakubandClaude Opus 5.5 94a8f8fe72 feat(bot): Allowed commands per channel, room and direct, Position = Fav, Reply gap, commands only at the start of a message
!loc off is the switch for the position: !status answers without it, !dist
is off and !gps fix answers "GPS: fix off". !help is built from the table.
ui-core/BotCommands.h, tested on the host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 23:25:22 +01:00
JakubandClaude Opus 5.5 bf7b262645 feat(l1): messages kept on flash across a power-off, and "Powered off" on e-ink
Settings > Messages > Keep messages (Off, 500, 1000, 2500 in all; off by
default; HIST_FLASH, ui-core/HistoryLog.h). Two append-only logs on the QSPI
flash, channels and DMs, restored into the RAM rings at the start. A batch is
written a minute after the first unsaved change and at shutdown, as the L1's
power switch gives no warning. Each segment has a directory of its own: a
LittleFS 1.x commit erases one of a directory's two fixed blocks every time.

E-ink panels keep their last frame, so a shutdown now leaves "Powered off" on
it and puts the controller into deep sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:46:43 +01:00
JakubandClaude Opus 5.5 3a26a8bee7 fix: review pass - Discover's late replies dropped and its way back usable, the Gallery's newest first and faster, the network clock's toast
- Discover: a reply after its try timed out, was stopped or was overtaken
  went on to the normal handling and became the contact's route (and sent
  a path back); the last tags sent are kept and a late reply is dropped.
  Leaving Route on the L2 stops a discovery as it stops a trace.
- Discover: a route whose reply came back another way offers that way too
  (L2 There / Back, L1 a Back row), turned round into a route there, so a
  trace checks it; the Discover button no longer sits on its group.
- Screenshots: numbered one past the highest (one pass over the folder,
  not a stat per number), so one taken after a delete is still the newest.
- Gallery: the newest 300 kept whatever order the folder lists them in;
  BMP rows read in the file's order and several at a time; the thumbnail
  buffer sized to the page; the folder read once per visit; a failed
  open frees or restores the picture.
- NTP: the slot the router's server goes in emptied before joining, so a
  cached address isn't taken for it; "Clock set from the network" judged
  against the clock a tick before (SNTP has set the system time already).
- Sim: sim_scroll up stops at the top.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 16:30:19 +01:00
JakubandClaude Opus 5.5 e154a4e721 feat(l2): Gallery app (screenshots as thumbnails, full view with swipe and delete, the saved trails), the clock from NTP while WiFi is up (the router's server from DHCP first), tabs switch on release, Home apps out of Settings
- Gallery: thumbnails 30 to a page, built only while the screen is still (a decode held the loop and a scroll read as a tap)
- segmented(): CLICK_TRIG, so a swipe starting on a screen's tabs doesn't switch them
- Settings > Device > Home apps removed (hold an app on Home instead)
- platformio.ini: a note that the L2 has no microphone on GPIO15 (verified on hardware)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 15:39:56 +01:00
JakubandClaude Opus 5.5 cdc2ff25c9 feat: summer time - Settings > Summer time (Europe, North America, Australia, New Zealand) puts the clock an hour ahead and back by itself; every local time goes through tzHoursAt(), the alarm keeps its time across the change (a skipped time rings an hour later, a repeated one once)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:09:25 +01:00
JakubandClaude Opus 5.5 c46a0a2b55 feat(l2): keyboard - a second symbols page behind #+= with the brackets and the rest of ASCII ([ ] { } < > \ | ~ ^ ` $ and a few more)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:09:25 +01:00
JakubandClaude Opus 5.5 cce2798d2d feat(route): Discover - path discovery from the device, 1/3/5 tries 20 s apart, the routes found to use in the route editor
MyMesh::sendPathDiscovery() shares the request with the app's
CMD_SEND_PATH_DISCOVERY_REQ and hands the reply (the way there and back)
to the UI; PathEditor keeps up to 4 distinct routes with how often each
came. L2: Find the route under Route; L1: Discover row in Path / trace.
Docs: Discover, message routes on the map, Ask status and discovery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 23:09:23 +01:00
JakubandClaude Opus 5.5 f4ad1bd643 feat(l2): recent packets on the map - the flow legend's tap lists the last 10 placed packets, a tap plays one again, Play all plays them in turn
PacketFlow keeps them (each with up to 3 ways it came, contacts by key
prefix) once a frontend asks, in PSRAM; the map frames a replay that's off
screen. Back on the map closes a popup first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 22:40:30 +01:00
JakubandClaude Opus 5.5 c1af501cc4 fix(l2): a map line starts from the middle of the own-position and node dots
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 20:42:36 +01:00
JakubandClaude Opus 5.5 80580ead54 fix: review pass - options menu room for Show route, 'known route' for a direct-routed !path, 3-byte hashes, a channel's route not from here, bot sender looked up once, no decimal times as routes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 20:06:03 +01:00
JakubandClaude Opus 5.5 8aec54b7e5 feat(bot): a Log tab with the bot's last 32 replies (ESP32 and the L2 sim)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 19:59:19 +01:00
JakubandClaude Opus 5.5 30ebef765f feat(bot): {path} !path (#55), {snr} {rssi} !snr, !dist, Actions by All/Fav
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 19:46:28 +01:00
JakubandClaude Opus 5.5 81c551425e feat(ui): a route written in a message shown on the map (L2 Route, L1 Show route)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 19:46:28 +01:00
JakubandClaude Sonnet 5.5 2ae55e97ac fix: review pass - storage unmount timeout, nav dial animates, dial text room, nearby name width, Simpson Enter with another key, GPS chip
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 10:12:56 +01:00
JakubandClaude Sonnet 5.5 e6ae1d63b8 fix(l2): the top button wakes the screen at once, switches it off on letting go
A press that silenced the alarm, took a screenshot or woke the screen doesn't
also switch the screen off when it's let go.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 21:33:59 +01:00
JakubandClaude Sonnet 5.5 9c40c83f4a fix(l2): the chat rows' preview isn't cut at the bottom
The font's line is 18 px (emoji and fallback glyphs), the subtitle label was a
fixed 15: the tails of y, g, j and emoji were cut. Now 18, the title and the
subtitle 1 px further apart; the row stays 44.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 21:33:59 +01:00
JakubandClaude Sonnet 5.5 15ac4d8f83 feat(l2): a turn dial in the navigation bar
An arrow at the target on a round dial whose top is the way you're heading:
turn until it points up. It turns green and the ring doubles when you're
within 12 degrees. The text says how far to turn ("turn right 55") instead of
two bearings to subtract. Standing still there's no course: the arrow greys
out, the top is north and marked red, and the text keeps the bearing.

sim_nav_target() sets a target from the simulator page.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 14:47:51 +01:00
JakubandClaude Sonnet 5.5 c5da3ecdea fix(l2): a banner or toast doesn't wait on a sleeping screen to be hidden
LVGL's timers stand still while the screen sleeps, so a message that arrived
with wake-on-message off (or in quiet hours, or with a client connected) left
its banner up until the next wake. No banner is shown while asleep now, and
sleep() hides a banner or toast that was up.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 19:29:00 +02:00
JakubandClaude Opus 5.5 1552ca4383 fix(l2): the battery shows an icon, a percentage or a voltage, not the icon too
Battery display's percent and voltage modes still drew the icon before
the number. Each mode now shows one thing; the title bar no longer has a
battery level to fold away, so only the button words give way to a title.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 23:00:52 +02:00
JakubandClaude Opus 5.5 b44ee6a599 feat(status): the path hash size on Status > Radio (L2: Diag > Radio)
Bytes per repeater in a path we send (Settings > Radio > Advanced), next
to the TX power.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 23:00:52 +02:00
JakubandClaude Opus 5.5 24156769f0 fix(bot): !temp and {temp} fall back to the chip's temperature
Same gap as the screens had: the bot reply, a typed message's {temp} and
the placeholder lists read only the sensors, so a board without one (the
L1) answered !temp with n/a while its telemetry carried a temperature.
The fallback moves to LocalSensors.h, shared by the screens, expandMsg()
and sensorPlaceholders(); the latter now takes the chip's temperature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:55:19 +02:00
JakubandClaude Opus 5.5 21feec0972 fix(l2): wait out the tile being read before the SD card is unmounted
USB drive and Format card closed the open map pack and unmounted, while the
tile task could still be reading a tile off the card (a map left open, a
prefetch). Both now wait for it first, as the map's own redraw does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:52:11 +02:00
JakubandClaude Opus 5.5 d2e1f086e2 fix(ui): the chip's temperature when no sensor reads one
The telemetry reply adds the MCU temperature, the screens read only the
sensors: on a board without a temperature sensor (the L1) the app showed
a temperature and the clock field '--'. The clock, Status and the L2's
Home now fall back to the chip's, like the reply. The bot's !temp and
{temp} still read only the sensors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:33:52 +02:00
MarekZegare4andClaude Sonnet 5.5 1683be63ca fix(l2): title bar fits its title - the battery level, then button words, give way
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 12:58:04 +02:00
JakubandClaude Opus 5.5 1f47fc56cd fix(route): a stored route longer than the editor's 7 hops can't be saved cut short
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 18:41:18 +02:00
JakubandClaude Opus 5.5 d85a3a1eef fix(map): L2 packet flow lines meet the marks too - PacketFlow::pointNow()
A flow's point is where its contact is now, its end here where you are now
(GPS, else the position set in Privacy): shared by the L2 map and the
OLED / e-ink Nodes map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:42:14 +02:00
JakubandClaude Opus 5.5 f6c0a2f021 refactor(companion): the app's links through upstream's MultiSerialInterface
- Bluetooth + USB (+ WiFi/Ethernet/UART per build) in one interface_manager,
  as upstream; frames go to every enabled link, USB is read while BT is
  connected. DUAL_SERIAL now means ENABLE_USB_INTERFACE.
- WiFi interface with upstream's wifi_* prefs and set/get wifi.* CLI.
- isClientConnected moved into ArduinoSerialInterface (DTR on nRF52 and
  ESP32 native CDC).
- UI uses isBluetoothEnabled/enableBluetooth/disableBluetooth; turning BT
  off leaves USB and the other links on.
- DualSerialInterface removed.
- Sim build gains DynamicConfigSerializer.cpp (broken since bd64c203).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 14:04:58 +02:00
JakubandClaude Opus 5.5 d1fc6e3fdd fix(l2): Messages - "Read all" an icon, the title squeezed to "Me..." beside it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:53:22 +02:00
JakubandClaude Opus 5.5 b17f97c71f fix(l2): quick panel stalled and tore when pulled; GPS sky plot cut off
The panel froze and dimmed the screen as the finger started: a snapshot of
the whole screen (slow on the map) and a full-screen flush, so it stalled,
jumped and tore top to bottom. Now it slides opaque over the live screen
(a clear layer under it still takes the tap that closes it), built at start.
Its slide is timed by its own frames, at most 30 ms a frame: a slow frame
ended the 160 ms lv_anim and the panel just appeared.

The sky plot on GPS > Sky was a fixed 168 px, taller than what is left
under the title bar and tabs: now it takes that height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:24:52 +02:00
JakubandClaude Opus 5.5 743500761a feat(l2): light theme reworked - a tint for selected, grey values, quiet edges
The light theme read as the dark one inverted. Now something selected (a
tab, a segment, a tile, Fav) is a tint of the accent with the accent's text
(SEL_*), the full accent fill stays for the primary action; setting values
read in grey (VALUE); popups, the banner and the toast have a quiet grey edge
(EDGE), the toast is a dark pill; neutral greys the RGB565 panel keeps
neutral; the big clock graphite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:24:46 +02:00
JakubandClaude Opus 5.5 76e96f7eaa feat(l2): light theme
Settings > Display > Theme: Dark / Light (NVS mc_ui/light). The colour
tokens are set once before anything is built, so a change restarts the
device. Text on an accent fill is the new ON_ACCENT (it was BG, white
in the light theme); each accent has a deeper hand-picked light variant
that reads on white and takes white text. The map's empty-tile fill and
grid and the areas' outlines follow the theme too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:55:47 +02:00
JakubandClaude Opus 5.5 e5a55c3b1f feat: flashlight - the whole screen white at full brightness
L2: a Flashlight app on Home (a lightbulb icon added to the fonts): a
white layer over everything, the backlight at 100 %, no auto-off; a tap,
the side or the top button puts it away and the brightness back.
L1: Tools > System > Flashlight, the whole OLED lit at full contrast
until a key. Not on e-ink.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:55:01 +02:00
JakubandClaude Opus 5.5 06a188d572 fix(l2): quick panel - the screen showed through its rounded top corners
The panel starts a radius up, under the status bar, so its top corners
are hidden there instead of cut out over the frozen screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:54:56 +02:00
JakubandClaude Opus 5.5 b4ec5dcb54 feat(map): base layers - Topo, Light, Dark, Satellite, Esri Topo
Map tools > Layers > Map picks what the map is drawn from:
- Topo: OpenTopoMap, as before.
- Light and Dark: Esri's grey canvases, no labels, up to z16.
- Satellite: Esri World Imagery.
- Esri Topo.

Each layer has its own folder for downloaded areas (/sdcard/maps-light,
-dark, -sat, -esritopo; Topo stays in /sdcard/maps) and its own live-tile
cache. Live-cache records carry the layer.

Esri serves JPEG: decoded with LVGL's tjpgd (LV_USE_TJPGD), whatever the
file name says. The layer is kept in NVS (mc_ui/layer); switching waits
while a download or a deletion runs in the current folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:25:16 +02:00
JakubandClaude Opus 5.5 85ef06b6be feat(map): packet flow shows all traffic - kinds in colours, a legend, its own nodes
- Every packet heard is drawn, by kind in fixed colours: advert, DM,
  channel, request, ack, other, sent. One that can't be placed on the map
  is a ring at your own position.
- A legend pill at the top counts each kind over the last minute.
- On a map without node markers, a flow brings its own nodes (a dot and
  the name), fading with it.
- Copies of one packet (the same packet hash) share one fade, so a path
  goes out as a whole, not segment by segment.
- 32 flows kept on ESP32 (12 on nRF).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:24:24 +02:00
JakubandClaude Opus 5.5 2f2db6045c fix(l2): WiFi fails to start or join - big statics and task stacks to PSRAM
WiFi starts and joins on internal RAM: ~42 KB the first time, ~25 KB after,
more for WPA. Free internal RAM had shrunk to ~20 KB after opening the map
(the tile decoder's 12 KB stack, the 32 KB I-cache, the DMA draw buffers,
UI statics), so a scan failed at once (esp_wifi_init: no memory) and a join
during a tile download timed out (AUTH_EXPIRE).

- ESP-IDF: CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY, and the esp_timer
  task stack 8 -> 4 KB (it uses ~0.4 KB). Rebuild the framework libs:
  pio run -e Wio_Tracker_L2_idf_libs.
- PSRAM_BSS (EXT_RAM_BSS_ATTR) on the UI's big statics: QR codes, map
  state, charts, lists. .dram0.bss 115 -> 66 KB.
- The tile decoder's and fetcher's task stacks in PSRAM.

Free internal RAM, idle: 48 -> 105 KB; WiFi up: 57 KB, 29 KB at the
lowest while downloading tiles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:23:29 +02:00
JakubandClaude Opus 5.5 3825dcc077 fix(l2): fast typing - a second finger is a new tap, not a slide
With two thumbs the second lands before the first lifts; the panel's
first point then jumped to it and LVGL saw one press sliding from key to
key, losing the first letter (or starting a scroll). A new GT911 track id
is now a release, then a press. The keyboard no longer hands a rolling
finger to a scroll or gesture up the tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:51:03 +02:00
JakubandClaude Opus 5.5 c779bf46b5 feat(ui-lvgl): title bar with the clock, tidier controls, contextual nav bar
Density from less chrome instead of smaller rows (ROW_H stays 44):
- titled screens drop the status bar; the title bar (APPBAR_H) holds back,
  the title, the screen's actions and the time/battery on a pill; the status
  bar returns for Home, the map, typing, the quick panel and the lock
- one radius (RADIUS) for everything tapped: buttons, tabs, choices, chips
- tabs are all segmented at TAB_H in the body (GPS, Clock converted)
- Nodes: chips row + sort + status line become one toolbar row with
  Show / Order choices; Messages' All/Favourites is the same choice
- nav map: the target bar only while there is a target; the pin opens one
  "Places" popup; back from a map options page restores the map and Map
  tools as left, without a jump
- node detail actions at the top of the scroll; Home tiles fill the page
- rowsFit() leaves growing labels to the flex (a screen title cut to one
  letter after Messages' filter changed)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:51:03 +02:00
JakubandClaude Opus 5.5 a8440c890e feat(map): packet flow - what the radio hears, as lines between nodes
Every packet heard runs from its origin through the repeaters with a
position to this device; a packet sent is a ring. ui-core/PacketFlow.h
resolves them (UiCore::flow, MyMesh logRx/logTx -> Listener). ui-lvgl
draws them on the map's marker layer and repaints only their area while
they move; ui-new draws the last minute on the Nodes map ("Flow" in its
options). Setting: Map options > On the map > Packet flow, CLI map.flow.
Off by default. Sim-checked only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:50:43 +02:00
JakubandClaude Opus 5.5 120ddfc830 feat(route): trace per link, to the node or the last repeater, find where it stops; channel order re-sorts on entry
Core: PathEditor results are links (node k hearing k-1 and back); toNode()
off traces only the repeaters (a companion answers only with repeat on);
probe() traces to each repeater in turn after no reply; failures carry a
reason; an empty list saves "direct". PingEngine takes over a slot left past
its timeout. A kept route: the dropped heard path isn't announced to the app
nor bumps lastmod; an app update keeps the flag only if it leaves the route.
Marker boxes sized for every dot and name (overflow).

ui-lvgl Route: one line per node with out / back dB coloured by quality, tap
a hop to move / remove, tap the node to include it, Keep in the header, Find
where beside a no-reply status. ui-new Path: To node / Find break rows,
result alerts, cursor kept on its action.

Channels: ui-new re-sorts the list on entering it, cursor on the same channel.
Docs: Path and trace, Channel order. Sim hooks: open route, add channel,
open messages.

Checked in the browser sim (L2 + ui-new peer + repeater); not on hardware.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:20:55 +02:00
JakubandClaude Sonnet 5.5 24dd025086 feat(channels): Channel order setting - slots, newest message or name (#48)
Shared chanctl::order() builds the channel list for ui-new and the L2:
favourites first, then by ch_sort. New ch_sort pref at the end of NodePrefs,
Settings > Contacts row and contacts.channel.order CLI key.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 10:46:20 +02:00
JakubandClaude Sonnet 5.5 140ea7c008 feat(route): path editor with out-and-back trace and a kept route; map markers as one drawn layer
Core: PathEditor (UiCore::route) loads, edits, traces and saves the route to
a contact; MyMesh::sendTrace over an explicit route with per-hop SNRs,
setContactPath / setContactPinned. A route can be kept
(CONTACT_FLAG_ROUTE_PINNED, ContactInfo::flags bit 4): a path heard from the
node doesn't replace it and the last DM resend doesn't drop it.

ui-lvgl: Route screen (node detail), repeater picker by distance, picking
hops by tapping the nodes map (numbered badges, line, Undo / Done). The
map's markers are one drawn layer with hit-testing and name decluttering
instead of three objects per node.

ui-new: Path / trace view in the Nodes action menu; Add reuses the list
filtered to repeaters.

First cut: built for L2 LVGL, L1 OLED and L1 e-ink, tried on L2 only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 10:18:05 +02:00
JakubandClaude Opus 5.5 b9735b089e fix: missing returns, BIT macro clash, longer tile source URLs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:53:53 +02:00
JakubandClaude Opus 5.5 ec42a74ab6 perf: unused TinyUSB classes off on nRF52, SSD1306 sends only changed blocks, ESP32 loop yields when idle
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:30:46 +02:00
JakubandClaude Opus 5.5 2b9e013071 fix(l2): no remount while the card is a USB drive, vector packs locked across cores, time zone list, noise sweep restore
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:30:46 +02:00
JakubandClaude Opus 5.5 57db27512d fix(companion): pack and history files from the card checked, contact loops skip the reserved slots, small UI fixes
- L2 vector packs: a damaged count can't wrap the index size, and an
  entry pointing past the file is refused.
- L2 map share-target list: sized for 40 long channel names and 16
  favourites (it could overflow), off the stack.
- L2 SD history: a file with an unreadable header is set aside as .bad
  instead of written over; Delete message history takes those too.
- Contact lookups by key or hash start after the reserved anon slots (an
  empty one matched a 00 hop hash with a blank name); MessagesScreen uses
  contactctl::hopName().
- Nearby keeps its selection by public key: deleting a contact shifts
  the table.
- ui-new Live Share target cycle holds every channel and favourite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:31:35 +02:00
JakubandClaude Opus 5.5 01a068be7d refactor(companion): shared shutdown steps, SD channel key by secret, fetch race, small UI fixes
- UITaskBase holds what both UIs' shutdown() and low-battery check share:
  the saves before the goodbye sound, the power-down (GPS through its
  provider) and the battery EMA and threshold.
- L2 SD archive: a channel's file is keyed by its secret only, so renaming
  keeps the history; old files are renamed once at boot.
- L2 fetch: abandoning a request and the task finishing it are one critical
  section (it could stay DONE for good); TileCache gets the read-side barrier.
- Text from a repeater or sensor no longer rings on the device (nothing to
  open); a settings switch reads any non-zero value as on; the message
  toast never cuts a letter in half; ui-new's GPS helpers ask UiCore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:08:31 +02:00