fix: SFU participants, duplicate peers, RC without login, devices, mobile bar (batch75)
#4 Participants list only ever showed "you": in SFU mode meetMakePeer drew a tile but NEVER added to meetPeers, so the roster (and the meeting-chat "To" list) was empty. #5 Same person as several tiles: each tab/reload/reconnect gets a new peerId, leaving ghost peers. One uid = one tile now (dropDupPeers keeps the newest). #1 Remote control needed a login: /share opened top-level (the no-login "Share my screen") has the preload bridge RIGHT THERE, but we only postMessage'd to a parent frame that doesn't exist — so control never armed. Use the native bridge directly. #2 Sharer's session bar moved to the shared Lucide icon set (was old inline SVGs). #3/#6 Device menu: collapse Windows' "Default -"/"Communications -" triplicates into one clean list (single "System default" + each real device once), and actually re-apply the saved mic/speaker to the room on connect so a picked headset/Bluetooth is used. #7 Guest "left the meeting" screen rebranded to match the new pre-join. #9 Tapping a member in group info opens the private conversation with them. #8a iOS bottom rail: border-box + height incl. the home-indicator inset, px env() fallbacks (unitless 0 breaks calc() in Safari), promoted layer so it stops drifting. #8c/#8e Mobile meeting bar: Mic / Camera / Speaker / End only; screen, record, transcript, chat, participants move behind a ⋮ More menu. No mic device dropdown on mobile. #8d Speaker button reflects the real route: speaker-on / speaker-off (dimmed) / bluetooth when a headset is in use; re-detected on devicechange. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -72,7 +72,7 @@
|
||||
@keyframes rcpulse{0%{box-shadow:0 0 0 0 rgba(34,197,94,.6)}70%{box-shadow:0 0 0 8px rgba(34,197,94,0)}100%{box-shadow:0 0 0 0 rgba(34,197,94,0)}}
|
||||
.rc-banner button{background:#ef4444;color:#fff;border:none;border-radius:999px;padding:.35rem .8rem;font-size:.8rem;font-weight:700;cursor:pointer;}
|
||||
</style>
|
||||
<script src="/icons.js?v=3"></script>
|
||||
<script src="/icons.js?v=6"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>if(new URLSearchParams(location.search).get('embed')==='1')document.documentElement.classList.add('embed');</script>
|
||||
@@ -226,9 +226,22 @@ function stopCustTranscription(){ crecogActive=false; if(crecog){ try{crecog.sto
|
||||
// after the user explicitly taps "Allow control", and only inside the desktop app. In a plain browser
|
||||
// there's no OS injection possible, so it stays view-only. The user can stop control at any time.
|
||||
let rcDesktop=false, rcAllowed=false, rcPrompted=false;
|
||||
// Two ways this page runs inside the desktop app:
|
||||
// • EMBEDDED in the signed-in app (Share tab iframe) → no direct bridge, relay via the parent frame.
|
||||
// • TOP-LEVEL, no login (the landing page's "Share my screen") → the preload bridge is right here.
|
||||
// The second case is the whole point of a support tool (the customer isn't a Connect user), and it was
|
||||
// broken: we only ever postMessage'd to a parent that didn't exist, so control never armed. #1
|
||||
const rcNative=(window.bizConnectNative && typeof window.bizConnectNative.rcAvailable==='function') ? window.bizConnectNative : null;
|
||||
if(rcNative){ try{ rcDesktop=!!rcNative.rcAvailable(); }catch(_){ rcDesktop=false; } }
|
||||
try{ window.addEventListener('message',(e)=>{ if(e.origin!==location.origin) return; const d=e.data||{}; if(d.type==='rc-pong'){ rcDesktop=!!d.desktop; try{ updateRcBtn(); }catch(_){} } }); }catch(_){}
|
||||
try{ if(window.parent && window.parent!==window) window.parent.postMessage({type:'rc-ping'}, location.origin); }catch(_){}
|
||||
function rcPost(msg){ try{ if(window.parent && window.parent!==window) window.parent.postMessage(msg, location.origin); }catch(_){} }
|
||||
try{ if(!rcNative && window.parent && window.parent!==window) window.parent.postMessage({type:'rc-ping'}, location.origin); }catch(_){}
|
||||
function rcPost(msg){
|
||||
if(rcNative){
|
||||
try{ if(msg.type==='rc-arm') rcNative.rcArm(!!msg.on); else if(msg.type==='rc-input') rcNative.rcInput(msg.evt); }catch(_){}
|
||||
return;
|
||||
}
|
||||
try{ if(window.parent && window.parent!==window) window.parent.postMessage(msg, location.origin); }catch(_){}
|
||||
}
|
||||
function rcOnInput(data){
|
||||
let evt; try{ evt=JSON.parse(data); }catch(_){ return; }
|
||||
if(rcAllowed){ rcPost({type:'rc-input', evt}); return; }
|
||||
@@ -304,16 +317,18 @@ function buildBar(){
|
||||
if(document.getElementById('sessionBar'))return;
|
||||
const bar=document.createElement('div'); bar.id='sessionBar';
|
||||
bar.style.cssText='position:fixed;right:18px;bottom:18px;z-index:2147483000;display:flex;gap:10px;align-items:center;background:rgba(15,23,42,.94);padding:8px 12px;border-radius:16px;box-shadow:0 10px 28px rgba(0,0,0,.35)';
|
||||
const mic=_btn('micBtn',SVG_MICOFF,'Muted','#6b7280');
|
||||
// #2: use the shared Lucide icon set (ic) — the bar was still on the old hand-rolled SVGs.
|
||||
const I=(n,s)=>(window.ic?window.ic(n,s||18):'');
|
||||
const mic=_btn('micBtn',I('micOff'),'Muted','#6b7280');
|
||||
// Remote-control access, right next to mic/chat, so the customer can see AND flip it at a glance.
|
||||
const rcb=_btn('rcBtn',(window.ic?window.ic('monitor',18):''),'Remote control is OFF','#6b7280');
|
||||
const chat=_btn('chatBtn',SVG_CHAT,'Chat','#475569');
|
||||
const end=_btn('endBtn2',SVG_END,'End','#dc2626');
|
||||
const rcb=_btn('rcBtn',I('monitor'),'Remote control is OFF','#6b7280');
|
||||
const chat=_btn('chatBtn',I('chat'),'Chat','#475569');
|
||||
const end=_btn('endBtn2',I('callEnd'),'End','#dc2626');
|
||||
bar.appendChild(mic);bar.appendChild(rcb);bar.appendChild(chat);bar.appendChild(end);
|
||||
document.body.appendChild(bar);
|
||||
rcb.onclick=()=>{ if(rcAllowed) rcStopControl(); else rcGrantControl(); };
|
||||
updateRcBtn();
|
||||
const setMic=(on)=>{mic.title=on?'Mute':'Unmute';mic.innerHTML='<span style="display:inline-flex">'+(on?SVG_MIC:SVG_MICOFF)+'</span>';mic.style.background=on?'#2563eb':'#6b7280';};
|
||||
const setMic=(on)=>{mic.title=on?'Mute':'Unmute';mic.innerHTML='<span style="display:inline-flex">'+I(on?'mic':'micOff')+'</span>';mic.style.background=on?'#2563eb':'#6b7280';};
|
||||
mic.onclick=async()=>{
|
||||
if(!window.__mic){
|
||||
// First unmute: NOW request mic permission, add the track, and renegotiate.
|
||||
|
||||
Reference in New Issue
Block a user