From 9006570bd1d07fb09021705bb7ac348d8295cb82 Mon Sep 17 00:00:00 2001 From: KoalaDev <6156589+Shik3i@users.noreply.github.com> Date: Fri, 26 Jun 2026 04:14:55 +0200 Subject: [PATCH] feat(extension): host control toggle + role badge in popup (step 5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Final wiring of host control mode — the user-facing UI: - Active-room section gains a Host Control card: a Host/Guest role badge, a host-only toggle ("Only I can control playback") shown to the host, and a guest notice when the room is host-only. - Toggle sends SET_CONTROL_MODE; UI refreshes from the server's CONTROL_MODE broadcast (with optimistic revert on failure). Card updates on GET_STATUS, CONTROL_MODE, and reconnect. - i18n: 6 new keys (LABEL_HOST_CONTROL[_TOOLTIP], LABEL_HOST_ONLY_TOGGLE, NOTICE_HOST_CONTROLS, BADGE_HOST, BADGE_GUEST) translated across all 15 popup locales. Completes the feature end to end (server + background + content + popup). Co-Authored-By: Claude Opus 4.8 --- extension/locales/de.json | 6 ++++++ extension/locales/en.json | 6 ++++++ extension/locales/es.json | 6 ++++++ extension/locales/fr.json | 6 ++++++ extension/locales/it.json | 6 ++++++ extension/locales/ja.json | 6 ++++++ extension/locales/ko.json | 6 ++++++ extension/locales/nl.json | 6 ++++++ extension/locales/pl.json | 6 ++++++ extension/locales/pt-BR.json | 6 ++++++ extension/locales/pt.json | 6 ++++++ extension/locales/ru.json | 6 ++++++ extension/locales/tr.json | 6 ++++++ extension/locales/uk.json | 6 ++++++ extension/locales/zh.json | 6 ++++++ extension/popup.html | 12 ++++++++++++ extension/popup.js | 38 ++++++++++++++++++++++++++++++++++++ 17 files changed, 140 insertions(+) diff --git a/extension/locales/de.json b/extension/locales/de.json index 10a8a9f..927f0b1 100644 --- a/extension/locales/de.json +++ b/extension/locales/de.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Teile diesen Link mit Freunden, damit sie beitreten können", "LABEL_PEERS_IN_ROOM": "Teilnehmer im Raum", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Andere Benutzer, die derzeit mit diesem Raum verbunden sind", + "LABEL_HOST_CONTROL": "Host-Steuerung", + "LABEL_HOST_CONTROL_TOOLTIP": "Festlegen, wer die Wiedergabe in diesem Raum steuern darf", + "LABEL_HOST_ONLY_TOGGLE": "Nur ich darf die Wiedergabe steuern", + "NOTICE_HOST_CONTROLS": "Der Host steuert die Wiedergabe für alle.", + "BADGE_HOST": "Host", + "BADGE_GUEST": "Gast", "NO_PEERS_CONNECTED": "Keine Teilnehmer verbunden", "BTN_LEAVE_ROOM": "Raum verlassen", "LABEL_SELECT_VIDEO": "Video auswählen", diff --git a/extension/locales/en.json b/extension/locales/en.json index 789abff..5a32d63 100644 --- a/extension/locales/en.json +++ b/extension/locales/en.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Share this link with friends so they can join", "LABEL_PEERS_IN_ROOM": "Peers in Room", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Other users currently connected to this room", + "LABEL_HOST_CONTROL": "Host Control", + "LABEL_HOST_CONTROL_TOOLTIP": "Restrict who can control playback in this room", + "LABEL_HOST_ONLY_TOGGLE": "Only I can control playback", + "NOTICE_HOST_CONTROLS": "The host controls playback for everyone.", + "BADGE_HOST": "Host", + "BADGE_GUEST": "Guest", "NO_PEERS_CONNECTED": "No peers connected", "BTN_LEAVE_ROOM": "Leave Room", "LABEL_SELECT_VIDEO": "Select Video", diff --git a/extension/locales/es.json b/extension/locales/es.json index 186678e..2dece79 100644 --- a/extension/locales/es.json +++ b/extension/locales/es.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Comparte este enlace con amigos para que se unan", "LABEL_PEERS_IN_ROOM": "Participantes en la sala", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Otros usuarios conectados actualmente a esta sala", + "LABEL_HOST_CONTROL": "Control del anfitrión", + "LABEL_HOST_CONTROL_TOOLTIP": "Restringir quién puede controlar la reproducción en esta sala", + "LABEL_HOST_ONLY_TOGGLE": "Solo yo puedo controlar la reproducción", + "NOTICE_HOST_CONTROLS": "El anfitrión controla la reproducción para todos.", + "BADGE_HOST": "Anfitrión", + "BADGE_GUEST": "Invitado", "NO_PEERS_CONNECTED": "Sin participantes conectados", "BTN_LEAVE_ROOM": "Salir de la sala", "LABEL_SELECT_VIDEO": "Seleccionar video", diff --git a/extension/locales/fr.json b/extension/locales/fr.json index 27db35b..f0cc0e4 100644 --- a/extension/locales/fr.json +++ b/extension/locales/fr.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Partagez ce lien avec vos amis pour qu'ils vous rejoignent", "LABEL_PEERS_IN_ROOM": "Membres dans le salon", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Autres utilisateurs connectés à ce salon", + "LABEL_HOST_CONTROL": "Contrôle de l'hôte", + "LABEL_HOST_CONTROL_TOOLTIP": "Définir qui peut contrôler la lecture dans ce salon", + "LABEL_HOST_ONLY_TOGGLE": "Moi seul peux contrôler la lecture", + "NOTICE_HOST_CONTROLS": "L'hôte contrôle la lecture pour tout le monde.", + "BADGE_HOST": "Hôte", + "BADGE_GUEST": "Invité", "NO_PEERS_CONNECTED": "Aucun membre connecté", "BTN_LEAVE_ROOM": "Quitter le salon", "LABEL_SELECT_VIDEO": "Choisir une vidéo", diff --git a/extension/locales/it.json b/extension/locales/it.json index 5217462..4cc5b53 100644 --- a/extension/locales/it.json +++ b/extension/locales/it.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Condividi questo link per invitare i tuoi amici", "LABEL_PEERS_IN_ROOM": "Partecipanti", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Utenti connessi a questa stanza", + "LABEL_HOST_CONTROL": "Controllo host", + "LABEL_HOST_CONTROL_TOOLTIP": "Limita chi può controllare la riproduzione in questa stanza", + "LABEL_HOST_ONLY_TOGGLE": "Solo io posso controllare la riproduzione", + "NOTICE_HOST_CONTROLS": "L'host controlla la riproduzione per tutti.", + "BADGE_HOST": "Host", + "BADGE_GUEST": "Ospite", "NO_PEERS_CONNECTED": "Nessun partecipante connesso", "BTN_LEAVE_ROOM": "Lascia Stanza", "LABEL_SELECT_VIDEO": "Seleziona Video", diff --git a/extension/locales/ja.json b/extension/locales/ja.json index afa8ed2..d7a8777 100644 --- a/extension/locales/ja.json +++ b/extension/locales/ja.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "友達とこのリンクを共有して参加してもらいましょう", "LABEL_PEERS_IN_ROOM": "ルーム内のメンバー", "LABEL_PEERS_IN_ROOM_TOOLTIP": "現在このルームに接続している他のユーザー", + "LABEL_HOST_CONTROL": "ホスト操作", + "LABEL_HOST_CONTROL_TOOLTIP": "このルームで再生を操作できる人を制限します", + "LABEL_HOST_ONLY_TOGGLE": "再生を操作できるのは自分だけ", + "NOTICE_HOST_CONTROLS": "ホストが全員の再生を操作します。", + "BADGE_HOST": "ホスト", + "BADGE_GUEST": "ゲスト", "NO_PEERS_CONNECTED": "接続しているメンバーはいません", "BTN_LEAVE_ROOM": "ルームを退室", "LABEL_SELECT_VIDEO": "ビデオを選択", diff --git a/extension/locales/ko.json b/extension/locales/ko.json index fd20147..fc22f82 100644 --- a/extension/locales/ko.json +++ b/extension/locales/ko.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "친구들이 참여할 수 있도록 이 링크를 공유하세요", "LABEL_PEERS_IN_ROOM": "방의 참여자", "LABEL_PEERS_IN_ROOM_TOOLTIP": "현재 이 방에 연결되어 있는 다른 사용자들", + "LABEL_HOST_CONTROL": "호스트 제어", + "LABEL_HOST_CONTROL_TOOLTIP": "이 방에서 재생을 제어할 수 있는 사람 제한", + "LABEL_HOST_ONLY_TOGGLE": "나만 재생을 제어할 수 있음", + "NOTICE_HOST_CONTROLS": "호스트가 모두의 재생을 제어합니다.", + "BADGE_HOST": "호스트", + "BADGE_GUEST": "게스트", "NO_PEERS_CONNECTED": "연결된 참여자가 없습니다", "BTN_LEAVE_ROOM": "방 나가기", "LABEL_SELECT_VIDEO": "비디오 선택", diff --git a/extension/locales/nl.json b/extension/locales/nl.json index cfef8a6..845be4d 100644 --- a/extension/locales/nl.json +++ b/extension/locales/nl.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Deel deze link met vrienden zodat ze kunnen deelnemen", "LABEL_PEERS_IN_ROOM": "Deelnemers in kamer", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Andere gebruikers die momenteel zijn verbonden met deze kamer", + "LABEL_HOST_CONTROL": "Hostbeheer", + "LABEL_HOST_CONTROL_TOOLTIP": "Bepaal wie de weergave in deze kamer mag bedienen", + "LABEL_HOST_ONLY_TOGGLE": "Alleen ik mag de weergave bedienen", + "NOTICE_HOST_CONTROLS": "De host bedient de weergave voor iedereen.", + "BADGE_HOST": "Host", + "BADGE_GUEST": "Gast", "NO_PEERS_CONNECTED": "Geen deelnemers verbonden", "BTN_LEAVE_ROOM": "Kamer verlaten", "LABEL_SELECT_VIDEO": "Selecteer video", diff --git a/extension/locales/pl.json b/extension/locales/pl.json index a7fe42c..31ee64a 100644 --- a/extension/locales/pl.json +++ b/extension/locales/pl.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Udostępnij ten link znajomym, aby mogli dołączyć", "LABEL_PEERS_IN_ROOM": "Uczestnicy w pokoju", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Inni użytkownicy aktualnie połączeni z tym pokojem", + "LABEL_HOST_CONTROL": "Kontrola hosta", + "LABEL_HOST_CONTROL_TOOLTIP": "Określ, kto może sterować odtwarzaniem w tym pokoju", + "LABEL_HOST_ONLY_TOGGLE": "Tylko ja mogę sterować odtwarzaniem", + "NOTICE_HOST_CONTROLS": "Host steruje odtwarzaniem dla wszystkich.", + "BADGE_HOST": "Host", + "BADGE_GUEST": "Gość", "NO_PEERS_CONNECTED": "Brak połączonych uczestników", "BTN_LEAVE_ROOM": "Opuść pokój", "LABEL_SELECT_VIDEO": "Wybierz wideo", diff --git a/extension/locales/pt-BR.json b/extension/locales/pt-BR.json index 9a9c608..d33caec 100644 --- a/extension/locales/pt-BR.json +++ b/extension/locales/pt-BR.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Compartilhe este link com seus amigos para que eles entrem", "LABEL_PEERS_IN_ROOM": "Participantes", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Outros usuários conectados a esta sala", + "LABEL_HOST_CONTROL": "Controle do anfitrião", + "LABEL_HOST_CONTROL_TOOLTIP": "Restringir quem pode controlar a reprodução nesta sala", + "LABEL_HOST_ONLY_TOGGLE": "Somente eu posso controlar a reprodução", + "NOTICE_HOST_CONTROLS": "O anfitrião controla a reprodução para todos.", + "BADGE_HOST": "Anfitrião", + "BADGE_GUEST": "Convidado", "NO_PEERS_CONNECTED": "Sem participantes conectados", "BTN_LEAVE_ROOM": "Sair da sala", "LABEL_SELECT_VIDEO": "Selecionar vídeo", diff --git a/extension/locales/pt.json b/extension/locales/pt.json index f5ab295..4e8833b 100644 --- a/extension/locales/pt.json +++ b/extension/locales/pt.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Partilhe este link com os amigos para que possam entrar", "LABEL_PEERS_IN_ROOM": "Participantes na Sala", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Utilizadores atualmente ligados a esta sala", + "LABEL_HOST_CONTROL": "Controlo do anfitrião", + "LABEL_HOST_CONTROL_TOOLTIP": "Restringir quem pode controlar a reprodução nesta sala", + "LABEL_HOST_ONLY_TOGGLE": "Só eu posso controlar a reprodução", + "NOTICE_HOST_CONTROLS": "O anfitrião controla a reprodução para todos.", + "BADGE_HOST": "Anfitrião", + "BADGE_GUEST": "Convidado", "NO_PEERS_CONNECTED": "Nenhum participante ligado", "BTN_LEAVE_ROOM": "Sair da Sala", "LABEL_SELECT_VIDEO": "Selecionar Vídeo", diff --git a/extension/locales/ru.json b/extension/locales/ru.json index f21e738..a749902 100644 --- a/extension/locales/ru.json +++ b/extension/locales/ru.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Поделитесь этой ссылкой с друзьями, чтобы они вошли", "LABEL_PEERS_IN_ROOM": "Участники в комнате", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Другие пользователи, подключенные к этой комнате", + "LABEL_HOST_CONTROL": "Управление ведущим", + "LABEL_HOST_CONTROL_TOOLTIP": "Ограничить, кто может управлять воспроизведением в этой комнате", + "LABEL_HOST_ONLY_TOGGLE": "Только я могу управлять воспроизведением", + "NOTICE_HOST_CONTROLS": "Ведущий управляет воспроизведением для всех.", + "BADGE_HOST": "Ведущий", + "BADGE_GUEST": "Гость", "NO_PEERS_CONNECTED": "Нет подключенных участников", "BTN_LEAVE_ROOM": "Выйти из комнаты", "LABEL_SELECT_VIDEO": "Выбрать видео", diff --git a/extension/locales/tr.json b/extension/locales/tr.json index 43dd76a..304ae7c 100644 --- a/extension/locales/tr.json +++ b/extension/locales/tr.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Katılabilmeleri için bu bağlantıyı arkadaşlarınızla paylaşın", "LABEL_PEERS_IN_ROOM": "Odadaki Kişiler", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Şu anda bu odaya bağlı olan diğer kullanıcılar", + "LABEL_HOST_CONTROL": "Sunucu Kontrolü", + "LABEL_HOST_CONTROL_TOOLTIP": "Bu odada oynatmayı kimin kontrol edebileceğini belirleyin", + "LABEL_HOST_ONLY_TOGGLE": "Oynatmayı yalnızca ben kontrol edebilirim", + "NOTICE_HOST_CONTROLS": "Oynatmayı herkes için sunucu kontrol eder.", + "BADGE_HOST": "Sunucu", + "BADGE_GUEST": "Misafir", "NO_PEERS_CONNECTED": "Bağlı kimse yok", "BTN_LEAVE_ROOM": "Odadan Ayrıl", "LABEL_SELECT_VIDEO": "Video Seç", diff --git a/extension/locales/uk.json b/extension/locales/uk.json index 9ab3c28..6f96dbd 100644 --- a/extension/locales/uk.json +++ b/extension/locales/uk.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "Поділіться цим посиланням з друзями, щоб вони могли приєднатися", "LABEL_PEERS_IN_ROOM": "Учасники в кімнаті", "LABEL_PEERS_IN_ROOM_TOOLTIP": "Інші користувачі зараз підключені до цієї кімнати", + "LABEL_HOST_CONTROL": "Керування ведучим", + "LABEL_HOST_CONTROL_TOOLTIP": "Обмежити, хто може керувати відтворенням у цій кімнаті", + "LABEL_HOST_ONLY_TOGGLE": "Лише я можу керувати відтворенням", + "NOTICE_HOST_CONTROLS": "Ведучий керує відтворенням для всіх.", + "BADGE_HOST": "Ведучий", + "BADGE_GUEST": "Гість", "NO_PEERS_CONNECTED": "Немає підключених однорангових пристроїв", "BTN_LEAVE_ROOM": "Вийти з кімнати", "LABEL_SELECT_VIDEO": "Виберіть Відео", diff --git a/extension/locales/zh.json b/extension/locales/zh.json index f414d05..e5bac19 100644 --- a/extension/locales/zh.json +++ b/extension/locales/zh.json @@ -44,6 +44,12 @@ "LABEL_INVITE_LINK_TOOLTIP": "与朋友分享此链接,以便他们可以加入", "LABEL_PEERS_IN_ROOM": "房间里的同伴", "LABEL_PEERS_IN_ROOM_TOOLTIP": "当前连接到该房间的其他用户", + "LABEL_HOST_CONTROL": "主持人控制", + "LABEL_HOST_CONTROL_TOOLTIP": "限制谁可以在此房间中控制播放", + "LABEL_HOST_ONLY_TOGGLE": "仅我可以控制播放", + "NOTICE_HOST_CONTROLS": "由主持人为所有人控制播放。", + "BADGE_HOST": "主持人", + "BADGE_GUEST": "访客", "NO_PEERS_CONNECTED": "没有对等点连接", "BTN_LEAVE_ROOM": "离开房间", "LABEL_SELECT_VIDEO": "选择视频", diff --git a/extension/popup.html b/extension/popup.html index bb4fb4c..3d36a4c 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -450,6 +450,18 @@ + +
diff --git a/extension/popup.js b/extension/popup.js index 3d94f60..c773c9e 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -41,6 +41,11 @@ const elements = { retryBtn: document.getElementById('retryBtn'), sectionJoin: document.getElementById('section-join'), sectionActive: document.getElementById('section-active'), + hostControlCard: document.getElementById('hostControlCard'), + hostRoleBadge: document.getElementById('hostRoleBadge'), + hostControlToggleRow: document.getElementById('hostControlToggleRow'), + hostControlToggle: document.getElementById('hostControlToggle'), + hostControlGuestNote: document.getElementById('hostControlGuestNote'), activeRoomId: document.getElementById('activeRoomId'), activeServer: document.getElementById('activeServer'), peerListSync: document.getElementById('peerListSync'), @@ -244,6 +249,7 @@ async function init() { updatePingDisplay(res.ping); updatePeerList(res.peers); lastKnownPeers = res.peers || []; + updateHostControlUI(res.controlMode, res.amHost, res.status === 'connected'); if (res.lastActionState) updateLastActionUI(res.lastActionState, res.peers); // If user has a room configured but background is not connected (disconnected or idle), @@ -303,6 +309,34 @@ function toggleUIState(inRoom) { if (syncInactive) syncInactive.style.display = inRoom ? 'none' : 'block'; } +// --- Host Control Mode UI --- +function updateHostControlUI(controlMode, amHost, inRoom) { + const card = elements.hostControlCard; + if (!card) return; + if (!inRoom) { card.style.display = 'none'; return; } + card.style.display = 'block'; + const hostOnly = controlMode === 'host-only'; + if (elements.hostRoleBadge) { + elements.hostRoleBadge.textContent = amHost ? (getMessage('BADGE_HOST') || 'Host') : (getMessage('BADGE_GUEST') || 'Guest'); + elements.hostRoleBadge.style.background = amHost ? 'var(--accent)' : 'var(--text-muted)'; + } + if (elements.hostControlToggleRow) elements.hostControlToggleRow.style.display = amHost ? 'flex' : 'none'; + if (elements.hostControlToggle) elements.hostControlToggle.checked = hostOnly; + if (elements.hostControlGuestNote) elements.hostControlGuestNote.style.display = (!amHost && hostOnly) ? 'block' : 'none'; +} + +if (elements.hostControlToggle) { + elements.hostControlToggle.addEventListener('change', () => { + const mode = elements.hostControlToggle.checked ? 'host-only' : 'everyone'; + chrome.runtime.sendMessage({ type: 'SET_CONTROL_MODE', controlMode: mode }, (res) => { + // Server broadcasts CONTROL_MODE back to refresh the UI; revert on failure. + if (chrome.runtime.lastError || !res || res.status !== 'ok') { + elements.hostControlToggle.checked = (mode === 'everyone'); + } + }); + }); +} + function updateUI(roomId, password, useCustomServer = false, serverUrl = '') { const inRoom = !!roomId; toggleUIState(inRoom); @@ -1656,6 +1690,9 @@ chrome.runtime.onMessage.addListener((msg) => { } else if (msg.type === 'PEER_UPDATE') { updatePeerList(msg.peers); if (msg.peers) detectPeerChanges(msg.peers); + } else if (msg.type === 'CONTROL_MODE') { + const inRoom = elements.sectionActive && elements.sectionActive.style.display === 'block'; + updateHostControlUI(msg.controlMode, msg.amHost, inRoom); } else if (msg.type === 'CONNECTION_STATUS') { if (msg.status === 'connected' || msg.status === 'disconnected') { if (joinBtnTimeout) { clearTimeout(joinBtnTimeout); joinBtnTimeout = null; } @@ -1673,6 +1710,7 @@ chrome.runtime.onMessage.addListener((msg) => { if (res.peers) updatePeerList(res.peers); if (res.lastActionState) updateLastActionUI(res.lastActionState, res.peers); updatePingDisplay(res.ping); + updateHostControlUI(res.controlMode, res.amHost, true); }); } if (msg.status === 'disconnected') {