Split activity status from session summary
This commit is contained in:
+4
-2
@@ -180,19 +180,21 @@ When KEEP-OPEN is nil, close PROCESS after writing."
|
||||
(defun kkkmeet-server--remove-peer (process)
|
||||
"Remove PROCESS from its room and notify remaining peers."
|
||||
(let ((room-id (process-get process :kkkmeet-room-id))
|
||||
(peer-id (process-get process :kkkmeet-peer-id)))
|
||||
(peer-id (process-get process :kkkmeet-peer-id))
|
||||
(name (or (process-get process :kkkmeet-name) "A participant")))
|
||||
(when (and room-id peer-id)
|
||||
(let ((room (gethash room-id kkkmeet-server--rooms)))
|
||||
(when room
|
||||
(remhash peer-id room)
|
||||
(kkkmeet-server--broadcast
|
||||
room-id peer-id `((type . "peer-left") (peerId . ,peer-id)))
|
||||
room-id peer-id `((type . "peer-left") (peerId . ,peer-id) (name . ,name)))
|
||||
(when (equal (alist-get 'peerId (gethash room-id kkkmeet-server--presentation-states))
|
||||
peer-id)
|
||||
(remhash room-id kkkmeet-server--presentation-states)
|
||||
(kkkmeet-server--broadcast
|
||||
room-id peer-id `((type . "presentation-state")
|
||||
(from . ,peer-id)
|
||||
(name . ,name)
|
||||
(sharing . :false))))
|
||||
(when (= (hash-table-count room) 0)
|
||||
(remhash room-id kkkmeet-server--rooms)
|
||||
|
||||
+47
-10
@@ -10,6 +10,7 @@ const nameDialogSubmit = document.querySelector("#name-dialog-submit");
|
||||
const initialNameForm = document.querySelector("#initial-name-form");
|
||||
const initialNameInput = document.querySelector("#initial-name-input");
|
||||
const statusText = document.querySelector("#status");
|
||||
const activityStatusText = document.querySelector("#activity-status");
|
||||
const youtubeForm = document.querySelector("#youtube-form");
|
||||
const youtubeInput = document.querySelector("#youtube-input");
|
||||
const youtubeShell = document.querySelector("#youtube-shell");
|
||||
@@ -73,6 +74,7 @@ let youtubeReadyResolvers = [];
|
||||
let watchApplySequence = 0;
|
||||
let youtubePlaybackRequestId = 0;
|
||||
let watchPlaylist = [];
|
||||
let remoteParticipantCount = 0;
|
||||
const peers = new Map();
|
||||
|
||||
function persistentClientId() {
|
||||
@@ -133,6 +135,26 @@ function setStatus(message) {
|
||||
statusText.textContent = message;
|
||||
}
|
||||
|
||||
function participantDisplayName(name, fallback = "Someone") {
|
||||
return normalizeName(String(name || "")) || fallback;
|
||||
}
|
||||
|
||||
function setSessionSummary() {
|
||||
if (!peerId) {
|
||||
setStatus(displayName ? `Ready as ${displayName}.` : "Enter your name to join the call.");
|
||||
return;
|
||||
}
|
||||
const suffix = remoteParticipantCount === 1 ? "participant" : "participants";
|
||||
setStatus(`You are ${displayName}. ${remoteParticipantCount} other ${suffix}.`);
|
||||
}
|
||||
|
||||
function setActivity(name, action) {
|
||||
const actor = participantDisplayName(name);
|
||||
const message = `${actor} ${action}`;
|
||||
activityStatusText.textContent = message;
|
||||
console.info(`[kkkmeet activity] ${message}`);
|
||||
}
|
||||
|
||||
function normalizeName(name) {
|
||||
return name.trim().replace(/\s+/g, " ").slice(0, 48);
|
||||
}
|
||||
@@ -177,6 +199,7 @@ function setDisplayName(nextName) {
|
||||
displayName = normalizeName(nextName);
|
||||
localStorage.setItem(nameStorageKey, displayName);
|
||||
localNameLabel.textContent = displayName ? `${displayName} (you)` : "You";
|
||||
setSessionSummary();
|
||||
}
|
||||
|
||||
function openNameDialog(mode) {
|
||||
@@ -528,6 +551,7 @@ async function sendWatchState({
|
||||
updatedAt: Date.now()
|
||||
})
|
||||
});
|
||||
setActivity(displayName, "synced YouTube playback.");
|
||||
}
|
||||
|
||||
function currentWatchState(playing) {
|
||||
@@ -1150,7 +1174,9 @@ async function answerPeer(message) {
|
||||
async function handleSignal(message) {
|
||||
if (message.type === "welcome") {
|
||||
peerId = message.peerId;
|
||||
setStatus(`Joined the call as ${displayName}. ${message.peers.length} other participant(s).`);
|
||||
remoteParticipantCount = message.peers.length;
|
||||
setSessionSummary();
|
||||
setActivity(displayName, "joined.");
|
||||
if (message.watchState) {
|
||||
const watchShouldPlay = message.watchState.action === "play" ||
|
||||
(!message.watchState.action && Boolean(message.watchState.playing));
|
||||
@@ -1175,13 +1201,20 @@ async function handleSignal(message) {
|
||||
if (message.type === "peer-joined") {
|
||||
updateRemoteLabel(message.peerId, message.name);
|
||||
announceParticipantJoined(message.name);
|
||||
setStatus(`${message.name || "A participant"} joined.`);
|
||||
remoteParticipantCount += 1;
|
||||
setSessionSummary();
|
||||
setActivity(message.name, "joined.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type === "peer-left") {
|
||||
const peerName = message.name ||
|
||||
peers.get(message.peerId)?.name ||
|
||||
`Participant ${message.peerId?.slice(0, 4) || ""}`.trim();
|
||||
closePeer(message.peerId);
|
||||
setStatus("A participant left.");
|
||||
remoteParticipantCount = Math.max(0, remoteParticipantCount - 1);
|
||||
setSessionSummary();
|
||||
setActivity(peerName, "left.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1197,21 +1230,22 @@ async function handleSignal(message) {
|
||||
allowJoinedYoutubeStartPrompt = false;
|
||||
}
|
||||
await applyWatchState(message, { allowStartPrompt });
|
||||
setStatus(`${message.name || "Someone"} synced YouTube playback.`);
|
||||
setActivity(message.name, "synced YouTube playback.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type === "presentation-state") {
|
||||
setRemotePresentation(message.from, message.sharing, message.name);
|
||||
setStatus(message.sharing
|
||||
? `${message.name || "Someone"} is sharing their screen.`
|
||||
: `${message.name || "Someone"} stopped sharing their screen.`);
|
||||
setActivity(
|
||||
message.name,
|
||||
message.sharing ? "started sharing their screen." : "stopped sharing their screen."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type === "voice-announcement") {
|
||||
speakAnnouncement(message);
|
||||
setStatus(`${message.name || "Someone"} sent an announcement.`);
|
||||
setActivity(message.name, "sent an announcement.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1260,8 +1294,9 @@ function leaveCall() {
|
||||
events?.close();
|
||||
events = undefined;
|
||||
peerId = "";
|
||||
remoteParticipantCount = 0;
|
||||
for (const remotePeerId of peers.keys()) closePeer(remotePeerId);
|
||||
setStatus(displayName ? `Ready as ${displayName}.` : "Enter your name to join the call.");
|
||||
setSessionSummary();
|
||||
}
|
||||
|
||||
function setTrackEnabled(kind, enabled) {
|
||||
@@ -1356,7 +1391,7 @@ async function sendVoiceAnnouncement(text) {
|
||||
|
||||
await sendRoomEvent({ type: "voice-announcement", text: announcementText });
|
||||
speakAnnouncement({ text: announcementText });
|
||||
setStatus("Announcement sent.");
|
||||
setActivity(displayName, "sent an announcement.");
|
||||
}
|
||||
|
||||
async function startScreenShare() {
|
||||
@@ -1368,6 +1403,7 @@ async function startScreenShare() {
|
||||
await replaceOutboundVideoTrack(screenTrack);
|
||||
shareButton.textContent = "Stop Sharing";
|
||||
await sendRoomEvent({ type: "presentation-state", sharing: true });
|
||||
setActivity(displayName, "started sharing their screen.");
|
||||
|
||||
screenTrack.onended = () => {
|
||||
stopScreenShare().catch((error) => {
|
||||
@@ -1389,6 +1425,7 @@ async function stopScreenShare() {
|
||||
}
|
||||
shareButton.textContent = "Share Screen";
|
||||
await sendRoomEvent({ type: "presentation-state", sharing: false });
|
||||
setActivity(displayName, "stopped sharing their screen.");
|
||||
}
|
||||
|
||||
initialNameForm.addEventListener("submit", (event) => {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<div>
|
||||
<h1>kkkmeet</h1>
|
||||
<p id="status">Enter your name to join the call.</p>
|
||||
<p id="activity-status" aria-live="polite"></p>
|
||||
</div>
|
||||
<button id="rename-button" type="button">Rename</button>
|
||||
</header>
|
||||
|
||||
@@ -62,6 +62,13 @@ h1 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#activity-status {
|
||||
min-height: 18px;
|
||||
margin-top: 3px;
|
||||
color: #d5dbe3;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#rename-button {
|
||||
min-width: 92px;
|
||||
}
|
||||
|
||||
@@ -84,11 +84,13 @@ function removePeer(roomId, peerId) {
|
||||
const room = rooms.get(roomId);
|
||||
if (!room) return;
|
||||
|
||||
const peer = room.get(peerId);
|
||||
const name = peer?.name || "A participant";
|
||||
room.delete(peerId);
|
||||
broadcast(roomId, peerId, { type: "peer-left", peerId });
|
||||
broadcast(roomId, peerId, { type: "peer-left", peerId, name });
|
||||
if (presentationStates.get(roomId)?.peerId === peerId) {
|
||||
presentationStates.delete(roomId);
|
||||
broadcast(roomId, peerId, { type: "presentation-state", from: peerId, sharing: false });
|
||||
broadcast(roomId, peerId, { type: "presentation-state", from: peerId, name, sharing: false });
|
||||
}
|
||||
|
||||
if (room.size === 0) {
|
||||
|
||||
Reference in New Issue
Block a user