From 2501adcae762d7714852d1756968fc21d7bf0b4f Mon Sep 17 00:00:00 2001 From: jolavillette Date: Thu, 27 Aug 2026 13:31:04 +0200 Subject: [PATCH] webui v155: marking a mail read must not take it out of the trash markReadLocally() clears the whole 0xf0 nibble, but RS_MSG_TRASH is 0x20 and lives inside it (rsmail.h). Opening a message from the Trash therefore cleared its trash flag as well, and the row showed as an ordinary read mail until the next load. Only the two unread bits are cleared now. The badge itself is read from the navigation view, so unreadCount() ran a full pass over the inbox on every redraw -- once for the rail and twice more for the bottom bar, which asks for the value twice per item. The count is kept instead, recomputed when the inbox changes: after a load, and after a message is marked read. --- webui-src/app/mail/mail_resolver.js | 23 ++++++++++++++++++++--- webui-src/app/main.js | 4 ++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/webui-src/app/mail/mail_resolver.js b/webui-src/app/mail/mail_resolver.js index 950d07a..e9d07d0 100644 --- a/webui-src/app/mail/mail_resolver.js +++ b/webui-src/app/mail/mail_resolver.js @@ -20,13 +20,22 @@ const Messages = { todo: [], later: [], refreshTimer: null, - unreadCount() { - return (Messages.inbox || []).filter((msg) => { + unread: 0, + // The badge is read from the navigation view, so it is asked for on every + // redraw -- once for the rail, twice more for the bottom bar. Counting is a + // full pass over the inbox, so it happens when the inbox changes instead: + // after a load, and after a message is marked read here. + recountUnread() { + Messages.unread = (Messages.inbox || []).filter((msg) => { const status = msg.msgflags & 0xf0; return (status === util.RS_MSG_NEW || status === util.RS_MSG_UNREAD_BY_USER) && !(msg.msgflags & util.RS_MSG_TRASH) && !(msg.msgflags & util.RS_MSG_SPAM); }).length; + return Messages.unread; + }, + unreadCount() { + return Messages.unread; }, refreshSoon() { if (Messages.refreshTimer) return; @@ -37,8 +46,15 @@ const Messages = { }, markReadLocally(msgId) { Messages.all.forEach((msg) => { - if (msg.msgId === msgId) msg.msgflags &= ~0xf0; + // Only the two unread bits. RS_MSG_TRASH is 0x20, inside the 0xf0 the + // status is read through, so clearing the whole nibble also takes a + // message out of the trash: opening one from there showed it as an + // ordinary read mail until the next load. + if (msg.msgId === msgId) { + msg.msgflags &= ~(util.RS_MSG_NEW | util.RS_MSG_UNREAD_BY_USER); + } }); + Messages.recountUnread(); }, load() { rs.rsJsonApiRequest('/rsMail/getMessageSummaries', { box: util.BOX_ALL }, (data) => { @@ -82,6 +98,7 @@ const Messages = { Messages.later = Messages.all.filter( (msg) => msg.msgtags && msg.msgtags.includes(util.RS_MSGTAGTYPE_LATER) ); + Messages.recountUnread(); m.redraw(); } }); diff --git a/webui-src/app/main.js b/webui-src/app/main.js index 5240d06..a680901 100644 --- a/webui-src/app/main.js +++ b/webui-src/app/main.js @@ -135,7 +135,7 @@ const navbar = () => { ? 'Connected to RetroShare Core' : 'Connection Lost', }), - m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v153'), + m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v155'), m('i.fas.fa-sync-alt.refresh-icon', { style: { cursor: 'pointer', fontSize: '0.8em' }, onclick: () => window.location.reload(true), @@ -258,7 +258,7 @@ const MobileStatus = () => { m('small', statusbar.formatBytes(state.totalOut)), ]), ]), - m('.mobile-status-sheet__version', 'WebUI v153'), + m('.mobile-status-sheet__version', 'WebUI v155'), ])), ]; },