From 8b90bc6485743da08a2b93c27729d4ac11d64d42 Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Sun, 24 Nov 2024 17:35:54 -0500 Subject: [PATCH] sync up mobile and desktop drop downs and user lists! modified: templates/base.html modified: templates/chat.html --- templates/base.html | 75 ++++++++++++++++++---- templates/chat.html | 152 +++++++++++++++++++++++++++++++------------- 2 files changed, 171 insertions(+), 56 deletions(-) diff --git a/templates/base.html b/templates/base.html index 2a3ba4c..25ee7de 100644 --- a/templates/base.html +++ b/templates/base.html @@ -262,7 +262,7 @@ - 🚀 docs for language models & other commands, also try /help + 🚀 docs for models & other commands, also try /help
@@ -274,15 +274,62 @@ - -
-
- -
- -
-
-
+ +
+
+ +
+
+ + +
+
+ + +
+
+
+

Active Users

+
    + +
+
+
+

Inactive Users

+
    + +
+
+
+ +
+
+ +
+
+
+
@@ -293,7 +340,13 @@
  • - {{ room.name }} {% if room.title %}
    {{ room.title }} {% endif %} + {{ room.name }} + {% if room.title %} +
    {{ room.title }} + {% endif %} + {% if room.get_active_users()|length %} +
    {{ room.get_active_users()|length }} users + {% endif %}
  • {% endfor %} diff --git a/templates/chat.html b/templates/chat.html index 203e9c0..8df28c0 100644 --- a/templates/chat.html +++ b/templates/chat.html @@ -98,8 +98,48 @@ let userHasScrolledUp = false; let currentAudio = null; // To keep track of the currently playing audio let audioCache = {}; // Cache to store audio blobs +// Flag to prevent mutual updates on desktop/mobile +let isSyncingDropdowns = false; + + +// Function to sanitize the username +function sanitizeUsername(username) { + // Split the username on commas and take the first part. + // The backend denormalizes the user list in the room table via csv. + return username.split(',')[0].trim(); +} + +// Function to sync dropdowns and update the query string +function syncDropdownsAndQueryString() { + const sanitizedUsername = sanitizeUsername(username); + const modelSelectDesktop = document.getElementById("model-select"); + const voiceSelectDesktop = document.getElementById("voice-select"); + const modelSelectMobile = document.getElementById("model-select-mobile"); + const voiceSelectMobile = document.getElementById("voice-select-mobile"); + + // Determine the current model and voice from any dropdown + const currentModel = VALID_MODELS.includes(modelSelectDesktop.value) ? modelSelectDesktop.value : 'None'; + const currentVoice = VALID_VOICES.includes(voiceSelectDesktop.value) ? voiceSelectDesktop.value : 'onyx'; + + // Sync both desktop and mobile dropdowns + modelSelectDesktop.value = currentModel; + voiceSelectDesktop.value = currentVoice; + modelSelectMobile.value = currentModel; + voiceSelectMobile.value = currentVoice; + + const newUrl = new URL(window.location.href); + newUrl.searchParams.set("username", sanitizedUsername); + newUrl.searchParams.set("model", currentModel); + newUrl.searchParams.set("voice", currentVoice); + window.history.replaceState({}, '', newUrl); +} + document.addEventListener('DOMContentLoaded', (event) => { const chatContainer = document.getElementById("chat"); + const modelSelectDesktop = document.getElementById("model-select"); + const voiceSelectDesktop = document.getElementById("voice-select"); + const modelSelectMobile = document.getElementById("model-select-mobile"); + const voiceSelectMobile = document.getElementById("voice-select-mobile"); chatContainer.addEventListener('scroll', () => { const distanceFromBottom = chatContainer.scrollHeight - chatContainer.scrollTop - chatContainer.clientHeight; @@ -107,57 +147,96 @@ document.addEventListener('DOMContentLoaded', (event) => { }); // Set initial model and voice from query string - const modelSelect = document.getElementById("model-select"); - const voiceSelect = document.getElementById("voice-select"); const initialModel = urlParams.get("model") || "None"; const initialVoice = urlParams.get("voice") || "onyx"; - modelSelect.value = initialModel; - voiceSelect.value = initialVoice; + modelSelectDesktop.value = initialModel; + voiceSelectDesktop.value = initialVoice; + modelSelectMobile.value = initialModel; + voiceSelectMobile.value = initialVoice; - // Update query string when model or voice changes - modelSelect.addEventListener("change", updateQueryString); - voiceSelect.addEventListener("change", updateQueryString); + // Add event listeners for desktop dropdowns + modelSelectDesktop.addEventListener("change", () => { + if (isSyncingDropdowns) return; + isSyncingDropdowns = true; + modelSelectMobile.value = modelSelectDesktop.value; + syncDropdownsAndQueryString(); + isSyncingDropdowns = false; + }); + + voiceSelectDesktop.addEventListener("change", () => { + if (isSyncingDropdowns) return; + isSyncingDropdowns = true; + voiceSelectMobile.value = voiceSelectDesktop.value; + syncDropdownsAndQueryString(); + isSyncingDropdowns = false; + }); + + // Add event listeners for mobile dropdowns + modelSelectMobile.addEventListener("change", () => { + if (isSyncingDropdowns) return; + isSyncingDropdowns = true; + modelSelectDesktop.value = modelSelectMobile.value; + syncDropdownsAndQueryString(); + isSyncingDropdowns = false; + }); + + voiceSelectMobile.addEventListener("change", () => { + if (isSyncingDropdowns) return; + isSyncingDropdowns = true; + voiceSelectDesktop.value = voiceSelectMobile.value; + syncDropdownsAndQueryString(); + isSyncingDropdowns = false; + }); }); - -// Function to validate and update the query string -function updateQueryString() { +// Socket event when the user connects +socket.on("connect", () => { + // Sanitize the username before joining const sanitizedUsername = sanitizeUsername(username); - const modelSelect = document.getElementById("model-select"); - const voiceSelect = document.getElementById("voice-select"); - - // Validate model and voice - const model = VALID_MODELS.includes(modelSelect.value) ? modelSelect.value : 'None'; - const voice = VALID_VOICES.includes(voiceSelect.value) ? voiceSelect.value : 'onyx'; - - const newUrl = new URL(window.location.href); - newUrl.searchParams.set("username", sanitizedUsername); - newUrl.searchParams.set("model", model); - newUrl.searchParams.set("voice", voice); - window.history.replaceState({}, '', newUrl); -} + socket.emit("join", {"username": sanitizedUsername, "room_name": room_name}); + // Sync dropdowns and update the query string + syncDropdownsAndQueryString(); +}); // Function to update the active and inactive user lists in the DOM function updateUserLists(activeUsers, inactiveUsers) { const activeUserListElement = document.getElementById("active-users"); const inactiveUserListElement = document.getElementById("inactive-users"); + const activeUserListElementMobile = document.getElementById("active-users-mobile"); + const inactiveUserListElementMobile = document.getElementById("inactive-users-mobile"); activeUserListElement.innerHTML = ''; // Clear the current list inactiveUserListElement.innerHTML = ''; // Clear the current list + activeUserListElementMobile.innerHTML = ''; // Clear the current list (mobile) + inactiveUserListElementMobile.innerHTML = ''; // Clear the current list (mobile) - // Populate the list with active users + // Populate the list with active users (desktop) activeUsers.forEach(username => { const userItem = document.createElement("li"); userItem.textContent = username; activeUserListElement.appendChild(userItem); }); - // Populate the list with inactive users + // Populate the list with inactive users (desktop) inactiveUsers.forEach(username => { const userItem = document.createElement("li"); userItem.textContent = username; inactiveUserListElement.appendChild(userItem); }); + + // Populate the list with active users (mobile) + activeUsers.forEach(username => { + const userItemMobile = document.createElement("li"); + userItemMobile.textContent = username; + activeUserListElementMobile.appendChild(userItemMobile); + }); + + // Populate the list with inactive users (mobile) + inactiveUsers.forEach(username => { + const userItemMobile = document.createElement("li"); + userItemMobile.textContent = username; + inactiveUserListElementMobile.appendChild(userItemMobile); + }); } // Update user lists whenever the event is received @@ -171,11 +250,10 @@ function sendMessage() { const model = document.getElementById("model-select").value; let messageToSend = message.trim(); - if (model !== "None") { - messageToSend = `${model} ${messageToSend}`; - } - if (messageToSend !== "") { // Ensure we're not sending empty messages + if (model !== "None") { + messageToSend = `${model} ${messageToSend}`; + } socket.emit("chat_message", {"username": username, "message": messageToSend, "room_name": room_name}); document.getElementById("message").value = ""; } @@ -216,22 +294,6 @@ socket.on('update_room_list', function(updatedRoom) { } }); -// Function to sanitize the username -function sanitizeUsername(username) { - // Split the username on commas and take the first part. - // The backend denormalizes the user list in the room table via csv. - return username.split(',')[0].trim(); -} - -// Socket event when the user connects -socket.on("connect", () => { - // Sanitize the username before joining - const sanitizedUsername = sanitizeUsername(username); - socket.emit("join", {"username": sanitizedUsername, "room_name": room_name}); - // Update the query string with the sanitized username - updateQueryString(); -}); - // Function to read text using TTS async function speakText(text, playButton, messageId) { const voice = document.getElementById("voice-select").value;