diff --git a/package.json b/package.json index bc8d22e..ce3624f 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "call-me", - "version": "1.2.50", + "version": "1.2.51", "description": "Your Go-To for Instant Video Calls", "author": "Miroslav Pejic - miroslav.pejic.85@gmail.com", "license": "AGPLv3", diff --git a/public/client.js b/public/client.js index 74b78ac..6559827 100755 --- a/public/client.js +++ b/public/client.js @@ -45,7 +45,7 @@ const hideBtn = document.getElementById('hideBtn'); const swapCameraBtn = document.getElementById('swapCameraBtn'); const videoBtn = document.getElementById('videoBtn'); const audioBtn = document.getElementById('audioBtn'); -const hangUpBtn = document.getElementById('hangUpBtn'); +const leaveBtn = document.getElementById('leaveBtn'); const localVideoContainer = document.getElementById('localVideoContainer'); const localVideo = document.getElementById('localVideo'); const remoteAudioDisabled = document.getElementById('remoteAudioDisabled'); @@ -436,7 +436,7 @@ function handleListeners() { hideBtn.addEventListener('click', toggleLocalVideo); videoBtn.addEventListener('click', handleVideoClick); audioBtn.addEventListener('click', handleAudioClick); - hangUpBtn.addEventListener('click', handleHangUpClick); + leaveBtn.addEventListener('click', handleLeaveClick); exitSidebarBtn.addEventListener('click', handleExitSidebarClick); localVideoContainer.addEventListener('click', toggleFullScreen); remoteVideo.addEventListener('click', toggleFullScreen); @@ -487,8 +487,8 @@ function handleUserClickToCall(user) { return; } selectedUser = user; - renderUserList(); connectedUser = user; + renderUserList(); sendMsg({ type: 'offerAccept', from: userName, @@ -693,8 +693,8 @@ function checkVideoAudioStatus() { } } -// Handle hang-up button click -function handleHangUpClick() { +// Handle leave button click +function handleLeaveClick() { sendMsg({ type: 'leave', name: socket.recipient }); handleLeave(); } @@ -742,7 +742,7 @@ async function handleSignIn(data) { if (!success) { handleError(message); if (!message.startsWith('Invalid username')) { - setTimeout(handleHangUpClick, 3000); + setTimeout(handleLeaveClick, 3000); } } else { userSignedIn = true; @@ -853,6 +853,7 @@ function initializeConnection() { remoteVideo.controls = false; startSessionTime(); + renderUserList(); // Update UI to show hang-up button console.log('Remote stream set to video element'); } else { @@ -1062,6 +1063,7 @@ function handleLeave(disconnect = true) { // Reset state connectedUser = null; + renderUserList(); console.log('Remote user cleanup completed - ready for new connections'); } @@ -1130,25 +1132,46 @@ function renderUserList() { li.tabIndex = 0; if (user === selectedUser) li.classList.add('selected'); - // Create call button - const callBtnEl = document.createElement('button'); - callBtnEl.className = 'btn btn-custom btn-warning btn-s call-user-btn fas fa-phone'; - callBtnEl.title = `Call ${user}`; - callBtnEl.setAttribute('data-toggle', 'tooltip'); - callBtnEl.setAttribute('data-placement', 'top'); - callBtnEl.style.marginRight = '10px'; - callBtnEl.style.cursor = 'pointer'; - callBtnEl.addEventListener('click', (e) => { - e.stopPropagation(); - if (!userSignedIn) return; - handleUserClickToCall(user); - }); + // Check if this user is currently in an active call (has answered) + const isInActiveCall = + connectedUser === user && remoteVideo.srcObject && remoteVideo.srcObject.getTracks().length > 0; + + // Create call/hangup button based on active call state + const actionBtnEl = document.createElement('button'); + actionBtnEl.style.marginRight = '10px'; + actionBtnEl.style.cursor = 'pointer'; + actionBtnEl.setAttribute('data-toggle', 'tooltip'); + actionBtnEl.setAttribute('data-placement', 'top'); + + if (isInActiveCall) { + // Show hang-up button only if in active call (user has answered) + actionBtnEl.className = 'btn btn-custom btn-danger btn-s hangup-user-btn fas fa-phone-slash'; + actionBtnEl.title = `Hang up call with ${user}`; + actionBtnEl.addEventListener('click', (e) => { + e.stopPropagation(); + if (!userSignedIn) return; + console.log(`Hanging up call with ${user}`); + // Send leave message to notify the other user + sendMsg({ type: 'leave', name: connectedUser }); + handleLeave(false); // End call but stay in room + renderUserList(); // Refresh the list to show call button again + }); + } else { + // Show call button if not in active call + actionBtnEl.className = 'btn btn-custom btn-warning btn-s call-user-btn fas fa-phone'; + actionBtnEl.title = `Call ${user}`; + actionBtnEl.addEventListener('click', (e) => { + e.stopPropagation(); + if (!userSignedIn) return; + handleUserClickToCall(user); + }); + } // Username span const nameSpan = document.createElement('span'); nameSpan.textContent = user; - li.appendChild(callBtnEl); + li.appendChild(actionBtnEl); li.appendChild(nameSpan); li.addEventListener('click', () => { @@ -1158,7 +1181,18 @@ function renderUserList() { }); li.addEventListener('keydown', (e) => { if (!userSignedIn) return; - if (e.key === 'Enter') handleUserClickToCall(user); + if (e.key === 'Enter') { + const isInActiveCall = + connectedUser === user && remoteVideo.srcObject && remoteVideo.srcObject.getTracks().length > 0; + if (isInActiveCall) { + // Send leave message to notify the other user + sendMsg({ type: 'leave', name: connectedUser }); + handleLeave(false); + renderUserList(); + } else { + handleUserClickToCall(user); + } + } }); userList.appendChild(li); }); @@ -1613,5 +1647,5 @@ function debugStreamState() { // Clean up before window close or reload window.onbeforeunload = () => { - handleHangUpClick(); + handleLeaveClick(); }; diff --git a/public/index.html b/public/index.html index c9d59ba..4b30214 100755 --- a/public/index.html +++ b/public/index.html @@ -233,15 +233,15 @@ > - +