Commit Graph

15 Commits

Author SHA1 Message Date
Jakub
92643d1721 fix(ui): scale trail-map markers for e-ink, add wrap-around nav
Trail map dots/diamonds/cross/start markers and the north indicator were
drawn as raw unscaled pixels, so they shrank to near-invisible specks on
landscape e-ink's larger font scale; they now route through the mini-icon
framework (icons.h) like the rest of the UI, and the grid intersection dots
scale with it too. The keyboard's preview/grid separator had the same bug
(hardcoded 1px) and now uses display.sepH().

Also makes UP/DOWN (and the keyboard's LEFT/RIGHT/UP/DOWN) wrap top<->bottom
across every list, menu and form selector, matching the behavior PopupMenu
already had.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 09:16:57 +02:00
MarekZegare4
8c0ccaed73 feat(ui): keyboard overhaul — shared instance, icon keys, symbols page
- Unify on the shared keyboard: WaypointsView drives UITask::keyboard()
  instead of its own instance; openKb() clears {loc}/{time} for literal
  fields (labels, coordinates). Reclaims the duplicate widget from the heap.
- Icon glyphs on the special row: caps ⇧, space ⎵ (two halves), delete ⌫,
  OK ✓ (reuses ICON_CHECK); {} and the page toggle stay text.
- Second character page (symbols), toggled by a "#@"/"abc" key. Tidy the
  letters page: drop the duplicate grid space, add the comma, group
  punctuation as . , ! ?
- Harden the preview buffers (KB_PREVIEW_CAP) against very wide displays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 10:47:50 +02:00
Jakub
daaa5b1503 fix(messages): allow full-length text on the compose/send paths too
After widening the history buffers, the compose side was still the
bottleneck: the keyboard capped input at 139 bytes and the quick-message
expand buffers were 140. Raise KB_MAX_LEN to 160 (MeshCore's MAX_TEXT_LEN)
and size the expand/compose buffers to MSG_TEXT_BUF, so a message can be
typed, expanded, sent, stored and displayed at the full protocol length on
every path.

The custom-message editor now passes an explicit max bound to its 140-byte
store, so the wider keyboard buffer can't overflow it; the bot editor
already passed per-field maxima.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 12:15:30 +02:00
Jakub
d981f93e6e refactor(ui): drawSelectionRow helper for the 5-line invert/restore pattern
Eight screens repeated the same if/else block to invert the row
background for selected items. Add DisplayDriver::drawSelectionRow that
sets LIGHT, optionally fills the rect, and leaves the colour as DARK
when sel (so the caller's text renders inverted). 61 lines removed
across SettingsScreen, KeyboardWidget (cells + special row), ToolsScreen,
DashboardConfigScreen, BotScreen, RingtoneEditorScreen (note slots +
menu), NearbyScreen, QuickMsgScreen (4 list views).

Card-style rows (QuickMsg hist, NearbyScreen discover, RingtoneEditor
notes display) keep their original drawRect/partial-fill outline for
unselected — they don't match the simple-invert pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 20:33:02 +02:00
Jakub
5fde79fae7 fix(ui): translate keyboard preview buffer through UTF-8 handler
KeyboardWidget printed the text preview directly via display.print()
without calling translateUTF8ToBlocks first. When a reply prefix
contained a UTF-8 sender name (e.g. Cyrillic), raw multi-byte sequences
reached the display driver on non-Lemon renders.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:28:10 +02:00
Jakub
b279b95b2d refactor(ui): apply code review fixes — bugs, risk, optimisations, cleanup
Fixes 7 bugs (timing UB on unsigned long, abs() no-op, XBM CRC PROGMEM
scan, CayenneLPP heap thrash ×2, UTF-8 reply prefix, lock-seq reset on
wake), 3 risk items (notif melody stop guard, bot trigger pre-lowercase,
lock-seq cleared on display wake), plus optimisations (fmtMsgAge/
getTextWidth caching, RTTTL builder consolidated to NodePrefs, HP_*
constants and homePageLabel table moved to NodePrefs, DataStore flat
lambda schema, translateUTF8Static factored out) and minor cleanup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 20:03:45 +02:00
Jakub
9c671891d9 fix: e-ink portrait/landscape layout — separators, battery, keyboard, screens
- DisplayDriver: add sepH() (2px landscape, 1px OLED); fix transliterateCodepoint
  fallback '?' (was '\xDB' which broke UTF-8 word-wrap and rendered tiny block char)
- GxEPDDisplay: drawRect draws double border on landscape for visible 2px weight
- UITask: navigation dots scale with lh; content_y saves 16px by using dots_y+6;
  battery iconW=lh*2, fill margin bm scales with orientation; indicator spacing fixed;
  clock separator uses sepH(); alert popup tight and vertically centred
- KeyboardWidget: compact cell height (no stretch), multi-line preview, cursor always
  on last visible line
- BotScreen / NearbyScreen detail: use lineStep() as natural item height, shrink only
  when items don't fit (fixes portrait stretch)
- QuickMsgScreen: send button pinned to display bottom (height-lh-2), not floating
- SettingsScreen: AUTO_OFF guarded with #if AUTO_OFF_MILLIS>0; default sel=AUTO_LOCK
- All screens: separators updated to sepH()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 23:13:27 +02:00
Jakub
118f29b0a1 fix: landscape e-ink layout corrections — clock overlap, keyboard overflow, bar sizing, nearby detail
- GxEPDDisplay: fontAscender only applies to sz=1 with Lemon; sz=2 (NULL font)
  was incorrectly getting a 16px cursor offset, causing clock text to render
  16px lower than expected and overlap the date line
- KeyboardWidget: compute cell_h from available screen height instead of lh+1;
  tighten sep_y to lh so the grid fits within 122px even with Lemon font (lh=20)
- SettingsScreen renderBar: constrain box size to available width so the 5th
  buzzer-volume square doesn't overflow past the right edge with Lemon font
- NearbyScreen discover detail: manually truncate b64 public key by charWidth
  to guarantee one-line rendering; use dynamic step = (height-hdr)/5 so
  Status line doesn't fall off the bottom of the screen
- NearbyScreen contacts detail: merge dist+az into one line and use dynamic
  step to fit 5 lines within the display; removes the off-screen Seen: row
- AutoAdvertScreen: replace lineStep() gap before hints with 4px fixed gap
  so both hint lines fit within the display with large fonts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 19:11:25 +02:00
Jakub
1d8ca25469 fix: adaptive layout for e-ink landscape across all remaining screens
- GxEPDDisplay: sz2 uses 4× scale on landscape (clock 32px vs body 16px)
- UITask: clock date_y and splash date_y computed from lh2 after setTextSize(2)
- UITask: battery/mute/BT/advert indicators scale with lh; muted uses text 'M'
- UITask: hibernate hint split into two lines to prevent wrapping
- ToolsScreen: full refactor — headerH, listStart, lineStep, getCharWidth
- KeyboardWidget: all cell sizes computed from display metrics (cell_w, cell_h, spec_w)
- RingtoneEditorScreen: cell_w = charWidth×2+6 (was hardcoded 18)
- SettingsScreen: BRIGHTNESS hidden on e-ink; renderBar boxes scale with lh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:34:20 +02:00
Jakub
7b63af1068 refactor: use PopupMenu in keyboard and context menus, fix bugs
- KeyboardWidget: replace inline placeholder overlay with PopupMenu
- UITask QuickMsgScreen: replace inline CONTACT_PICK/CHANNEL_PICK context
  menus with PopupMenu; notif label stored in _ctx_notif_item at open time
- BotScreen: clear placeholder list for trigger field (expansion tokens
  would never match incoming literal text)
- MsgExpand: fix APPEND macro off-by-one (oi+_l < out_len-1 → < out_len)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 08:06:26 +02:00
Jakub
42b51935b1 feat: sensor placeholders in messages and keyboard picker
expandMsg now expands {temp}, {hum}, {pres}, {batt}, {alt}, {lux}, {dist},
{co2} from live sensor readings. The [{}] picker in the on-screen keyboard
shows only sensors currently detected by SensorManager and scrolls when
more than 3 items fit the overlay.

New SensorPlaceholders.h helper keeps sensor-to-keyboard wiring out of
UITask.cpp. MsgExpand.h handles all expansion logic centrally; MyMeshBot
and QuickMsgScreen pass &sensors and batt_volts to each call.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:12:07 +02:00
Jakub
4063c2d296 style: shorten Del label to [Dl] to fit 25px special row cell
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:09:47 +02:00
Jakub
464f5cd7a2 fix: remove label prefix from keyboard preview for visual consistency
All three keyboard instances (Settings, QuickMsg, Bot) now show plain
text + cursor without any field-name prefix. Removes the label field
from KeyboardWidget entirely — the screen title already indicates context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:09:47 +02:00
Jakub
5fecafd4f9 fix: KeyboardWidget preview buffer size and KEY_CONTEXT_MENU handling
- preview[] increased from 32 to 40 bytes to safely fit max label (15 chars)
  + 20 chars text + cursor + null without snprintf truncation
- KEY_CONTEXT_MENU (long-press ENTER) now treated as CANCEL in keyboard
  input handler, restoring BotScreen behavior lost in the refactor

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:09:47 +02:00
Jakub
07bd5f1167 refactor: extract on-screen keyboard into reusable KeyboardWidget module
All three keyboard implementations (SettingsScreen, QuickMsgScreen, BotScreen)
now share a single KeyboardWidget struct defined in KeyboardWidget.h, eliminating
~480 lines of duplicated render/input logic. Also fixes the SettingsScreen bug
where navigation keys were checked before the placeholder overlay, causing cursor
movement when the overlay was open.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:09:47 +02:00