Fix: hide native video while a meeting menu/panel is open (z-order)

Native video draws on top of the WebView, so the More/audio menu,
participant panel, meeting chat, modals and the image lightbox all opened
BEHIND the shared screen. Now bzNativeSyncTiles clears the native tiles
whenever any of those overlays is present (.meet-panel/.spk-menu/.modal-ov/
.lightbox), and the menu/panel toggles trigger an immediate sync so there's
no lag; the video returns when they close.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 11:14:41 +05:30
parent f2efff394b
commit f971908d80
+10 -4
View File
@@ -2654,7 +2654,7 @@ function meetParticipantsList(){ const a=[{id:'__local', name:((ME&&ME.name)||(M
let meetChatLog=[], meetChatUnread=0, meetChatTo=''; let meetChatLog=[], meetChatUnread=0, meetChatTo='';
function resetMeetChat(){ meetChatLog=[]; meetChatUnread=0; meetChatTo=''; const c=document.getElementById('meetChat'); if(c) c.remove(); updateMeetChatBadge(); } function resetMeetChat(){ meetChatLog=[]; meetChatUnread=0; meetChatTo=''; const c=document.getElementById('meetChat'); if(c) c.remove(); updateMeetChatBadge(); }
function meetChatRecipients(){ const a=[]; meetPeers.forEach((pp,pid)=>a.push({id:pid, name:meetNames.get(pid)||pp.name||'Guest'})); return a; } function meetChatRecipients(){ const a=[]; meetPeers.forEach((pp,pid)=>a.push({id:pid, name:meetNames.get(pid)||pp.name||'Guest'})); return a; }
function toggleMeetChat(){ const ex=document.getElementById('meetChat'); if(ex){ ex.remove(); return; } const meet=document.querySelector('.meet'); if(!meet) return; const p=document.createElement('div'); p.id='meetChat'; p.className='meet-panel meet-chat'; meet.appendChild(p); meetChatUnread=0; updateMeetChatBadge(); renderMeetChat(); } function toggleMeetChat(){ const ex=document.getElementById('meetChat'); if(ex){ ex.remove(); try{ bzNativeSyncTiles(); }catch(_){} return; } const meet=document.querySelector('.meet'); if(!meet) return; const p=document.createElement('div'); p.id='meetChat'; p.className='meet-panel meet-chat'; meet.appendChild(p); meetChatUnread=0; updateMeetChatBadge(); renderMeetChat(); try{ bzNativeSyncTiles(); }catch(_){} }
function updateMeetChatBadge(){ const b=document.getElementById('meetChatBadge'); if(!b) return; if(meetChatUnread>0){ b.textContent=meetChatUnread>9?'9+':meetChatUnread; b.style.display='grid'; } else b.style.display='none'; } function updateMeetChatBadge(){ const b=document.getElementById('meetChatBadge'); if(!b) return; if(meetChatUnread>0){ b.textContent=meetChatUnread>9?'9+':meetChatUnread; b.style.display='grid'; } else b.style.display='none'; }
function renderMeetChat(){ function renderMeetChat(){
const p=document.getElementById('meetChat'); if(!p) return; const p=document.getElementById('meetChat'); if(!p) return;
@@ -2719,7 +2719,7 @@ function copyMeetingLink(){
function fallbackCopy(text,cb){ try{ const ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.opacity='0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); ta.remove(); cb&&cb(); }catch(_){ prompt('Copy this link:', text); } } function fallbackCopy(text,cb){ try{ const ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.opacity='0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); ta.remove(); cb&&cb(); }catch(_){ prompt('Copy this link:', text); } }
let meetPanelTab='people'; // 'people' | 'add' let meetPanelTab='people'; // 'people' | 'add'
let _addPool=null; // cached candidates for "Add people" (group members for a group call) let _addPool=null; // cached candidates for "Add people" (group members for a group call)
function toggleMeetPanel(){ const ex=document.getElementById('meetPanel'); if(ex){ ex.remove(); return; } const meet=document.querySelector('.meet'); if(!meet) return; meetPanelTab='people'; const p=document.createElement('div'); p.id='meetPanel'; p.className='meet-panel'; meet.appendChild(p); renderMeetPanel(); } function toggleMeetPanel(){ const ex=document.getElementById('meetPanel'); if(ex){ ex.remove(); try{ bzNativeSyncTiles(); }catch(_){} return; } const meet=document.querySelector('.meet'); if(!meet) return; meetPanelTab='people'; const p=document.createElement('div'); p.id='meetPanel'; p.className='meet-panel'; meet.appendChild(p); renderMeetPanel(); try{ bzNativeSyncTiles(); }catch(_){} }
function renderMeetPanel(){ function renderMeetPanel(){
const p=document.getElementById('meetPanel'); if(!p) return; const p=document.getElementById('meetPanel'); if(!p) return;
const list=meetParticipantsList(); const list=meetParticipantsList();
@@ -5060,9 +5060,10 @@ function openMeetMore(anchor){
const r=anchor.getBoundingClientRect(); const r=anchor.getBoundingClientRect();
menu.style.left=Math.max(8,Math.min(r.left-100, window.innerWidth-menu.offsetWidth-8))+'px'; menu.style.left=Math.max(8,Math.min(r.left-100, window.innerWidth-menu.offsetWidth-8))+'px';
menu.style.top=Math.max(8,(r.top-menu.offsetHeight-10))+'px'; menu.style.top=Math.max(8,(r.top-menu.offsetHeight-10))+'px';
menu.querySelectorAll('.mm-opt').forEach(b=>b.onclick=()=>{ const it=items[+b.dataset.i]; menu.remove(); try{ it.fn(); }catch(_){} }); menu.querySelectorAll('.mm-opt').forEach(b=>b.onclick=()=>{ const it=items[+b.dataset.i]; menu.remove(); try{ it.fn(); }catch(_){} try{ if(meetNative) bzNativeSyncTiles(); }catch(_){} });
const close=(e)=>{ if(!menu.contains(e.target) && !anchor.contains(e.target)){ menu.remove(); document.removeEventListener('mousedown',close); document.removeEventListener('touchstart',close); } }; const close=(e)=>{ if(!menu.contains(e.target) && !anchor.contains(e.target)){ menu.remove(); document.removeEventListener('mousedown',close); document.removeEventListener('touchstart',close); try{ if(meetNative) bzNativeSyncTiles(); }catch(_){} } };
setTimeout(()=>{ document.addEventListener('mousedown',close); document.addEventListener('touchstart',close); },0); setTimeout(()=>{ document.addEventListener('mousedown',close); document.addEventListener('touchstart',close); },0);
try{ if(meetNative) bzNativeSyncTiles(); }catch(_){} // clear the native video NOW so the menu isn't hidden behind it
} }
async function setSpeakerDevice(id){ async function setSpeakerDevice(id){
meetSinkId=id||''; try{ localStorage.setItem('bzc_sink', meetSinkId); }catch(_){} meetSinkId=id||''; try{ localStorage.setItem('bzc_sink', meetSinkId); }catch(_){}
@@ -5390,9 +5391,14 @@ let meetNative=false, meetNativeUuid=null, _ncEnding=false; // native call: WebV
// join-leave / camera-toggle changes; a no-op on web calls. getBoundingClientRect coords are CSS px, which // join-leave / camera-toggle changes; a no-op on web calls. getBoundingClientRect coords are CSS px, which
// equal points in the WKWebView, so the plugin can use them directly. // equal points in the WKWebView, so the plugin can use them directly.
let _ncTileTimer=null; let _ncTileTimer=null;
// Any web menu/panel/modal that opens over the meeting would be hidden BEHIND the native video (which draws
// on top of the WebView). While one is open, clear the native video so the web UI is usable; the poll restores
// it when they close. (Covers the More/audio menus, participant panel, meeting chat, modals, image lightbox.)
function bzMeetOverlayOpen(){ return !!document.querySelector('.meet-panel, .spk-menu, .modal-ov, .lightbox'); }
function bzNativeSyncTiles(){ function bzNativeSyncTiles(){
if(!meetNative) return; if(!meetNative) return;
const NC=nativeCallPlugin(); if(!NC||!NC.syncVideoTiles) return; const NC=nativeCallPlugin(); if(!NC||!NC.syncVideoTiles) return;
if(bzMeetOverlayOpen()){ try{ NC.syncVideoTiles({ tiles:[] }); }catch(_){} return; } // a menu/panel is open → don't cover it
const tiles=[]; const tiles=[];
// Native views draw ON TOP of the WebView, so a full-height tile would cover the control bar. Never let a // Native views draw ON TOP of the WebView, so a full-height tile would cover the control bar. Never let a
// tile's native video extend past the top of the meeting controls (or, in normal grid mode, below the grid). // tile's native video extend past the top of the meeting controls (or, in normal grid mode, below the grid).