add message read/unread render & fix profile display
This commit is contained in:
parent
271c573fb4
commit
68ac0beedf
14 changed files with 290 additions and 38 deletions
143
webroot/main.js
143
webroot/main.js
|
|
@ -1533,6 +1533,13 @@ async function openProfile(accountId) {
|
|||
|
||||
try {
|
||||
if (!accountId) accountId = window.id; //var fallback
|
||||
|
||||
if (accountId.endsWith(';' + host)) {
|
||||
accountId = accountId.substring(0, accountId.length - host.length - 1);
|
||||
} else if (accountId.endsWith(':' + host)) {
|
||||
accountId = accountId.substring(0, accountId.length - host.length - 1);
|
||||
}
|
||||
|
||||
let nameWithHost = await fetchAsync(`${url}/idtoname?id=${accountId}`);
|
||||
if (nameWithHost.startsWith("error:")) nameWithHost = accountId; //api fallback
|
||||
|
||||
|
|
@ -1632,7 +1639,7 @@ async function openProfile(accountId) {
|
|||
<div class="profile-info">
|
||||
<div>
|
||||
<div class="profile-name">${profileName}</div>
|
||||
<div class="profile-id-host">${profileName}:${profileHost} (${accountId.split(':')[0]})</div>
|
||||
<div class="profile-id-host">${profileName}:${profileHost} (${accountId.split(':')[0].split(';')[0]})</div>
|
||||
</div>
|
||||
${bioHtml}
|
||||
${actionBtnHtml}
|
||||
|
|
@ -2098,11 +2105,14 @@ async function renderDms(res) {
|
|||
let pfp = await getAvatarUrl(targetId, targetUsername);
|
||||
let displayName = targetUsername.split(':')[0];
|
||||
|
||||
let isRead = dmData.string3 === "true";
|
||||
let nameStyle = isRead ? "opacity: 0.8;" : "opacity: 1;";
|
||||
|
||||
html += `
|
||||
<button class="room-entry" id="dm-btn-${dmId}" onclick="openDm('${dmId}', '${targetUsername}', '${targetId}')">
|
||||
<img src="${pfp}" class="room-pfp">
|
||||
<div style="display: flex; flex-direction: column; text-align: left; overflow: hidden; width: 100%; margin-left: 0.37rem;">
|
||||
<span class="room-name">${displayName}</span>
|
||||
<span class="room-name" style="${nameStyle}">${displayName}</span>
|
||||
<span class="room-id" style="font-size: 0.8rem; opacity: 0.6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${targetUsername} (${targetId.split(';')[0]})</span>
|
||||
</div>
|
||||
</button>
|
||||
|
|
@ -2188,6 +2198,8 @@ async function openDm(dmId, username, targetId) {
|
|||
try {
|
||||
showAction("action.dm.opening", "dmopen");
|
||||
|
||||
markDmAsRead(dmId);
|
||||
|
||||
currentDmKey = await ensureDmRoomKey(dmId);
|
||||
if (!currentDmKey) {
|
||||
throw new Error("Missing DM room key");
|
||||
|
|
@ -2484,13 +2496,21 @@ async function renderMessages(messages, isPrepend = false) {
|
|||
|
||||
container.innerHTML = html;
|
||||
|
||||
let targetScrollTop = 0;
|
||||
if (wasAtBottom) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
targetScrollTop = container.scrollHeight;
|
||||
} else if (isPrepend) {
|
||||
container.scrollTop = oldScrollTop + (container.scrollHeight - oldScrollHeight);
|
||||
targetScrollTop = oldScrollTop + (container.scrollHeight - oldScrollHeight);
|
||||
} else {
|
||||
container.scrollTop = oldScrollTop;
|
||||
targetScrollTop = oldScrollTop;
|
||||
}
|
||||
|
||||
ignoreScroll = true;
|
||||
container.scrollTop = targetScrollTop;
|
||||
lastChatScroll = container.scrollHeight - targetScrollTop - container.clientHeight;
|
||||
if (lastChatScroll < 0) lastChatScroll = 0;
|
||||
|
||||
setTimeout(() => { ignoreScroll = false; }, 50);
|
||||
}
|
||||
|
||||
var lastChatScroll = 0;
|
||||
|
|
@ -2528,6 +2548,9 @@ function setupChatScrollListener() {
|
|||
if (!ignoreScroll) {
|
||||
isAdjusting = false;
|
||||
lastChatScroll = container.scrollHeight - container.scrollTop - container.clientHeight;
|
||||
if (lastChatScroll <= 10) {
|
||||
handleDmInteraction();
|
||||
}
|
||||
}
|
||||
|
||||
if (container.scrollTop === 0 && !isLoadingOlderMessages && oldestLoadedMsgId !== null && oldestLoadedMsgId > 0) {
|
||||
|
|
@ -2678,7 +2701,18 @@ function setupWebSocket() {
|
|||
appWebSocket.onmessage = (event) => {
|
||||
let data = event.data;
|
||||
if (data.startsWith("dm_message:")) {
|
||||
let msgDmId = data.substring("dm_message:".length);
|
||||
let parts = data.split(":");
|
||||
let msgDmId = parts[1];
|
||||
let msgType = parts[2] || "unread";
|
||||
|
||||
if (msgType === "unread") {
|
||||
updateDmListUI(msgDmId, false, Date.now().toString());
|
||||
} else if (msgType === "read") {
|
||||
updateDmListUI(msgDmId, true, Date.now().toString());
|
||||
} else if (msgType === "update") {
|
||||
// do nothing to UI sorting/read state
|
||||
}
|
||||
|
||||
if (currentDmId === msgDmId) {
|
||||
if (dmMessageLoadTimeout) clearTimeout(dmMessageLoadTimeout);
|
||||
dmMessageLoadTimeout = setTimeout(() => {
|
||||
|
|
@ -2709,12 +2743,21 @@ function handleMessageContextMenu(e, msgId) {
|
|||
|
||||
showFixedContextMenu({top: e.clientY, right: e.clientX, bottom: e.clientY, left: e.clientX}, messageContextMenu);
|
||||
let delBtn = fixedContextMenu.querySelector("#context-delete-btn");
|
||||
if (delBtn) {
|
||||
if (loadedMessages[msgId] && loadedMessages[msgId].author !== id) {
|
||||
delBtn.style.display = "none";
|
||||
} else {
|
||||
delBtn.style.display = "";
|
||||
let reactBtn = fixedContextMenu.querySelector("#context-react-btn");
|
||||
let msg = loadedMessages[msgId];
|
||||
|
||||
if (msg && msg.type === "larp.redacted") {
|
||||
if (delBtn) delBtn.style.display = "none";
|
||||
if (reactBtn) reactBtn.style.display = "none";
|
||||
} else {
|
||||
if (delBtn) {
|
||||
if (msg && msg.author !== id) {
|
||||
delBtn.style.display = "none";
|
||||
} else {
|
||||
delBtn.style.display = "";
|
||||
}
|
||||
}
|
||||
if (reactBtn) reactBtn.style.display = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2895,6 +2938,11 @@ async function reactMessagePrompt(msgId, quickReaction = null) {
|
|||
showAction("action.message.reacting", "msgreact");
|
||||
try {
|
||||
let currentMsg = loadedMessages[msgId];
|
||||
if (currentMsg && currentMsg.type === "larp.redacted") {
|
||||
clearAction("msgreact");
|
||||
showNotification(processBlah("error.message.already.deleted"), "error");
|
||||
return;
|
||||
}
|
||||
let existingReactions = [];
|
||||
if (currentMsg && currentMsg.reactions) {
|
||||
let rxStr = currentMsg.reactions;
|
||||
|
|
@ -2922,7 +2970,9 @@ async function reactMessagePrompt(msgId, quickReaction = null) {
|
|||
let dmKeyBytes = await sha256Bytes(base64ToUint8(currentDmKey));
|
||||
let encryptedReactions = await encryptAesGcmToBase64(JSON.stringify(existingReactions), dmKeyBytes);
|
||||
|
||||
let originalReactionsEncrypted = "";
|
||||
if (currentMsg) {
|
||||
originalReactionsEncrypted = currentMsg.reactions || "";
|
||||
currentMsg.reactions = encryptedReactions;
|
||||
renderMessages(loadedMessages);
|
||||
}
|
||||
|
|
@ -2935,6 +2985,10 @@ async function reactMessagePrompt(msgId, quickReaction = null) {
|
|||
let res = await fetchEncrypted("dm/message/react", JSON.stringify(msgPayload));
|
||||
if (res && res.startsWith("error:")) {
|
||||
showBlahNotification(res);
|
||||
if (currentMsg) {
|
||||
currentMsg.reactions = originalReactionsEncrypted;
|
||||
renderMessages(loadedMessages);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
showBlahNotification("error:message.react.failed");
|
||||
|
|
@ -3430,4 +3484,69 @@ if (container) {
|
|||
document.addEventListener('touchmove', onDrag, {passive: true});
|
||||
document.addEventListener('mouseup', endDrag);
|
||||
document.addEventListener('touchend', endDrag);
|
||||
}
|
||||
}
|
||||
|
||||
function updateDmListUI(dmId, isRead, timestamp = null) {
|
||||
try {
|
||||
if (!window.cachedDms) return;
|
||||
let parsedDms = JSON.parse(window.cachedDms);
|
||||
if (!parsedDms.dms || !parsedDms.dms[dmId]) return;
|
||||
|
||||
let changed = false;
|
||||
if (parsedDms.dms[dmId].string3 !== (isRead ? "true" : "false")) {
|
||||
parsedDms.dms[dmId].string3 = isRead ? "true" : "false";
|
||||
changed = true;
|
||||
}
|
||||
if (timestamp && parsedDms.dms[dmId].string2 !== timestamp) {
|
||||
parsedDms.dms[dmId].string2 = timestamp;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
window.cachedDms = JSON.stringify(parsedDms);
|
||||
}
|
||||
|
||||
let btn = document.getElementById(`dm-btn-${dmId}`);
|
||||
let container = document.getElementById("dms-list");
|
||||
if (btn && container) {
|
||||
let nameSpan = btn.querySelector('.room-name');
|
||||
if (nameSpan) {
|
||||
nameSpan.style.opacity = isRead ? "0.8" : "1";
|
||||
}
|
||||
if (timestamp) {
|
||||
container.prepend(btn);
|
||||
}
|
||||
} else {
|
||||
if (typeof refreshDms === 'function') refreshDms(0, false);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (typeof refreshDms === 'function') refreshDms(0, false);
|
||||
}
|
||||
}
|
||||
|
||||
function markDmAsRead(dmId) {
|
||||
fetchEncrypted("dm/read", JSON.stringify({string1: dmId})).catch(()=>{});
|
||||
updateDmListUI(dmId, true);
|
||||
}
|
||||
|
||||
function handleDmInteraction() {
|
||||
if (!currentDmId) return;
|
||||
let container = document.getElementById("chat-messages");
|
||||
if (!container) return;
|
||||
|
||||
if (lastChatScroll <= 10) {
|
||||
try {
|
||||
if (window.cachedDms) {
|
||||
let parsedDms = JSON.parse(window.cachedDms);
|
||||
if (parsedDms.dms && parsedDms.dms[currentDmId] && parsedDms.dms[currentDmId].string3 !== "true") {
|
||||
markDmAsRead(currentDmId);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', handleDmInteraction);
|
||||
document.addEventListener('keydown', handleDmInteraction);
|
||||
document.addEventListener('touchstart', handleDmInteraction);
|
||||
Loading…
Add table
Add a link
Reference in a new issue