indicators
This commit is contained in:
parent
4358d49b48
commit
af46da77a7
6 changed files with 216 additions and 26 deletions
|
|
@ -32,6 +32,7 @@ const state = {
|
|||
chatWs: null,
|
||||
lastMessageId: null,
|
||||
onlineUsers: new Set(),
|
||||
idleUsers: new Set(),
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -363,7 +364,7 @@ function renderChannels() {
|
|||
const pRow = document.createElement("div");
|
||||
pRow.className = `channel-row ${p.is_speaking ? 'voice-speaking' : ''}`;
|
||||
pRow.style.padding = "2px 8px";
|
||||
pRow.innerHTML = `<div class="avatar" style="width:20px;height:20px;font-size:10px">${shortName(p.display_name)}</div> <span>${escapeHtml(p.display_name)}</span>`;
|
||||
pRow.innerHTML = `<div class="avatar" style="width:20px;height:20px;font-size:10px">${shortName(p.display_name)}</div> <span>${escapeHtml(p.display_name)}</span>${p.is_muted ? '<i data-lucide="mic-off" class="voice-muted-icon"></i>' : ''}`;
|
||||
pList.appendChild(pRow);
|
||||
}
|
||||
el.voiceChannelList.appendChild(pList);
|
||||
|
|
@ -377,12 +378,13 @@ function renderDMs() {
|
|||
el.dmList.innerHTML = "";
|
||||
for (const dm of state.dmConversations) {
|
||||
const isOnline = state.onlineUsers.has(dm.user_id);
|
||||
const isIdle = state.idleUsers.has(dm.user_id);
|
||||
const row = document.createElement("button");
|
||||
row.className = `channel-row ${state.selectedDmUserId === dm.user_id ? "active" : ""}`;
|
||||
row.innerHTML = `
|
||||
<div class="avatar-wrapper">
|
||||
<i data-lucide="message-circle"></i>
|
||||
<div class="status-dot ${isOnline ? "online" : ""}"></div>
|
||||
<div class="status-dot ${isOnline ? (isIdle ? 'idle' : 'online') : ''}"></div>
|
||||
</div>
|
||||
<span>${escapeHtml(dm.display_name)}</span>
|
||||
`;
|
||||
|
|
@ -450,12 +452,13 @@ function renderMembers() {
|
|||
el.memberList.innerHTML = "";
|
||||
for (const m of state.members) {
|
||||
const isOnline = state.onlineUsers.has(m.id);
|
||||
const isIdle = state.idleUsers.has(m.id);
|
||||
const row = document.createElement("div");
|
||||
row.className = "member-row";
|
||||
row.innerHTML = `
|
||||
<div class="member-avatar">
|
||||
${shortName(m.display_name)}
|
||||
<div class="status-dot ${isOnline ? "online" : ""}"></div>
|
||||
<div class="status-dot ${isOnline ? (isIdle ? 'idle' : 'online') : ''}"></div>
|
||||
</div>
|
||||
<div class="member-name">${escapeHtml(m.display_name)}</div>
|
||||
`;
|
||||
|
|
@ -626,8 +629,14 @@ function initChatWs() {
|
|||
} else if (msg.type === "user_presence") {
|
||||
if (msg.online) {
|
||||
state.onlineUsers.add(msg.user_id);
|
||||
if (msg.idle) {
|
||||
state.idleUsers.add(msg.user_id);
|
||||
} else {
|
||||
state.idleUsers.delete(msg.user_id);
|
||||
}
|
||||
} else {
|
||||
state.onlineUsers.delete(msg.user_id);
|
||||
state.idleUsers.delete(msg.user_id);
|
||||
}
|
||||
renderMembers();
|
||||
renderDMs();
|
||||
|
|
@ -1086,8 +1095,8 @@ async function joinVoice() {
|
|||
return;
|
||||
}
|
||||
if (state.voice.joinedChannelId === state.selectedVoiceChannelId &&
|
||||
state.voice.ws &&
|
||||
state.voice.ws.readyState === WebSocket.OPEN) {
|
||||
state.voice.ws &&
|
||||
state.voice.ws.readyState === WebSocket.OPEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1190,6 +1199,11 @@ async function joinVoice() {
|
|||
if (videoEl) {
|
||||
videoEl.parentElement.classList.toggle('speaking', msg.is_speaking);
|
||||
}
|
||||
} else if (msg.type === "mute_status_changed") {
|
||||
state.voicePresence.get(state.selectedVoiceChannelId)?.forEach(p => {
|
||||
if (p.user_id === msg.user_id) p.is_muted = msg.is_muted;
|
||||
});
|
||||
renderChannels();
|
||||
} else if (msg.type === "play_sound") {
|
||||
const audio = new Audio(msg.sound_url);
|
||||
audio.play().catch(console.error);
|
||||
|
|
@ -1238,6 +1252,9 @@ function toggleMute() {
|
|||
state.voice.localStream.getAudioTracks().forEach((t) => {
|
||||
t.enabled = !state.voice.muted;
|
||||
});
|
||||
if (state.voice.ws && state.voice.ws.readyState === WebSocket.OPEN) {
|
||||
state.voice.ws.send(JSON.stringify({ type: "set_mute_status", is_muted: state.voice.muted }));
|
||||
}
|
||||
el.voiceMuteBtn.innerHTML = state.voice.muted ? '<i data-lucide="mic-off"></i>' : '<i data-lucide="mic"></i>';
|
||||
el.voiceMuteBtn.style.color = state.voice.muted ? 'var(--danger)' : 'var(--text-muted)';
|
||||
lucide.createIcons();
|
||||
|
|
@ -1443,6 +1460,30 @@ function closeMobileMenus() {
|
|||
|
||||
// --- Initialization ---
|
||||
|
||||
let inactivityTimer = null;
|
||||
let isCurrentlyIdle = false;
|
||||
|
||||
function resetInactivityTimer() {
|
||||
if (isCurrentlyIdle) {
|
||||
isCurrentlyIdle = false;
|
||||
if (state.chatWs && state.chatWs.readyState === WebSocket.OPEN) {
|
||||
state.chatWs.send(JSON.stringify({ type: "set_idle_status", is_idle: false }));
|
||||
}
|
||||
}
|
||||
|
||||
if (inactivityTimer) clearTimeout(inactivityTimer);
|
||||
inactivityTimer = setTimeout(() => {
|
||||
isCurrentlyIdle = true;
|
||||
if (state.chatWs && state.chatWs.readyState === WebSocket.OPEN) {
|
||||
state.chatWs.send(JSON.stringify({ type: "set_idle_status", is_idle: true }));
|
||||
}
|
||||
}, 5 * 60 * 1000); // 5 minutes
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', resetInactivityTimer);
|
||||
document.addEventListener('keydown', resetInactivityTimer);
|
||||
document.addEventListener('click', resetInactivityTimer);
|
||||
|
||||
async function init() {
|
||||
lucide.createIcons();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue