Commit Graph

2881 Commits

Author SHA1 Message Date
Jakub
4d163cda49 chore: bump build date to 19 May 2026; fix UTF-8 ellipsis truncation
Fix drawTextEllipsized to strip orphaned UTF-8 leading bytes after
byte-at-a-time trimming, preventing an invisible 6px gap before "..."
when truncating non-ASCII names.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wio-tracker-lemon-v1.15-plus.1.7
2026-05-19 10:25:25 +02:00
Jakub
0b3477daeb Merge wio-tracker-l1-improvements into font-experiments
Brings in reply feature (@[nick] format), screen lock auto-lock, README
updates, and scroll-arrow overlap fix (FS_CHARS_MAX kept at 80 for
pixel-accurate wrapping). FullscreenMsgView conflict resolved by
preserving font-experiments' DisplayDriver-based wrapLines and dynamic
lineH while adding wio-tracker's @[nick] header parsing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 09:40:32 +02:00
Jakub
02fd79d567 docs: update README with reply feature and screen lock
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:33:04 +02:00
Jakub
0f5740f6b6 fix: remove redundant slen clamp and update stale comment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:20:42 +02:00
Jakub
34cfd27b8a fix: use @[nick] format for replies and fix fullscreen message display
- Reply prefix changed to "@[nick] " format — bracket delimiter handles
  nicks with spaces unambiguously
- FullscreenMsgView: parse "@[nick] body" to show "To: nick" header;
  fall back gracefully if format not matched
- Reduce FS_CHARS 21→20 to prevent scroll arrows overlapping last char
- Transliterate nick before displaying in "To:" header and "RE:" title
  so non-ASCII characters render correctly on the OLED font

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:18:45 +02:00
Jakub
b21bcb5ca4 fix: render reply popup in CHANNEL_HIST and DM_HIST phases
_ctx_menu.render() was only called in CONTACT_PICK and CHANNEL_PICK,
so the reply popup was active but invisible in history views. Added
render calls for list view and fullscreen view in both DM_HIST and
CHANNEL_HIST phases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 16:11:25 +02:00
Jakub
6f7de3ed20 feat: add reply action to channel and DM message history
Long-press Enter (KEY_CONTEXT_MENU) on a selected message shows an
'Options / Reply' popup in both list and fullscreen views. Confirming
opens MSG_PICK with 'RE: nick' title — the reply can be sent via
keyboard or quick message templates, both automatically prefixed with
'@nick '.

