Spaces:
Runtime error
Runtime error
Simplify call flow: use live call window with in-app status and event logs (v2.8.4)
Browse files- client.js +62 -27
- index.html +16 -2
- package.json +1 -1
client.js
CHANGED
|
@@ -33,6 +33,7 @@ let forceRelayOnly = false;
|
|
| 33 |
let pendingIceRecoveryTimer = null;
|
| 34 |
let pendingRelayFallbackTimer = null;
|
| 35 |
let pendingRemoteIceCandidates = [];
|
|
|
|
| 36 |
let hasUserInteractedWithPage = false;
|
| 37 |
let activeRoomSubscription = null;
|
| 38 |
let roomMessages = JSON.parse(localStorage.getItem('roomMessages') || '{}');
|
|
@@ -366,6 +367,22 @@ function ensureLocalPreviewPlayback(videoEl) {
|
|
| 366 |
setTimeout(tryPlay, 500);
|
| 367 |
}
|
| 368 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 369 |
let callControlBindingsDone = false;
|
| 370 |
function bindCallControlButtons() {
|
| 371 |
if (callControlBindingsDone) return;
|
|
@@ -6111,34 +6128,24 @@ function openVideoCallModal(targetName, targetId, callType) {
|
|
| 6111 |
targetName = targetName || currentChatContext.name || 'User';
|
| 6112 |
targetId = targetId || currentChatContext.id;
|
| 6113 |
callType = callType || 'Video Call';
|
| 6114 |
-
|
| 6115 |
-
|
| 6116 |
-
|
| 6117 |
-
|
| 6118 |
-
|
| 6119 |
-
|
| 6120 |
-
|
| 6121 |
-
|
| 6122 |
-
|
| 6123 |
-
|
| 6124 |
-
|
| 6125 |
-
|
| 6126 |
-
</div>
|
| 6127 |
-
<button onclick="endVideoCall();" style="margin-top: 20px; padding: 12px 30px; background: var(--danger); color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 600; font-size: 14px;">
|
| 6128 |
-
β Cancel Call
|
| 6129 |
-
</button>
|
| 6130 |
-
</div>
|
| 6131 |
-
<style>
|
| 6132 |
-
@keyframes pulse {
|
| 6133 |
-
0%, 100% { transform: scale(1); }
|
| 6134 |
-
50% { transform: scale(1.05); }
|
| 6135 |
}
|
| 6136 |
-
|
| 6137 |
-
|
| 6138 |
-
|
| 6139 |
-
|
| 6140 |
-
|
| 6141 |
-
|
| 6142 |
if (socket && socket.connected && targetId) {
|
| 6143 |
socket.emit('start video call', {
|
| 6144 |
targetId: targetId,
|
|
@@ -6147,6 +6154,7 @@ function openVideoCallModal(targetName, targetId, callType) {
|
|
| 6147 |
});
|
| 6148 |
activeCallState = { callId: null, peerId: targetId, direction: 'outgoing' };
|
| 6149 |
showToast(`π Calling ${targetName}...`, 'success');
|
|
|
|
| 6150 |
}
|
| 6151 |
}
|
| 6152 |
|
|
@@ -6170,6 +6178,7 @@ function handleIncomingVideoCall(payload) {
|
|
| 6170 |
|
| 6171 |
if (accepted) {
|
| 6172 |
stopIncomingCallAlert();
|
|
|
|
| 6173 |
socket.emit('accept video call', {
|
| 6174 |
callId: activeCallState.callId,
|
| 6175 |
toId: activeCallState.peerId
|
|
@@ -6325,6 +6334,7 @@ function createPeerConnection(peerId) {
|
|
| 6325 |
if (event.track && remoteCallStream) {
|
| 6326 |
if (!remoteCallStream.getTrackById(event.track.id)) {
|
| 6327 |
remoteCallStream.addTrack(event.track);
|
|
|
|
| 6328 |
}
|
| 6329 |
}
|
| 6330 |
const remoteVideo = document.getElementById('remoteCallVideo');
|
|
@@ -6353,9 +6363,12 @@ function createPeerConnection(peerId) {
|
|
| 6353 |
return;
|
| 6354 |
}
|
| 6355 |
if (peerConnection.connectionState === 'connecting') {
|
|
|
|
| 6356 |
showToast('π Connecting call...', 'info');
|
| 6357 |
} else if (peerConnection.connectionState === 'connected') {
|
| 6358 |
callIceFailureCount = 0;
|
|
|
|
|
|
|
| 6359 |
showToast('π Call connected!', 'success');
|
| 6360 |
// Start timer only if not already running (avoids resetting a running clock)
|
| 6361 |
if (!callTimerInterval) {
|
|
@@ -6374,6 +6387,8 @@ function createPeerConnection(peerId) {
|
|
| 6374 |
}
|
| 6375 |
}
|
| 6376 |
} else if (peerConnection.connectionState === 'failed') {
|
|
|
|
|
|
|
| 6377 |
showCallWarningThrottled('β οΈ Network issue detected, retrying call connection...');
|
| 6378 |
attemptIceRecovery(peerId);
|
| 6379 |
} else if (peerConnection.connectionState === 'closed') {
|
|
@@ -6385,6 +6400,7 @@ function createPeerConnection(peerId) {
|
|
| 6385 |
peerConnection.oniceconnectionstatechange = () => {
|
| 6386 |
if (!peerConnection) return;
|
| 6387 |
console.log('ICE connection state:', peerConnection.iceConnectionState);
|
|
|
|
| 6388 |
|
| 6389 |
if (peerConnection.iceConnectionState === 'connected' || peerConnection.iceConnectionState === 'completed') {
|
| 6390 |
callIceFailureCount = 0;
|
|
@@ -6412,6 +6428,7 @@ function createPeerConnection(peerId) {
|
|
| 6412 |
iceTransportPolicy: 'all'
|
| 6413 |
});
|
| 6414 |
showToast('Retrying call with mixed network mode...', 'warning');
|
|
|
|
| 6415 |
attemptIceRecovery(peerId);
|
| 6416 |
} catch (fallbackError) {
|
| 6417 |
console.warn('Relay fallback failed:', fallbackError);
|
|
@@ -6460,8 +6477,10 @@ function createPeerConnection(peerId) {
|
|
| 6460 |
iceTransportPolicy: 'relay'
|
| 6461 |
});
|
| 6462 |
showToast('Switching call to relay mode for network compatibility...', 'warning');
|
|
|
|
| 6463 |
} else if (callIceFailureCount >= 2 && !hasTurnServersConfigured) {
|
| 6464 |
showToast('Retrying call without relay fallback...', 'warning');
|
|
|
|
| 6465 |
}
|
| 6466 |
|
| 6467 |
peerConnection.restartIce?.();
|
|
@@ -6473,6 +6492,7 @@ function createPeerConnection(peerId) {
|
|
| 6473 |
offerToReceiveVideo: true
|
| 6474 |
});
|
| 6475 |
await peerConnection.setLocalDescription(recoveryOffer);
|
|
|
|
| 6476 |
|
| 6477 |
socket.emit('video signal', {
|
| 6478 |
toId: recoveryPeerId,
|
|
@@ -6491,14 +6511,19 @@ function openCallDialog(peerName) {
|
|
| 6491 |
const overlay = document.getElementById('callOverlay');
|
| 6492 |
if (overlay) {
|
| 6493 |
overlay.classList.toggle('desktop-window', window.innerWidth > 700);
|
|
|
|
| 6494 |
document.getElementById('callOverlayPeerName').textContent = `π ${peerName}`;
|
| 6495 |
document.getElementById('callTimerLabel').textContent = '00:00:00';
|
|
|
|
| 6496 |
const muteBtn = document.getElementById('muteBtn');
|
| 6497 |
if (muteBtn) { muteBtn.textContent = 'π€'; muteBtn.classList.remove('muted'); }
|
| 6498 |
const camBtn = document.getElementById('cameraBtn');
|
| 6499 |
if (camBtn) { camBtn.textContent = 'π·'; camBtn.classList.remove('cam-off'); }
|
| 6500 |
isCallCameraOff = false;
|
| 6501 |
overlay.classList.add('active');
|
|
|
|
|
|
|
|
|
|
| 6502 |
}
|
| 6503 |
}
|
| 6504 |
|
|
@@ -6515,6 +6540,7 @@ async function startCallSession(peerName, peerId, isCaller) {
|
|
| 6515 |
callIceFailureCount = 0;
|
| 6516 |
await ensureRtcConfigLoaded();
|
| 6517 |
forceRelayOnly = rtcRuntimeConfig?.iceTransportPolicy === 'relay';
|
|
|
|
| 6518 |
|
| 6519 |
openCallDialog(peerName);
|
| 6520 |
// Start timer from session start to avoid "stuck at 00:00" perception on unstable networks.
|
|
@@ -6527,6 +6553,7 @@ async function startCallSession(peerName, peerId, isCaller) {
|
|
| 6527 |
// Do not abort the call - continue in receive-only mode so user can still hear/see remote party.
|
| 6528 |
console.warn('Local media unavailable, continuing receive-only call:', mediaError);
|
| 6529 |
localCallStream = null;
|
|
|
|
| 6530 |
showToast('Starting call in receive-only mode (local camera/mic unavailable)', 'warning');
|
| 6531 |
}
|
| 6532 |
|
|
@@ -6539,6 +6566,7 @@ async function startCallSession(peerName, peerId, isCaller) {
|
|
| 6539 |
}
|
| 6540 |
|
| 6541 |
createPeerConnection(peerId);
|
|
|
|
| 6542 |
|
| 6543 |
if (isCaller && peerConnection) {
|
| 6544 |
makingOffer = true;
|
|
@@ -6548,6 +6576,7 @@ async function startCallSession(peerName, peerId, isCaller) {
|
|
| 6548 |
offerToReceiveVideo: true
|
| 6549 |
});
|
| 6550 |
await peerConnection.setLocalDescription(offer);
|
|
|
|
| 6551 |
socket.emit('video signal', {
|
| 6552 |
toId: peerId,
|
| 6553 |
callId: activeCallState?.callId,
|
|
@@ -6564,9 +6593,11 @@ async function startCallSession(peerName, peerId, isCaller) {
|
|
| 6564 |
pendingSignalOffer = null;
|
| 6565 |
try {
|
| 6566 |
await peerConnection.setRemoteDescription(new RTCSessionDescription(po.offer));
|
|
|
|
| 6567 |
await flushQueuedIceCandidates();
|
| 6568 |
const answer = await peerConnection.createAnswer();
|
| 6569 |
await peerConnection.setLocalDescription(answer);
|
|
|
|
| 6570 |
socket.emit('video signal', {
|
| 6571 |
toId: po.fromId,
|
| 6572 |
callId: activeCallState?.callId,
|
|
@@ -6676,6 +6707,8 @@ function refreshCallDebug() {
|
|
| 6676 |
<div class="dbg-row">πΊ Remote Video: ${vidState}</div>
|
| 6677 |
<div class="dbg-row">π Socket: ${socketStr}</div>
|
| 6678 |
<div class="dbg-row">β± Call duration: ${document.getElementById('callTimerLabel')?.textContent || 'n/a'}</div>
|
|
|
|
|
|
|
| 6679 |
<div style="margin-top:8px;">
|
| 6680 |
<button onclick="forceRestartIce()" style="background:#00ff88;color:#000;border:none;padding:4px 10px;border-radius:4px;cursor:pointer;font-size:10px;font-weight:700;">π Restart ICE</button>
|
| 6681 |
<button onclick="refreshCallDebug()" style="background:rgba(255,255,255,0.2);color:#fff;border:none;padding:4px 10px;border-radius:4px;cursor:pointer;font-size:10px;margin-left:4px;">β» Refresh</button>
|
|
@@ -6740,6 +6773,8 @@ function cleanupCallSession(keepDialogOpen = false) {
|
|
| 6740 |
currentCallPeerId = null;
|
| 6741 |
currentCallPeerName = null;
|
| 6742 |
activeCallState = null;
|
|
|
|
|
|
|
| 6743 |
|
| 6744 |
// Close the overlay
|
| 6745 |
const overlay = document.getElementById('callOverlay');
|
|
|
|
| 33 |
let pendingIceRecoveryTimer = null;
|
| 34 |
let pendingRelayFallbackTimer = null;
|
| 35 |
let pendingRemoteIceCandidates = [];
|
| 36 |
+
let callEventLog = [];
|
| 37 |
let hasUserInteractedWithPage = false;
|
| 38 |
let activeRoomSubscription = null;
|
| 39 |
let roomMessages = JSON.parse(localStorage.getItem('roomMessages') || '{}');
|
|
|
|
| 367 |
setTimeout(tryPlay, 500);
|
| 368 |
}
|
| 369 |
|
| 370 |
+
function appendCallLog(message) {
|
| 371 |
+
const entry = `[${new Date().toLocaleTimeString()}] ${message}`;
|
| 372 |
+
callEventLog.push(entry);
|
| 373 |
+
if (callEventLog.length > 20) {
|
| 374 |
+
callEventLog = callEventLog.slice(-20);
|
| 375 |
+
}
|
| 376 |
+
refreshCallDebug();
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
function setCallStatus(statusText) {
|
| 380 |
+
const statusLabel = document.getElementById('callStatusLabel');
|
| 381 |
+
if (statusLabel) {
|
| 382 |
+
statusLabel.textContent = statusText || '';
|
| 383 |
+
}
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
let callControlBindingsDone = false;
|
| 387 |
function bindCallControlButtons() {
|
| 388 |
if (callControlBindingsDone) return;
|
|
|
|
| 6128 |
targetName = targetName || currentChatContext.name || 'User';
|
| 6129 |
targetId = targetId || currentChatContext.id;
|
| 6130 |
callType = callType || 'Video Call';
|
| 6131 |
+
openCallDialog(targetName);
|
| 6132 |
+
setCallStatus('Dialing...');
|
| 6133 |
+
appendCallLog(`Outgoing ${callType.toLowerCase()} to ${targetName}`);
|
| 6134 |
+
|
| 6135 |
+
ensureRtcConfigLoaded()
|
| 6136 |
+
.then(() => ensureLocalCallStream())
|
| 6137 |
+
.then(() => {
|
| 6138 |
+
const localVideo = document.getElementById('localCallVideo');
|
| 6139 |
+
if (localVideo && localCallStream) {
|
| 6140 |
+
localVideo.srcObject = localCallStream;
|
| 6141 |
+
ensureLocalPreviewPlayback(localVideo);
|
| 6142 |
+
appendCallLog('Local preview started before answer');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6143 |
}
|
| 6144 |
+
})
|
| 6145 |
+
.catch((error) => {
|
| 6146 |
+
appendCallLog(`Local preview unavailable: ${error?.message || error}`);
|
| 6147 |
+
});
|
| 6148 |
+
|
|
|
|
| 6149 |
if (socket && socket.connected && targetId) {
|
| 6150 |
socket.emit('start video call', {
|
| 6151 |
targetId: targetId,
|
|
|
|
| 6154 |
});
|
| 6155 |
activeCallState = { callId: null, peerId: targetId, direction: 'outgoing' };
|
| 6156 |
showToast(`π Calling ${targetName}...`, 'success');
|
| 6157 |
+
appendCallLog('Call request emitted to signaling server');
|
| 6158 |
}
|
| 6159 |
}
|
| 6160 |
|
|
|
|
| 6178 |
|
| 6179 |
if (accepted) {
|
| 6180 |
stopIncomingCallAlert();
|
| 6181 |
+
appendCallLog(`Accepted incoming call from ${callerName}`);
|
| 6182 |
socket.emit('accept video call', {
|
| 6183 |
callId: activeCallState.callId,
|
| 6184 |
toId: activeCallState.peerId
|
|
|
|
| 6334 |
if (event.track && remoteCallStream) {
|
| 6335 |
if (!remoteCallStream.getTrackById(event.track.id)) {
|
| 6336 |
remoteCallStream.addTrack(event.track);
|
| 6337 |
+
appendCallLog(`Remote ${event.track.kind} track received`);
|
| 6338 |
}
|
| 6339 |
}
|
| 6340 |
const remoteVideo = document.getElementById('remoteCallVideo');
|
|
|
|
| 6363 |
return;
|
| 6364 |
}
|
| 6365 |
if (peerConnection.connectionState === 'connecting') {
|
| 6366 |
+
setCallStatus('Connecting...');
|
| 6367 |
showToast('π Connecting call...', 'info');
|
| 6368 |
} else if (peerConnection.connectionState === 'connected') {
|
| 6369 |
callIceFailureCount = 0;
|
| 6370 |
+
setCallStatus('Connected');
|
| 6371 |
+
appendCallLog('Peer connection connected');
|
| 6372 |
showToast('π Call connected!', 'success');
|
| 6373 |
// Start timer only if not already running (avoids resetting a running clock)
|
| 6374 |
if (!callTimerInterval) {
|
|
|
|
| 6387 |
}
|
| 6388 |
}
|
| 6389 |
} else if (peerConnection.connectionState === 'failed') {
|
| 6390 |
+
setCallStatus('Connection failed');
|
| 6391 |
+
appendCallLog('Peer connection failed, starting recovery');
|
| 6392 |
showCallWarningThrottled('β οΈ Network issue detected, retrying call connection...');
|
| 6393 |
attemptIceRecovery(peerId);
|
| 6394 |
} else if (peerConnection.connectionState === 'closed') {
|
|
|
|
| 6400 |
peerConnection.oniceconnectionstatechange = () => {
|
| 6401 |
if (!peerConnection) return;
|
| 6402 |
console.log('ICE connection state:', peerConnection.iceConnectionState);
|
| 6403 |
+
appendCallLog(`ICE state: ${peerConnection.iceConnectionState}`);
|
| 6404 |
|
| 6405 |
if (peerConnection.iceConnectionState === 'connected' || peerConnection.iceConnectionState === 'completed') {
|
| 6406 |
callIceFailureCount = 0;
|
|
|
|
| 6428 |
iceTransportPolicy: 'all'
|
| 6429 |
});
|
| 6430 |
showToast('Retrying call with mixed network mode...', 'warning');
|
| 6431 |
+
appendCallLog('Fallback from relay-only to mixed mode');
|
| 6432 |
attemptIceRecovery(peerId);
|
| 6433 |
} catch (fallbackError) {
|
| 6434 |
console.warn('Relay fallback failed:', fallbackError);
|
|
|
|
| 6477 |
iceTransportPolicy: 'relay'
|
| 6478 |
});
|
| 6479 |
showToast('Switching call to relay mode for network compatibility...', 'warning');
|
| 6480 |
+
appendCallLog('Switching to relay mode for recovery');
|
| 6481 |
} else if (callIceFailureCount >= 2 && !hasTurnServersConfigured) {
|
| 6482 |
showToast('Retrying call without relay fallback...', 'warning');
|
| 6483 |
+
appendCallLog('No TURN available, retrying direct ICE only');
|
| 6484 |
}
|
| 6485 |
|
| 6486 |
peerConnection.restartIce?.();
|
|
|
|
| 6492 |
offerToReceiveVideo: true
|
| 6493 |
});
|
| 6494 |
await peerConnection.setLocalDescription(recoveryOffer);
|
| 6495 |
+
appendCallLog('ICE restart offer created and sent');
|
| 6496 |
|
| 6497 |
socket.emit('video signal', {
|
| 6498 |
toId: recoveryPeerId,
|
|
|
|
| 6511 |
const overlay = document.getElementById('callOverlay');
|
| 6512 |
if (overlay) {
|
| 6513 |
overlay.classList.toggle('desktop-window', window.innerWidth > 700);
|
| 6514 |
+
callEventLog = [];
|
| 6515 |
document.getElementById('callOverlayPeerName').textContent = `π ${peerName}`;
|
| 6516 |
document.getElementById('callTimerLabel').textContent = '00:00:00';
|
| 6517 |
+
setCallStatus('Preparing call...');
|
| 6518 |
const muteBtn = document.getElementById('muteBtn');
|
| 6519 |
if (muteBtn) { muteBtn.textContent = 'π€'; muteBtn.classList.remove('muted'); }
|
| 6520 |
const camBtn = document.getElementById('cameraBtn');
|
| 6521 |
if (camBtn) { camBtn.textContent = 'π·'; camBtn.classList.remove('cam-off'); }
|
| 6522 |
isCallCameraOff = false;
|
| 6523 |
overlay.classList.add('active');
|
| 6524 |
+
const dbg = document.getElementById('callDebugPanel');
|
| 6525 |
+
if (dbg) dbg.style.display = 'block';
|
| 6526 |
+
appendCallLog(`Call window opened for ${peerName}`);
|
| 6527 |
}
|
| 6528 |
}
|
| 6529 |
|
|
|
|
| 6540 |
callIceFailureCount = 0;
|
| 6541 |
await ensureRtcConfigLoaded();
|
| 6542 |
forceRelayOnly = rtcRuntimeConfig?.iceTransportPolicy === 'relay';
|
| 6543 |
+
appendCallLog(`Starting session as ${isCaller ? 'caller' : 'callee'}`);
|
| 6544 |
|
| 6545 |
openCallDialog(peerName);
|
| 6546 |
// Start timer from session start to avoid "stuck at 00:00" perception on unstable networks.
|
|
|
|
| 6553 |
// Do not abort the call - continue in receive-only mode so user can still hear/see remote party.
|
| 6554 |
console.warn('Local media unavailable, continuing receive-only call:', mediaError);
|
| 6555 |
localCallStream = null;
|
| 6556 |
+
appendCallLog(`Local media unavailable: ${mediaError?.message || mediaError}`);
|
| 6557 |
showToast('Starting call in receive-only mode (local camera/mic unavailable)', 'warning');
|
| 6558 |
}
|
| 6559 |
|
|
|
|
| 6566 |
}
|
| 6567 |
|
| 6568 |
createPeerConnection(peerId);
|
| 6569 |
+
appendCallLog('Peer connection created');
|
| 6570 |
|
| 6571 |
if (isCaller && peerConnection) {
|
| 6572 |
makingOffer = true;
|
|
|
|
| 6576 |
offerToReceiveVideo: true
|
| 6577 |
});
|
| 6578 |
await peerConnection.setLocalDescription(offer);
|
| 6579 |
+
appendCallLog('Offer created and sent');
|
| 6580 |
socket.emit('video signal', {
|
| 6581 |
toId: peerId,
|
| 6582 |
callId: activeCallState?.callId,
|
|
|
|
| 6593 |
pendingSignalOffer = null;
|
| 6594 |
try {
|
| 6595 |
await peerConnection.setRemoteDescription(new RTCSessionDescription(po.offer));
|
| 6596 |
+
appendCallLog('Pending remote offer applied');
|
| 6597 |
await flushQueuedIceCandidates();
|
| 6598 |
const answer = await peerConnection.createAnswer();
|
| 6599 |
await peerConnection.setLocalDescription(answer);
|
| 6600 |
+
appendCallLog('Answer created for pending offer');
|
| 6601 |
socket.emit('video signal', {
|
| 6602 |
toId: po.fromId,
|
| 6603 |
callId: activeCallState?.callId,
|
|
|
|
| 6707 |
<div class="dbg-row">πΊ Remote Video: ${vidState}</div>
|
| 6708 |
<div class="dbg-row">π Socket: ${socketStr}</div>
|
| 6709 |
<div class="dbg-row">β± Call duration: ${document.getElementById('callTimerLabel')?.textContent || 'n/a'}</div>
|
| 6710 |
+
<div class="dbg-row">π Status: ${document.getElementById('callStatusLabel')?.textContent || 'n/a'}</div>
|
| 6711 |
+
<div class="dbg-log">${callEventLog.map((entry) => `<div>${entry}</div>`).join('')}</div>
|
| 6712 |
<div style="margin-top:8px;">
|
| 6713 |
<button onclick="forceRestartIce()" style="background:#00ff88;color:#000;border:none;padding:4px 10px;border-radius:4px;cursor:pointer;font-size:10px;font-weight:700;">π Restart ICE</button>
|
| 6714 |
<button onclick="refreshCallDebug()" style="background:rgba(255,255,255,0.2);color:#fff;border:none;padding:4px 10px;border-radius:4px;cursor:pointer;font-size:10px;margin-left:4px;">β» Refresh</button>
|
|
|
|
| 6773 |
currentCallPeerId = null;
|
| 6774 |
currentCallPeerName = null;
|
| 6775 |
activeCallState = null;
|
| 6776 |
+
callEventLog = [];
|
| 6777 |
+
setCallStatus('');
|
| 6778 |
|
| 6779 |
// Close the overlay
|
| 6780 |
const overlay = document.getElementById('callOverlay');
|
index.html
CHANGED
|
@@ -1055,6 +1055,19 @@
|
|
| 1055 |
display: none;
|
| 1056 |
}
|
| 1057 |
#callDebugPanel .dbg-row { margin-bottom: 4px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1058 |
|
| 1059 |
/* ==================== NOTIFICATION PANEL ==================== */
|
| 1060 |
.notif-bell-btn {
|
|
@@ -3098,7 +3111,7 @@
|
|
| 3098 |
<div class="chat-header-title" id="chatTitle">π¬ Select a friend to chat</div>
|
| 3099 |
</div>
|
| 3100 |
<div class="chat-header-actions">
|
| 3101 |
-
<span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v2.8.
|
| 3102 |
<button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
|
| 3103 |
<i class="fas fa-archive"></i>
|
| 3104 |
</button>
|
|
@@ -3687,6 +3700,7 @@
|
|
| 3687 |
<div>
|
| 3688 |
<div id="callOverlayPeerName" style="color:#fff; font-size:18px; font-weight:700;"></div>
|
| 3689 |
<div id="callTimerLabel" style="color:rgba(255,255,255,0.7); font-size:13px; margin-top:4px;">00:00:00</div>
|
|
|
|
| 3690 |
</div>
|
| 3691 |
<button id="callDebugBtn" style="background:rgba(255,255,255,0.18); border:none; color:white; padding:7px 13px; border-radius:8px; cursor:pointer; font-size:12px; font-weight:600;">π§ Debug</button>
|
| 3692 |
</div>
|
|
@@ -3717,7 +3731,7 @@
|
|
| 3717 |
|
| 3718 |
<script src="/socket.io/socket.io.js"></script>
|
| 3719 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
| 3720 |
-
<script src="client.js?v=2.8.
|
| 3721 |
</body>
|
| 3722 |
</html>
|
| 3723 |
|
|
|
|
| 1055 |
display: none;
|
| 1056 |
}
|
| 1057 |
#callDebugPanel .dbg-row { margin-bottom: 4px; }
|
| 1058 |
+
#callDebugPanel .dbg-log {
|
| 1059 |
+
margin-top: 8px;
|
| 1060 |
+
max-height: 180px;
|
| 1061 |
+
overflow-y: auto;
|
| 1062 |
+
border-top: 1px solid rgba(0,255,136,0.35);
|
| 1063 |
+
padding-top: 8px;
|
| 1064 |
+
color: #c7ffd9;
|
| 1065 |
+
}
|
| 1066 |
+
#callDebugPanel .dbg-log div {
|
| 1067 |
+
margin-bottom: 4px;
|
| 1068 |
+
line-height: 1.35;
|
| 1069 |
+
word-break: break-word;
|
| 1070 |
+
}
|
| 1071 |
|
| 1072 |
/* ==================== NOTIFICATION PANEL ==================== */
|
| 1073 |
.notif-bell-btn {
|
|
|
|
| 3111 |
<div class="chat-header-title" id="chatTitle">π¬ Select a friend to chat</div>
|
| 3112 |
</div>
|
| 3113 |
<div class="chat-header-actions">
|
| 3114 |
+
<span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v2.8.4</span>
|
| 3115 |
<button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
|
| 3116 |
<i class="fas fa-archive"></i>
|
| 3117 |
</button>
|
|
|
|
| 3700 |
<div>
|
| 3701 |
<div id="callOverlayPeerName" style="color:#fff; font-size:18px; font-weight:700;"></div>
|
| 3702 |
<div id="callTimerLabel" style="color:rgba(255,255,255,0.7); font-size:13px; margin-top:4px;">00:00:00</div>
|
| 3703 |
+
<div id="callStatusLabel" style="color:#8fffc2; font-size:12px; margin-top:4px;">Preparing call...</div>
|
| 3704 |
</div>
|
| 3705 |
<button id="callDebugBtn" style="background:rgba(255,255,255,0.18); border:none; color:white; padding:7px 13px; border-radius:8px; cursor:pointer; font-size:12px; font-weight:600;">π§ Debug</button>
|
| 3706 |
</div>
|
|
|
|
| 3731 |
|
| 3732 |
<script src="/socket.io/socket.io.js"></script>
|
| 3733 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
| 3734 |
+
<script src="client.js?v=2.8.4"></script>
|
| 3735 |
</body>
|
| 3736 |
</html>
|
| 3737 |
|
package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "discord-like-app",
|
| 3 |
-
"version": "2.8.
|
| 4 |
"main": "server.js",
|
| 5 |
"scripts": {
|
| 6 |
"dev": "nodemon server.js",
|
|
|
|
| 1 |
{
|
| 2 |
"name": "discord-like-app",
|
| 3 |
+
"version": "2.8.4",
|
| 4 |
"main": "server.js",
|
| 5 |
"scripts": {
|
| 6 |
"dev": "nodemon server.js",
|