fix(ui): cap channel unread badge to what the message ring still holds

The per-channel unread counter was independent of the ring's actual
contents, so the two drifted apart:

- Opening a channel whose entries had been evicted left the badge
  claiming messages the list could no longer show. The viewing-session
  bookkeeping computes the count from an _unread_at_entry snapshot, and
  with an empty list _hist_visible is 0, so entering only knocked the
  count down by one instead of clearing it (badge "7", empty list, then
  "6").
- Eviction from a full ring decremented the counter for any dropped
  entry, including already-read ones, undercounting the newer unread
  messages the counter actually refers to.

chUnread()/getTotalChannelUnread() now clamp to the channel's ring
occupancy, so the badge can never promise more than the history holds
whatever the raw counter says, and eviction only decrements when the
entry being dropped was itself unread.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-07-27 18:05:47 +02:00
co-authored by Claude Opus 5
parent 096e4580b5
commit 6470afaf56
2 changed files with 28 additions and 4 deletions
+1
View File
@@ -14,6 +14,7 @@
- **DM/room replies sometimes didn't show who they were addressed to, and room messages could wrap incorrectly.** The reply-prefix (`@[nick] `) was being stripped at the wrong point for room posts and DMs feeding the fullscreen message view, so a DM reply's "To:" header could go missing while a room reply showed the raw `@[nick] ` marker as literal message text; a related mismatch meant the history list's scrollbar/box-height sizing pass wrapped room messages with their sender name still attached, disagreeing with the actual rendered text.
- **Remote Bot Actions (`!buzz`/`!gps`/`!advert`/`!gpio1`..`!gpio4`) ran immediately on every matching message, before quiet hours/cooldown/per-contact throttle were checked** — those gates only suppressed the reply text, not the actual buzz/GPS toggle/advert/pin write, so e.g. `!buzz` still audibly buzzed during configured quiet hours, and repeating a command wasn't rate-limited at all. Actions now only run once those checks have passed.
- **A channel's unread badge could claim messages the history no longer held** — e.g. showing "7 unread" on a channel that opens to an empty list, and opening it only knocked the count down by one instead of clearing it. The badge is now capped at what the message ring actually still holds, and evicting an old message from a full ring only decrements the counter when the message being dropped was itself unread (previously it decremented regardless, undercounting newer unread messages).
- **CardKB's Fn+`<letter>` accent-popup shortcut could open the accent popup while the device was locked**, unlike every other key on the keyboard (all of which are correctly discarded while locked) — it went straight to the keyboard widget instead of through the normal locked-input gate. Now respects the lock like everything else. Since a locked device now correctly ignores CardKB entirely, **Fn+Esc** (single press) is added as CardKB's own lock/unlock gesture — otherwise a CardKB-only setup had no way to unlock at all.
---