- Channel: reply prefix extracted from 'sender: message' format
- DM: reply available only on incoming messages, uses contact name
- FullscreenMsgView: REPLY added to Result enum, KEY_CONTEXT_MENU handled
- MSG_PICK: _reply_mode flag routes prefix through keyboard and templates
- Guard: prevent sending empty reply (prefix-only keyboard input ignored)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:12:11 +02:00
Jakub
8f566732ed feat: show @recipient as 'To: nick' bar in fullscreen message view
When a message starts with @nick, the fullscreen view expands the header
to show a second row 'To: nick' below the sender name, and displays the
message body without the @nick prefix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:00:01 +02:00
Jakub
14bf908f3f refactor: clean up SH1106Display and CharTestScreen
- Remove redundant translateUTF8ToBlocks override (now same as base class)
- Remove cp437/setTextColor/setTextSize calls from startFrame (unused since print() is overridden)
- Simplify setTextSize (both branches were identical)
- CharTestScreen: update comment, use UTF-8 literals for Greek, fix refresh rate 500→2000ms

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 13:39:01 +02:00
Jakub
7bba82f7ce fix: experimental workflow builds only Wio Tracker L1 firmwares
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
companion-experimental-v1.7
2026-05-18 10:26:46 +02:00
Jakub
290ff63174 fix: exclude companion-experimental-* tags from regular firmware build
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 10:19:29 +02:00
Jakub
d3b2480fdb refactor: remove transliteration from DisplayDriver base class
Lemon font supports Latin Extended, Greek, and Cyrillic natively,
so transliteration to ASCII is not needed. SH1106Display overrides
translateUTF8ToBlocks to pass UTF-8 directly to the Lemon renderer.
The base class implementation is now a simple pass-through copy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 10:08:50 +02:00
Jakub
340b4854f1 Merge wio-tracker-l1-improvements into font-experiments
- DataStore.cpp: persist auto_lock setting across reboots
- MyMeshBot.h: fix bot responding when disabled (missing bot_enabled check)
- QuickMsgScreen.h: fix msg buffer too small for 140-byte templates
- DisplayDriver.h: add European language transliterations (kept for non-Lemon displays)
- FullscreenMsgView.h: keep pixel-accurate word-wrap (font-experiments)
- SettingsScreen.h: keep dynamic layout via _vis/_item_h (font-experiments)
- UITask.cpp: remove stale placeholder comment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 10:04:56 +02:00
Jakub
9b61bc3028 fix: increase quick-message expansion buffer from 80 to 140 bytes
custom_msgs templates are up to 140 chars; the 80-byte msg[] buffer
silently truncated any message longer than 79 characters before sending.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:53:36 +02:00
Jakub
584ef33b3e fix: channel bot respects bot_enabled flag
tryBotReplyChannel checked bot_channel_enabled but not bot_enabled,
so disabling the bot via the main Enable toggle had no effect on
channel replies. Added bot_enabled to the guard condition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:41:56 +02:00
Jakub
4df97ae5ed fix: persist auto_lock setting across reboots
auto_lock was defined in NodePrefs but missing from both loadPrefsInt
and savePrefs in DataStore.cpp. Added at the end of the serialization
chain (inside if(file.available())) for backwards compatibility with
existing saved files — old files default to auto_lock=0 (disabled).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:39:10 +02:00
Jakub
25a7831f95 ci: add experimental companion firmware build workflow
Triggers on tags matching companion-experimental-* pushed from the
font-experiments branch. Appends -experimental to the version string
so all output filenames are clearly distinguishable from stable builds.
Creates a separate draft release labeled "(Experimental)".

Usage: git tag companion-experimental-v1.x.x && git push origin companion-experimental-v1.x.x

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:35:22 +02:00
Jakub
de8861f574 fix: draw substitution block for unsupported characters in SH1106 Lemon renderer
- drawLemonChar: for codepoints outside the font range (> U+04FF) that
  are printable (>= U+0020), render a 4×6 filled rectangle instead of
  silently advancing the cursor with no visible output
- decodeUtf8: properly decode 4-byte UTF-8 sequences (U+10000+) to their
  actual codepoints so they reach the block fallback; return U+FFFD for
  genuinely invalid bytes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:30:25 +02:00
Jakub
acc062718f fix: dynamic layout and pixel-accurate word-wrap in companion radio UI
- All menu screens (Tools, Bot, Settings) now derive item height from
  display.getLineHeight() instead of hardcoded constants, preventing
  item overflow on 64px OLED displays
- ToolsScreen caps rendered items to screen height so Char Test is visible
- FullscreenMsgView word-wrap now uses display.getTextWidth() per candidate
  line instead of fixed char count, correctly handles variable-width and
  multi-byte UTF-8 glyphs; FS_CHARS_MAX increased 32→80
- CharTestScreen: fix v-arrow y-position; remove stale "→ blocks █" comments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:26:11 +02:00
Jakub
50eb58c276 feat: add Char Test screen and extend Lemon font to Greek/Cyrillic
- Add CharTestScreen showing sample characters from 11 scripts
  (PL, DE, CS, FR, NO, HU, HR, TR, LT, Cyrillic, Greek) as raw
  UTF-8 to verify native font rendering without transliteration
- Add "Char Test" entry to ToolsScreen menu
- Regenerate LemonFont.h from lemon.bdf with full U+0020–U+04FF
  range: 1074 BDF glyphs + 174 placeholders, 4111 bitmap bytes;
  adds Greek (137 glyphs) and Cyrillic (256 glyphs) coverage;
  also fixes space advance (DWIDTH=5, was BBX+1=1)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:34:44 +02:00
