From 2b23aa7b957b8d11e4017d9d5f99e9f95aa8a650e58e4968a77a014b083038e1 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Fri, 10 Jul 2026 11:57:00 +0400 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20UI=20=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81=D1=8B?= =?UTF-8?q?=20DM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VERSION.properties | 4 ++-- shine-UI/js/app.js | 15 ++++++++++++++- shine-UI/js/pages/chat-view.js | 19 +++++++++++++++++-- shine-UI/js/state.js | 7 ++++++- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/VERSION.properties b/VERSION.properties index 1db2cef..1ee7dcb 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.302 -server.version=1.2.281 +client.version=1.2.303 +server.version=1.2.282 diff --git a/shine-UI/js/app.js b/shine-UI/js/app.js index 334113d..0612131 100644 --- a/shine-UI/js/app.js +++ b/shine-UI/js/app.js @@ -892,6 +892,15 @@ function refreshToolbarOnly() { refreshConnectionUi(); } +function refreshUnreadUi() { + const pageId = getRoute().pageId || ''; + if (pageId === 'messages-list') { + renderApp(); + return; + } + refreshToolbarOnly(); +} + async function tryAutoLogin() { if (!state.session.login || !state.session.sessionId) return; try { @@ -1151,7 +1160,9 @@ async function init() { if (messageType === 3) { markOutgoingReadByBaseKey(refBaseKey); } else { - markIncomingReadByBaseKey(refBaseKey); + if (markIncomingReadByBaseKey(refBaseKey)) { + shouldRefreshToolbarUnread = true; + } } } addAppLogEntry({ @@ -1214,6 +1225,8 @@ async function init() { try { await handleIncomingCallInvite(evt); } catch {} }); + window.addEventListener('shine-unread-state-updated', refreshUnreadUi); + authService.onEvent('IncomingCallSignal', async (evt) => { try { await handleIncomingCallSignal(evt); } catch {} }); diff --git a/shine-UI/js/pages/chat-view.js b/shine-UI/js/pages/chat-view.js index 1ff68d3..1dcd307 100644 --- a/shine-UI/js/pages/chat-view.js +++ b/shine-UI/js/pages/chat-view.js @@ -619,11 +619,19 @@ export function render({ navigate, route }) { revisionTimeMs: Number(parsed?.revisionTimeMs || 0), deleted: Boolean(parsed?.deleted), }); + return true; } catch { // ignore local parse failure; server backlog/realtime will reconcile later + return false; } }; + const notifyUnreadStateUpdated = () => { + window.dispatchEvent(new CustomEvent('shine-unread-state-updated', { + detail: { chatId }, + })); + }; + const sendDeleteRevision = async (msg) => { const base = parseBaseKey(msg?.baseKey); if (!base) return; @@ -681,7 +689,7 @@ export function render({ navigate, route }) { }); } - void applyLocalRevision({ + const localRevisionApplied = await applyLocalRevision({ localOutgoingBlobB64: result?.localOutgoingBlobB64 || '', fallbackMessageKey: result?.outgoingKey || '', fallbackBaseKey: result?.baseKey || result?.localBaseKey || '', @@ -692,6 +700,9 @@ export function render({ navigate, route }) { } renderLog(log, chatId, { onOpenActions: handleOpenActions }); + if (localRevisionApplied) { + notifyUnreadStateUpdated(); + } scrollToLatestMessageSmart(log, { smoothIfNearBottom: true }); window.requestAnimationFrame(() => scrollToLatestMessageSmart(log, { smoothIfNearBottom: true })); window.setTimeout(() => scrollToLatestMessageSmart(log, { smoothIfNearBottom: true }), 220); @@ -841,7 +852,11 @@ export function render({ navigate, route }) { window.requestAnimationFrame(() => scrollToLatestMessage(log)); window.setTimeout(() => scrollToLatestMessage(log), 180); } - window.setTimeout(() => markChatRead(chatId), 220); + window.setTimeout(() => { + if (markChatRead(chatId) > 0) { + notifyUnreadStateUpdated(); + } + }, 220); void sendReadReceiptsForVisible(chatId); screen.cleanup = () => { setChatKeyboardOpen(false); diff --git a/shine-UI/js/state.js b/shine-UI/js/state.js index 42008d4..3a55c60 100644 --- a/shine-UI/js/state.js +++ b/shine-UI/js/state.js @@ -577,6 +577,7 @@ export function markOutgoingReadByBaseKey(baseKey) { } else { state.pendingOutgoingReadByBaseKey[baseKey] = true; } + return matched; } export function markIncomingReadByBaseKey(baseKey) { @@ -600,6 +601,7 @@ export function markIncomingReadByBaseKey(baseKey) { } else { state.pendingIncomingReadByBaseKey[baseKey] = true; } + return matched; } export function markReadReceiptSentByBaseKey(baseKey) { @@ -727,12 +729,15 @@ export function deleteConversationMessagesBefore(chatId, boundaryTimeMs) { export function markChatRead(chatId) { const normalizedChatId = normalizeDmChatId(chatId); const list = getChatMessages(normalizedChatId); + let changed = 0; list.forEach((row) => { - if (row?.from === 'in') { + if (row?.from === 'in' && row?.unread) { row.unread = false; persistMessageRecord(normalizedChatId, row); + changed += 1; } }); + return changed; } export function setContacts(list) {