mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-02 10:51:57 +00:00
feat: open a conversation on its first unread message, under a "New" line
Both UIs: a channel, DM or room with unread messages opens on the oldest of
them (MessageHistory::firstUnreadChannel / firstUnreadDm, own messages not
counted), a "New" line above it, so it reads down to the newest. Nothing
unread: the newest, as before.
L1: the first unread is selected and scrolled up top with the line in view;
the channel's unread count now counts down as you read towards the newest.
L2: the page holding it, scrolled to the line; an incoming message scrolls
down only when the list is already at its end. Sim hooks: sim_unread (L1),
sim_open("unread") (L2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -413,6 +413,31 @@ public:
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Where reading resumes on opening a conversation with `unread` unread: the
|
||||
// newest-first index (as histEntryForChannel / dmHistEntryForContact) of the
|
||||
// oldest of the `unread` newest received messages -- our own don't count --
|
||||
// or of the oldest held when some were pushed out. -1 when none is unread.
|
||||
int firstUnreadChannel(int ch_idx, int unread) const {
|
||||
int j = 0, last = -1;
|
||||
for (int i = _hist_count - 1; i >= 0 && unread > 0; i--) {
|
||||
const ChHistEntry& e = _hist[(_hist_head + i) % CH_HIST_MAX];
|
||||
if (e.ch_idx != (uint8_t)ch_idx) continue;
|
||||
last = j++;
|
||||
if (strncmp(e.text, "Me: ", 4) != 0) unread--;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
int firstUnreadDm(const uint8_t* prefix, int unread) const {
|
||||
int j = 0, last = -1;
|
||||
for (int i = _dm_hist_count - 1; i >= 0 && unread > 0; i--) {
|
||||
const DmHistEntry& e = _dm_hist[(_dm_hist_head + i) % DM_HIST_MAX];
|
||||
if (memcmp(e.prefix, prefix, 4) != 0) continue;
|
||||
last = j++;
|
||||
if (!e.outgoing) unread--;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
// Effective status for display. A pending ACK only reads as failed once its
|
||||
// deadline has passed AND no auto-resends remain — while resends_left > 0 the
|
||||
// entry stays pending (tickDmResends() retries / finalises it). Safety net for
|
||||
|
||||
@@ -224,6 +224,28 @@ public:
|
||||
if (viewing && pos >= 0) _host->onViewedHistoryGrew(true);
|
||||
return pos;
|
||||
}
|
||||
#ifdef SIM_PLATFORM
|
||||
// Sim tests: channel 0 and the first chat contact get 12 read messages, then 5 new.
|
||||
void simUnreadDemo() {
|
||||
uint32_t now = rtc_clock.getCurrentTime();
|
||||
static const char* const W[] = { "Alice", "Bob", "Me", "Carol" };
|
||||
const uint8_t* dm = nullptr;
|
||||
ContactInfo c;
|
||||
for (int i = 0; i < the_mesh.getNumContacts() && !dm; i++)
|
||||
if (the_mesh.getContactByIdx(MAX_ANON_CONTACTS + i, c) && c.type == ADV_TYPE_CHAT) dm = c.id.pub_key;
|
||||
for (int i = 0; i < 17; i++) {
|
||||
char t[48];
|
||||
snprintf(t, sizeof(t), "%s: message %d", i < 12 ? W[i % 4] : W[i % 2], i + 1);
|
||||
addChannelMsg(0, t, now - (17 - i) * 120);
|
||||
if (dm) {
|
||||
bool out = i < 12 && i % 3 == 2;
|
||||
if (!out) dm_unread.onIncoming(dm);
|
||||
addDMMsg(dm, out, strstr(t, ": ") + 2, now - (17 - i) * 120);
|
||||
}
|
||||
if (i == 11) { history.setChUnread(0, 0); if (dm) clearDMUnread(dm); }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void armChannelRelay(int pos, uint32_t seq) override { history.armChannelRelay(pos, seq); }
|
||||
void onChannelRelayed(uint32_t seq, const uint8_t* repeater_hash = nullptr, uint8_t hash_size = 0) override {
|
||||
history.markChannelRelayed(seq, repeater_hash, hash_size);
|
||||
|
||||
Reference in New Issue
Block a user