Jakub
dbda484f2b fix: replace FS_LINE_H with lineH variable in FullscreenMsgView arrow background
FS_LINE_H was removed when adopting dynamic font-adaptive layout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:10:05 +02:00
Jakub
c00aa66f15 Update Discord link in README.md 2026-05-17 23:08:45 +02:00
Jakub
9a9efe74c8 perf: query sensors once for both lock screen dashboard fields
Previously each LPP sensor field called querySensors() separately.
Now a single querySensors() call fills a shared buffer used by both fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
17d9a93044 Add Discord discussion link to README
Added a link to the discussion channel on Discord.
2026-05-17 23:08:45 +02:00
Jakub
b789a0570f feat: add 30s minimum interval option to auto-advert screen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
073b98f535 fix: lock screen wake window no longer extends on repeated key presses
Previously every key press while locked reset _lock_wake_until to now+5s,
so multiple presses (or spurious button events) kept extending the window.
Now the 5s timer is set only when the display first wakes from dark.
The unlock sequence still extends the window on each Back+Enter step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
b2c7e249a6 fix: auto-reset _lock_seq_used after 5s in case Back release event is missed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
e763e3ae9d fix: polish lock screen sequence — hints update instantly, screen stays on, triple-Back blocked
- Turn display on at first Back+Enter press so hints are visible even when screen was dark
- Extend _lock_wake_until on every sequence step to prevent screen blanking mid-press
- Set _next_refresh=0 on every Enter press (not just on completion) for immediate hint redraw
- Add _lock_seq_used flag to suppress the Back CLICK that fires on release after unlock
- Block triple-Back (buzzer toggle) when screen is locked

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
e4063c0c8c fix: replace long-press lock trigger with back_btn.isPressed() check
Long press detection on back_btn was unreliable — the release generated
a spurious CLICK that cancelled the sequence. Now the Enter click handler
checks back_btn.isPressed() directly: holding Back and clicking Enter 3×
within 3 seconds locks/unlocks the screen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
2d4f7d3d23 feat: show two dashboard sensor values on lock screen
Reuses dashboard_fields[0] and [1] from NodePrefs — left-aligned and
right-aligned in one row under the clock, no labels to save space.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
b8336b4983 feat: screen lock — hold Back + 3×Enter to lock/unlock
- Long press Back starts lock sequence; 3 Enter presses within 3s toggle lock
- Locked screen wakes for 5 seconds on any key, showing clock and unlock hint
- Incoming messages do not wake the display while locked
- Auto Lock setting in Display section: locks automatically when screen turns off
- Lock state persisted in UITask; NodePrefs gains auto_lock flag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
885aa11f47 refactor: extract SettingsScreen and QuickMsgScreen to separate header files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:08:45 +02:00
Jakub
83124f8228 perf: increase render interval on static screens from 300ms to 2000ms
Static screens (SettingsScreen, BotScreen, FullscreenMsgView, message
list, contact picker) were re-rendering every 300ms with no visible
benefit. New messages still trigger immediate refresh via newMsg() →
_next_refresh=100, so responsiveness is unchanged. Reduces unnecessary
SPI transfers and CPU wakeups ~6x on idle static screens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:06:04 +02:00
Jakub
2911efc92f fix: clear arrow background in FullscreenMsgView to prevent text overlap
Text lines fill the full display width, causing the last chars to bleed
into the scroll arrow area. Draw a DARK fillRect behind each arrow before
rendering it, so the arrow appears on a clean black background without
truncating the text width.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:06:04 +02:00
Jakub
9650ba685b fix: separate DM and channel bot reply cooldown timers
Single shared _bot_last_reply_ms caused a DM reply to block the
channel bot for 10s and vice versa. Split into _bot_last_dm_reply_ms
and _bot_last_ch_reply_ms so each cooldown is independent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:05:49 +02:00
Jakub
571a56e418 fix: with_sender buffer too small and FS_LINE_H mismatch
- with_sender[160] could hold only ~160 chars but node_name(32) +
  expanded(200) needs up to 234; snprintf would silently truncate
  the UI display entry. Increased to 240.
