SHA256
Сохранить текущий снимок DM-синхронизации
This commit is contained in:
@@ -43,6 +43,7 @@ import {
|
||||
deleteConversationMessagesBefore,
|
||||
deleteSignedMessageByBaseKey,
|
||||
markIncomingReadByBaseKey,
|
||||
markOutgoingDeliveryState,
|
||||
markOutgoingReadByBaseKey,
|
||||
normalizeDmChatId,
|
||||
setContacts,
|
||||
@@ -1390,6 +1391,17 @@ async function init() {
|
||||
});
|
||||
});
|
||||
|
||||
authService.onEvent('DmDeliveryStateChanged', (evt) => {
|
||||
const payload = evt?.payload || {};
|
||||
const changed = markOutgoingDeliveryState({
|
||||
outgoingKey: payload.outgoingKey,
|
||||
baseKey: payload.baseKey,
|
||||
deliveryState: payload.deliveryState,
|
||||
});
|
||||
if (!changed) return;
|
||||
window.dispatchEvent(new CustomEvent('shine-dm-delivery-updated', { detail: payload }));
|
||||
});
|
||||
|
||||
authService.onEvent('SignedMessageArrived', async (evt) => {
|
||||
const payload = evt?.payload || {};
|
||||
const messageKey = String(payload.messageKey || '').trim();
|
||||
|
||||
@@ -528,10 +528,28 @@ function resolveEffectiveReadState(messages, msg) {
|
||||
function resolveDeliveryStatus(messages, msg) {
|
||||
if (msg?.from !== 'out') return '';
|
||||
if (resolveEffectiveReadState(messages, msg).isRead) return '✓✓';
|
||||
if (msg?.firstTick) return '✓';
|
||||
const deliveryState = String(msg?.deliveryState || '').trim().toLowerCase();
|
||||
if (deliveryState === 'delivered') return '✓';
|
||||
if (deliveryState === 'failed') return '!';
|
||||
if (deliveryState === 'accepted' || msg?.firstTick) return '✓';
|
||||
return '…';
|
||||
}
|
||||
|
||||
function resolveDeliveryTone(messages, msg) {
|
||||
if (resolveEffectiveReadState(messages, msg).isRead) return 'read';
|
||||
const deliveryState = String(msg?.deliveryState || '').trim().toLowerCase();
|
||||
if (deliveryState === 'delivered') return 'delivered';
|
||||
if (deliveryState === 'failed') return 'failed';
|
||||
return 'accepted';
|
||||
}
|
||||
|
||||
function resolveDeliveryNote(msg) {
|
||||
if (msg?.from !== 'out') return '';
|
||||
const deliveryState = String(msg?.deliveryState || '').trim().toLowerCase();
|
||||
if (deliveryState === 'failed') return 'Сообщение не доставлено.';
|
||||
return '';
|
||||
}
|
||||
|
||||
function resolveMessageEditedTimeMs(msg) {
|
||||
const revisionTimeMs = Number(msg?.revisionTimeMs || 0);
|
||||
if (!Number.isFinite(revisionTimeMs) || revisionTimeMs <= 0) return 0;
|
||||
@@ -744,13 +762,21 @@ function renderLog(
|
||||
const status = resolveDeliveryStatus(messages, msg);
|
||||
if (status) {
|
||||
const statusNode = document.createElement('span');
|
||||
statusNode.className = 'bubble-status';
|
||||
statusNode.className = `bubble-status bubble-status--${resolveDeliveryTone(messages, msg)}`;
|
||||
statusNode.textContent = status;
|
||||
metaNode.append(statusNode);
|
||||
}
|
||||
|
||||
bubble.append(metaNode);
|
||||
|
||||
const deliveryNote = resolveDeliveryNote(msg);
|
||||
if (deliveryNote) {
|
||||
const deliveryNoteNode = document.createElement('div');
|
||||
deliveryNoteNode.className = `bubble-delivery-note${String(msg?.deliveryState || '') === 'failed' ? ' bubble-delivery-note--failed' : ''}`;
|
||||
deliveryNoteNode.textContent = deliveryNote;
|
||||
bubble.append(deliveryNoteNode);
|
||||
}
|
||||
|
||||
const editedAtMs = resolveMessageEditedTimeMs(msg);
|
||||
if (editedAtMs > 0) {
|
||||
const editedNode = document.createElement('div');
|
||||
@@ -831,6 +857,7 @@ async function mergeDirectMessagesPage(chatId, payloadMessages) {
|
||||
readAtMs: Number(item?.readAtMs || 0),
|
||||
rawBlobB64: blobB64,
|
||||
revisionTimeMs: Number(item?.revisionTimeMs || parsed?.revisionTimeMs || 0),
|
||||
deliveryState: String(item?.deliveryState || ''),
|
||||
});
|
||||
} catch (error) {
|
||||
addAppLogEntry({
|
||||
@@ -1248,7 +1275,12 @@ export function render({ navigate, route, chrome }) {
|
||||
focusInputToEnd();
|
||||
};
|
||||
|
||||
const applyLocalRevision = async ({ localOutgoingBlobB64, fallbackMessageKey = '', fallbackBaseKey = '' }) => {
|
||||
const applyLocalRevision = async ({
|
||||
localOutgoingBlobB64,
|
||||
fallbackMessageKey = '',
|
||||
fallbackBaseKey = '',
|
||||
deliveryState = '',
|
||||
}) => {
|
||||
if (!localOutgoingBlobB64) return;
|
||||
try {
|
||||
const parsed = authService.parseSignedMessageBlob(localOutgoingBlobB64);
|
||||
@@ -1271,6 +1303,7 @@ export function render({ navigate, route, chrome }) {
|
||||
unread: false,
|
||||
rawBlobB64: localOutgoingBlobB64,
|
||||
revisionTimeMs: Number(parsed?.revisionTimeMs || 0),
|
||||
deliveryState,
|
||||
deleted: Boolean(parsed?.deleted),
|
||||
});
|
||||
return true;
|
||||
@@ -1346,6 +1379,7 @@ export function render({ navigate, route, chrome }) {
|
||||
markOutgoingSent(tempId, {
|
||||
messageKey: result?.outgoingKey || '',
|
||||
baseKey: result?.baseKey || result?.localBaseKey || '',
|
||||
deliveryState: result?.deliveryState || 'accepted',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1353,6 +1387,7 @@ export function render({ navigate, route, chrome }) {
|
||||
localOutgoingBlobB64: result?.localOutgoingBlobB64 || '',
|
||||
fallbackMessageKey: result?.outgoingKey || '',
|
||||
fallbackBaseKey: result?.baseKey || result?.localBaseKey || '',
|
||||
deliveryState: result?.deliveryState || 'accepted',
|
||||
});
|
||||
|
||||
if (editing) {
|
||||
@@ -1580,7 +1615,14 @@ export function render({ navigate, route, chrome }) {
|
||||
void sendReadReceiptsForVisible(chatId);
|
||||
};
|
||||
|
||||
const handleDeliveryRefresh = () => {
|
||||
preserveComposerSelection(input, () => {
|
||||
renderChatLog({ scrollMode: 'preserve', markAsRead: false });
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('shine-chat-messages-updated', handleIncomingChatRefresh);
|
||||
window.addEventListener('shine-dm-delivery-updated', handleDeliveryRefresh);
|
||||
|
||||
wrap.append(historyLoader, log);
|
||||
screen.append(wrap);
|
||||
@@ -1609,6 +1651,7 @@ export function render({ navigate, route, chrome }) {
|
||||
hideUnreadSeparator({ rerender: false });
|
||||
stopAllTwemojiAnimations();
|
||||
window.removeEventListener('shine-chat-messages-updated', handleIncomingChatRefresh);
|
||||
window.removeEventListener('shine-dm-delivery-updated', handleDeliveryRefresh);
|
||||
boundScrollContainer?.removeEventListener('scroll', handleHistoryScroll);
|
||||
clearUnreadSeparatorHideTimer();
|
||||
document.body.classList.remove('chat-topbar-overlay');
|
||||
|
||||
@@ -17,6 +17,7 @@ const DM_BLOB_PREVIEW_CACHE = new Map();
|
||||
const DM_BLOB_PREVIEW_PENDING = new Map();
|
||||
const dmAvatarSnapshotCache = new Map();
|
||||
const dmAvatarPendingByLogin = new Map();
|
||||
const SVG_CHEVRON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>';
|
||||
|
||||
const RELATION_ORDER = new Map([
|
||||
['close_friend', 0],
|
||||
@@ -166,6 +167,7 @@ function compareChatRows(a, b) {
|
||||
export function render({ navigate, chrome }) {
|
||||
const screen = document.createElement('section');
|
||||
screen.className = 'stack dm-screen dm-list-screen';
|
||||
const login = String(state.session.login || '').trim();
|
||||
const head = document.createElement('header');
|
||||
head.className = 'dm-head';
|
||||
head.innerHTML = `
|
||||
|
||||
+37
-1
@@ -414,6 +414,7 @@ function persistMessageRecord(chatId, row) {
|
||||
readAtMs: Number(row.readAtMs || 0),
|
||||
readReceiptSent: Boolean(row.readReceiptSent),
|
||||
refBaseKey: String(row.refBaseKey || ''),
|
||||
deliveryState: String(row.deliveryState || ''),
|
||||
ts: resolvedTs > 0 ? resolvedTs : Date.now(),
|
||||
}).catch(() => {});
|
||||
}
|
||||
@@ -450,6 +451,7 @@ export async function hydrateMessagesFromStore() {
|
||||
readAtMs: Number(row.readAtMs || 0),
|
||||
readReceiptSent: Boolean(row.readReceiptSent),
|
||||
refBaseKey: String(row.refBaseKey || ''),
|
||||
deliveryState: String(row.deliveryState || ''),
|
||||
createdAtMs: Number(row.ts || 0),
|
||||
});
|
||||
});
|
||||
@@ -531,7 +533,11 @@ export function addOutgoingPendingMessage(chatId, text) {
|
||||
return tempId;
|
||||
}
|
||||
|
||||
export function markOutgoingSent(tempId, { messageKey = '', baseKey = '' } = {}) {
|
||||
export function markOutgoingSent(tempId, {
|
||||
messageKey = '',
|
||||
baseKey = '',
|
||||
deliveryState = 'accepted',
|
||||
} = {}) {
|
||||
if (!tempId) return;
|
||||
const keys = Object.keys(state.chats || {});
|
||||
keys.forEach((chatId) => {
|
||||
@@ -541,6 +547,7 @@ export function markOutgoingSent(tempId, { messageKey = '', baseKey = '' } = {})
|
||||
row.firstTick = true;
|
||||
row.messageKey = messageKey || row.messageKey || '';
|
||||
row.baseKey = baseKey || row.baseKey || '';
|
||||
row.deliveryState = String(deliveryState || row.deliveryState || 'accepted');
|
||||
if (messageKey) {
|
||||
state.knownMessageKeys[messageKey] = true;
|
||||
persistMessageRecord(chatId, row);
|
||||
@@ -549,6 +556,33 @@ export function markOutgoingSent(tempId, { messageKey = '', baseKey = '' } = {})
|
||||
});
|
||||
}
|
||||
|
||||
export function markOutgoingDeliveryState({
|
||||
outgoingKey = '',
|
||||
baseKey = '',
|
||||
deliveryState = '',
|
||||
} = {}) {
|
||||
const normalizedOutgoingKey = String(outgoingKey || '').trim();
|
||||
const normalizedBaseKey = String(baseKey || '').trim();
|
||||
let changed = false;
|
||||
Object.keys(state.chats || {}).forEach((chatId) => {
|
||||
getChatMessages(chatId).forEach((row) => {
|
||||
if (row?.from !== 'out') return;
|
||||
const matches = (
|
||||
(normalizedOutgoingKey && String(row.messageKey || '') === normalizedOutgoingKey)
|
||||
|| (normalizedBaseKey && String(row.baseKey || '') === normalizedBaseKey)
|
||||
);
|
||||
if (!matches) return;
|
||||
row.deliveryState = String(deliveryState || row.deliveryState || 'accepted');
|
||||
if (row.deliveryState === 'delivered') {
|
||||
row.firstTick = true;
|
||||
}
|
||||
persistMessageRecord(chatId, row);
|
||||
changed = true;
|
||||
});
|
||||
});
|
||||
return changed;
|
||||
}
|
||||
|
||||
export function markOutgoingReadByBaseKey(baseKey, readAtMs = 0) {
|
||||
if (!baseKey) return;
|
||||
const normalizedReadAtMs = Number(readAtMs || 0);
|
||||
@@ -629,6 +663,7 @@ export function addSignedMessageToChat({
|
||||
rawBlobB64 = '',
|
||||
refBaseKey = '',
|
||||
revisionTimeMs = 0,
|
||||
deliveryState = '',
|
||||
deleted = false,
|
||||
} = {}) {
|
||||
const normalizedChatId = normalizeDmChatId(chatId);
|
||||
@@ -663,6 +698,7 @@ export function addSignedMessageToChat({
|
||||
row.messageType = Number(messageType || 0);
|
||||
row.rawBlobB64 = String(rawBlobB64 || '');
|
||||
row.revisionTimeMs = nextRevision;
|
||||
row.deliveryState = String(deliveryState || existing?.deliveryState || (row.from === 'out' ? 'accepted' : ''));
|
||||
row.unread = row.from === 'in' ? Boolean(unread) : false;
|
||||
row.refBaseKey = String(refBaseKey || '');
|
||||
row.firstTick = row.from === 'out';
|
||||
|
||||
Reference in New Issue
Block a user