iOS Share Screen: show the code and wait; start sharing when the helper joins
Fix the confusing flow: tapping Share Screen dumped the user straight into a meeting and auto-shared, with the join code hard to find. Now it shows a clear full-screen "Share your screen" step with the big 6-digit code + Copy + a "Waiting for them to join…" spinner (and Cancel). The native screen broadcast starts only when the helper actually joins with that code (meeting-peer-joined) — matching the remote-support mental model. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+30
-6
@@ -6153,9 +6153,9 @@ async function onMeetMsg(e){
|
|||||||
if(_pendingJoinMic){ _pendingJoinMic=false; if(!meetMic){ try{ await toggleMic(); }catch(_){} } }
|
if(_pendingJoinMic){ _pendingJoinMic=false; if(!meetMic){ try{ await toggleMic(); }catch(_){} } }
|
||||||
if(_pendingJoinCam){ _pendingJoinCam=false; if(!meetCam){ try{ await toggleCam(); }catch(_){} } }
|
if(_pendingJoinCam){ _pendingJoinCam=false; if(!meetCam){ try{ await toggleCam(); }catch(_){} } }
|
||||||
refreshMeetPanel(); updateHostControls();
|
refreshMeetPanel(); updateHostControls();
|
||||||
// iOS "Share Screen" entry: auto-start the native screen broadcast now that we have a peerId + room, and
|
// iOS "Share Screen" entry: show the code + a "waiting for them to join" screen. The screen broadcast
|
||||||
// surface the code so the user can hand it to whoever should watch.
|
// only STARTS once the helper joins (see meeting-peer-joined) — matching the remote-support mental model.
|
||||||
if(_autoShareOnJoin){ _autoShareOnJoin=false; setTimeout(()=>{ try{ toggleScreen(); }catch(_){} if(meetRoom) toast('Share code '+meetRoom+' so others can watch your screen.'); }, 800); }
|
if(_shareWaitMode){ showShareWaitOverlay(meetRoom); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The room is gone (host ended it / code expired). Say so plainly instead of hanging on "Connecting…"
|
// The room is gone (host ended it / code expired). Say so plainly instead of hanging on "Connecting…"
|
||||||
@@ -6176,6 +6176,8 @@ async function onMeetMsg(e){
|
|||||||
meetSend({type:'meeting-state', muted:!meetMic, camOff:!meetCam});
|
meetSend({type:'meeting-state', muted:!meetMic, camOff:!meetCam});
|
||||||
if(meetIsHost){ meetSend({type:'meeting-host', to:meetHostId}); meetSend({type:'meeting-sharemode', multi:meetMultiShare}); if(meetRec) meetSend({type:'meeting-recording', on:true}); }
|
if(meetIsHost){ meetSend({type:'meeting-host', to:meetHostId}); meetSend({type:'meeting-sharemode', multi:meetMultiShare}); if(meetRec) meetSend({type:'meeting-recording', on:true}); }
|
||||||
if(meetScreen) meetSend({type:'meeting-screen', on:true});
|
if(meetScreen) meetSend({type:'meeting-screen', on:true});
|
||||||
|
// iOS "Share Screen": the helper just joined → dismiss the waiting screen and start the screen broadcast now.
|
||||||
|
if(_shareWaitMode){ _shareWaitMode=false; hideShareWaitOverlay(); setTimeout(()=>{ try{ toggleScreen(); }catch(_){} }, 300); }
|
||||||
refreshMeetPanel(); return;
|
refreshMeetPanel(); return;
|
||||||
}
|
}
|
||||||
if(m.type==='meeting-peer-state'){ setTileMute(m.peerId, !!m.muted); meetCamOff.set(m.peerId, !!m.camOff); const _t=document.getElementById('meet-tile-'+m.peerId); if(_t){ const v=_t.querySelector('video'), s=v&&v.srcObject; const hv=!!(s&&s.getVideoTracks&&s.getVideoTracks().some(tr=>tr.enabled&&tr.readyState!=='ended')); _t.classList.toggle('novid', !hv || (!!m.camOff && !meetSharers.has(m.peerId))); } refreshMeetPanel(); return; } // camOff -> avatar, unless sharing a screen (#9)
|
if(m.type==='meeting-peer-state'){ setTileMute(m.peerId, !!m.muted); meetCamOff.set(m.peerId, !!m.camOff); const _t=document.getElementById('meet-tile-'+m.peerId); if(_t){ const v=_t.querySelector('video'), s=v&&v.srcObject; const hv=!!(s&&s.getVideoTracks&&s.getVideoTracks().some(tr=>tr.enabled&&tr.readyState!=='ended')); _t.classList.toggle('novid', !hv || (!!m.camOff && !meetSharers.has(m.peerId))); } refreshMeetPanel(); return; } // camOff -> avatar, unless sharing a screen (#9)
|
||||||
@@ -6314,18 +6316,40 @@ const panels=document.querySelectorAll('.panel');
|
|||||||
const chatcol=document.getElementById('chatcol');
|
const chatcol=document.getElementById('chatcol');
|
||||||
let loaded={share:false,connect:false};
|
let loaded={share:false,connect:false};
|
||||||
function currentTab(){ const b=document.querySelector('.railbtn.active'); return b?b.dataset.tab:'chat'; }
|
function currentTab(){ const b=document.querySelector('.railbtn.active'); return b?b.dataset.tab:'chat'; }
|
||||||
let _autoShareOnJoin=false;
|
let _shareWaitMode=false;
|
||||||
// iOS "Share Screen": WKWebView can't capture the P2P remote-support flow, so route it to a screen-share
|
// iOS "Share Screen": WKWebView can't capture the P2P remote-support flow, so route it to a screen-share
|
||||||
// MEETING — the native ReplayKit path publishes into LiveKit, and a helper joins by code to watch (+ talk/chat).
|
// MEETING — the native ReplayKit path publishes into LiveKit, and a helper joins by code to watch (+ talk/chat).
|
||||||
// (Viewing a shared screen already works in the webview; only capture is blocked, so only the SHARE side moves.)
|
// (Viewing a shared screen already works in the webview; only capture is blocked, so only the SHARE side moves.)
|
||||||
|
// UX: show the code + "waiting" first; screen sharing only STARTS once the helper joins (like remote support).
|
||||||
function startIosScreenShareMeeting(){
|
function startIosScreenShareMeeting(){
|
||||||
const NC=nativeCallPlugin();
|
const NC=nativeCallPlugin();
|
||||||
if(!NC || typeof NC.startMeetingScreenShare!=='function'){ switchTab('meeting'); toast('Update the app to share your screen'); return; }
|
if(!NC || typeof NC.startMeetingScreenShare!=='function'){ switchTab('meeting'); toast('Update the app to share your screen'); return; }
|
||||||
if(meetState==='call'){ switchTab('meeting'); toast('You’re already in a meeting — tap Share screen there.'); return; }
|
if(meetState==='call'){ switchTab('meeting'); toast('You’re already in a meeting — tap Share screen there.'); return; }
|
||||||
_autoShareOnJoin=true;
|
_shareWaitMode=true;
|
||||||
switchTab('meeting');
|
switchTab('meeting');
|
||||||
enterMeeting(null); // start an instant meeting; the auto-share fires once meeting-joined gives us a peerId
|
enterMeeting(null); // instant meeting; on join we show the code + wait, then auto-share when the helper joins
|
||||||
}
|
}
|
||||||
|
// Full-screen "give this code, waiting to join" screen shown to the iOS sharer before anyone connects.
|
||||||
|
function showShareWaitOverlay(code){
|
||||||
|
hideShareWaitOverlay();
|
||||||
|
const ov=document.createElement('div'); ov.id='shareWaitOv';
|
||||||
|
ov.style.cssText='position:fixed;inset:0;z-index:9200;background:linear-gradient(180deg,#20396f,#16294f);color:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px;text-align:center';
|
||||||
|
ov.innerHTML='<div style="max-width:360px;width:100%">'
|
||||||
|
+'<div style="font-size:1.35rem;font-weight:700;margin-bottom:.35rem">Share your screen</div>'
|
||||||
|
+'<div style="color:#c9d4ec;font-size:.95rem;line-height:1.5;margin-bottom:1.6rem">Give this code to the person who will view your screen. Sharing starts automatically when they join.</div>'
|
||||||
|
+'<div style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.18);border-radius:16px;padding:1.2rem 1rem;margin-bottom:1.3rem">'
|
||||||
|
+ '<div style="font-size:.72rem;letter-spacing:.14em;color:#9fb2d8;text-transform:uppercase;margin-bottom:.55rem">Your code</div>'
|
||||||
|
+ '<div style="font-size:2.6rem;font-weight:800;letter-spacing:.28em;font-variant-numeric:tabular-nums">'+pEsc(code)+'</div>'
|
||||||
|
+ '<button id="shareWaitCopy" style="margin-top:1rem;background:#FFC708;color:#16294f;border:none;border-radius:10px;padding:.55rem 1.1rem;font-weight:700;font-size:.9rem;cursor:pointer">Copy code</button>'
|
||||||
|
+'</div>'
|
||||||
|
+'<div style="display:flex;align-items:center;justify-content:center;gap:.5rem;color:#c9d4ec;font-size:.9rem;margin-bottom:1.6rem"><img src="/loaders/loader-ring.svg" width="22" height="22" alt=""> Waiting for them to join…</div>'
|
||||||
|
+'<button id="shareWaitCancel" style="background:transparent;border:1px solid rgba(255,255,255,.4);color:#fff;border-radius:10px;padding:.55rem 1.3rem;font-size:.9rem;cursor:pointer">Cancel</button>'
|
||||||
|
+'</div>';
|
||||||
|
document.body.appendChild(ov);
|
||||||
|
const cp=ov.querySelector('#shareWaitCopy'); if(cp) cp.onclick=async()=>{ try{ await navigator.clipboard.writeText(code); cp.textContent='Copied!'; setTimeout(()=>{ cp.textContent='Copy code'; },1500); }catch(_){} };
|
||||||
|
const cx=ov.querySelector('#shareWaitCancel'); if(cx) cx.onclick=()=>{ hideShareWaitOverlay(); _shareWaitMode=false; try{ leaveMeeting(true); }catch(_){} };
|
||||||
|
}
|
||||||
|
function hideShareWaitOverlay(){ const o=document.getElementById('shareWaitOv'); if(o) o.remove(); }
|
||||||
function switchTab(tab){
|
function switchTab(tab){
|
||||||
if(tab==='share' && SFU.on && bzIsIOS()){ startIosScreenShareMeeting(); return; } // iOS: screen-share via a meeting, not the P2P iframe
|
if(tab==='share' && SFU.on && bzIsIOS()){ startIosScreenShareMeeting(); return; } // iOS: screen-share via a meeting, not the P2P iframe
|
||||||
railBtns.forEach(b=>b.classList.toggle('active',b.dataset.tab===tab));
|
railBtns.forEach(b=>b.classList.toggle('active',b.dataset.tab===tab));
|
||||||
|
|||||||
Reference in New Issue
Block a user