- FS_LINE_H was 9 but Adafruit 5x7 font line height is 8, wasting
  1px per line and showing 5 lines instead of 6.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:05:49 +02:00
Jakub
4d08c130e9 fix: bot trigger matched against message body only, not sender name
Channel messages have the format "sender_name: body". The trigger was
being searched across the whole string, so a nick containing the trigger
word would fire a reply even with an unrelated message. Now the match
skips past the ": " separator and only checks the message body.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:05:24 +02:00
Jakub
361af6a795 fix: apply saved display brightness before UI task starts
Loading... screen was always shown at full brightness because prefs
are not yet loaded at that point. Apply setBrightness() in the first
common code path after the_mesh.begin() loads prefs, so at least the
tail of the loading screen and the entire splash screen respect the
saved brightness level.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:05:24 +02:00
Jakub
a99b248c9c fix: reduce low battery shutdown text size to fit 128px OLED
Size 2 rendered text wider than display width. Switched to size 1
and adjusted y-positions to keep both lines visible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:05:24 +02:00
Jakub
db3f287c78 fix: transliterate message text in FullscreenMsgView before wrapping
Raw UTF-8 message body was passed directly to display.print(), rendering
Polish and other accented chars as garbage on the Adafruit font.
Transliterating before wrapLines also fixes byte-count wrapping for
multi-byte UTF-8 characters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:05:24 +02:00
Jakub
d1d524aab1 fix: apply UTF-8 transliteration in drawTextEllipsized
Names printed via drawTextEllipsized (contacts, senders) bypassed
translateUTF8ToBlocks, causing raw UTF-8 bytes to render as garbage
on the Adafruit font. Now transliteration happens inside the method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:04:03 +02:00
Jakub
9ec4fddbbc fix: use block char █ fallback for unknown codepoints in transliteration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:04:03 +02:00
Jakub
8ec2a0ac22 feat: transliterate accented/diacritic characters to ASCII in translateUTF8ToBlocks
Replaces the block-character fallback with proper transliteration for
Polish (ą→a, ć→c, ę→e, ł→l, ń→n, ó→o, ś→s, ź→z, ż→z), German (ä ö ü ß),
and common French/Spanish/Portuguese accents. Unknown codepoints fall back
to '?' instead of █.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:04:03 +02:00
Jakub
a5a32530f0 Update Discord link in README.md 2026-05-17 18:55:21 +02:00
Jakub
44122565f6 perf: query sensors once for both lock screen dashboard fields
Previously each LPP sensor field called querySensors() separately.
Now a single querySensors() call fills a shared buffer used by both fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 18:52:40 +02:00
Jakub
28d69f88f4 Add Discord discussion link to README
Added a link to the discussion channel on Discord.
2026-05-17 18:51:48 +02:00
Jakub
360d5d10f7 feat: add 30s minimum interval option to auto-advert screen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 14:33:58 +02:00
Jakub
a2856b7a48 fix: lock screen wake window no longer extends on repeated key presses
Previously every key press while locked reset _lock_wake_until to now+5s,
so multiple presses (or spurious button events) kept extending the window.
Now the 5s timer is set only when the display first wakes from dark.
The unlock sequence still extends the window on each Back+Enter step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 14:30:53 +02:00
Jakub
3fb0a55aef fix: auto-reset _lock_seq_used after 5s in case Back release event is missed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:17:02 +02:00
Jakub
2bc6dae78e feat: add Icelandic and Romanian legacy cedilla transliteration
Adds ð/Ð (eth), þ/Þ (thorn) for Icelandic, and ţ/Ţ (t with cedilla)
for legacy-encoded Romanian text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:11:42 +02:00