mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-26 20:56:37 +00:00
fix(ui): correct DM unread overflow check and aggregate/scope edge cases
- DM unread: the ring-eviction check ran in newMsg(), which MyMesh calls before addDMMsg(), so the new message itself read as evicted -- the first DM from a contact showed no badge and every later one was one short with a false "+". Moved into addDMMsg() after the insert, and run for every slot, so a contact whose unread entry was evicted by someone else's message is flagged right away too. - Channel overflow aggregate: ignore channels whose unread count is 0 (eviction can zero it with the flag left set), so the dashboard no longer shows "0+ msgs" or a "+" borrowed from another conversation. - Live Share scope: a stale index past the list's end now follows the target, as the screen shows, instead of silently sending unscoped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -241,8 +241,13 @@ public:
|
||||
bool chUnreadOverflow(int ch) const {
|
||||
return ch >= 0 && ch < MAX_GROUP_CHANNELS && _ch_unread_overflow[ch];
|
||||
}
|
||||
// Only channels that still show unread count: eviction alone can take a
|
||||
// channel's counter down to 0 with the flag left set (nothing then calls
|
||||
// setChUnread(ch, 0) to clear it), and a "+" on the aggregate must not come
|
||||
// from a channel contributing nothing to it (e.g. a dashboard "0+ msgs").
|
||||
bool anyChannelUnreadOverflow() const {
|
||||
for (int i = 0; i < MAX_GROUP_CHANNELS; i++) if (_ch_unread_overflow[i]) return true;
|
||||
for (int i = 0; i < MAX_GROUP_CHANNELS; i++)
|
||||
if (_ch_unread_overflow[i] && chUnread(i) > 0) return true;
|
||||
return false;
|
||||
}
|
||||
void setChUnread(int ch, uint8_t v) {
|
||||
|
||||
@@ -2010,6 +2010,22 @@ void UITask::addDMMsg(const uint8_t* pub_key, bool outgoing, const char* text, u
|
||||
uint32_t ack_tag, uint32_t ack_deadline_ms, uint8_t resends,
|
||||
const uint8_t* path, uint8_t path_len) {
|
||||
((MessagesScreen*)messages_screen)->addDMMsg(pub_key, outgoing, text, sender_timestamp, ack_tag, ack_deadline_ms, resends, path, path_len);
|
||||
// The DM ring (unlike the channel ring) doesn't proactively decrement the
|
||||
// unread counters as it evicts old entries, so catch it here, right after
|
||||
// the insert: a raw count claiming more unread than the ring still holds
|
||||
// for that contact means one of their unread entries was just evicted. Any
|
||||
// contact can lose one -- not just this sender -- so check every slot.
|
||||
// Clamp back to the honest value and flag it (mirrors MessageHistory's
|
||||
// channel-side fix). Must run after the insert, not in newMsg() (called
|
||||
// before it), or the new message itself reads as evicted.
|
||||
for (int i = 0; i < DM_UNREAD_TABLE_SIZE; i++) {
|
||||
if (_dm_unread_table[i].count == 0) continue;
|
||||
int held = ((MessagesScreen*)messages_screen)->dmHistCountForContact(_dm_unread_table[i].prefix);
|
||||
if (_dm_unread_table[i].count > held) {
|
||||
_dm_unread_table[i].count = (uint8_t)held;
|
||||
_dm_unread_table[i].overflow = held > 0; // held == 0 frees the slot -- nothing left to flag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int UITask::getDMUnreadTotal() const {
|
||||
@@ -2114,21 +2130,8 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
|
||||
memcpy(_dm_unread_table[empty_slot].prefix, pub_key, 4);
|
||||
_dm_unread_table[empty_slot].count = 1;
|
||||
_dm_unread_table[empty_slot].overflow = false; // fresh contact -- don't inherit a stale flag from whoever held this slot before
|
||||
slot = empty_slot;
|
||||
}
|
||||
// The DM ring (unlike the channel ring) doesn't proactively decrement this
|
||||
// counter as it evicts old entries, so it can only be caught here: if the
|
||||
// raw count now claims more unread than the ring actually still holds for
|
||||
// this contact, an unread entry for them was just evicted (this insert, by
|
||||
// definition, can only have evicted at most one entry). Clamp back to the
|
||||
// honest value and flag it -- mirrors MessageHistory's channel-side fix.
|
||||
if (slot >= 0) {
|
||||
int held = ((MessagesScreen*)messages_screen)->dmHistCountForContact(pub_key);
|
||||
if (_dm_unread_table[slot].count > held) {
|
||||
_dm_unread_table[slot].count = (uint8_t)held;
|
||||
_dm_unread_table[slot].overflow = true;
|
||||
}
|
||||
}
|
||||
// Eviction/overflow is checked in addDMMsg(), after the ring insert.
|
||||
}
|
||||
|
||||
char alert_buf[80];
|
||||
@@ -3466,9 +3469,14 @@ bool UITask::sendLocationShare(int32_t lat, int32_t lon) {
|
||||
if (!_node_prefs) return false;
|
||||
// Live Share's own scope, if set: applies to these sends only (0 = follow the
|
||||
// target's usual scope). The sends below are synchronous, so bracketing works.
|
||||
// A value past the list's end (list shrunk other than via removeScope())
|
||||
// follows the target, as LiveShareScreen shows it -- ScopeList::key() would
|
||||
// otherwise clamp it to "*" and send unscoped.
|
||||
struct ScopeGuard {
|
||||
bool on;
|
||||
explicit ScopeGuard(uint8_t v) : on(v != 0) { if (on) the_mesh.setOneShotScope(v - 1); }
|
||||
explicit ScopeGuard(uint8_t v) : on(v != 0 && v <= the_mesh.scopeList().count + 1) {
|
||||
if (on) the_mesh.setOneShotScope(v - 1);
|
||||
}
|
||||
~ScopeGuard() { if (on) the_mesh.clearOneShotScope(); }
|
||||
} scope_guard(_node_prefs->loc_share_scope);
|
||||
char text[80];
|
||||
|
||||
Reference in New Issue
Block a user