fix(calls): screen shows with camera OFF (#9), screen-share button highlight, unanswered caller vs callee text
- #9 REAL cause: the tile was forced to avatar whenever the peer's CAMERA was off (addTile + meeting-peer-state), so a screen-share only appeared if the camera was also on. Now camera-off only shows the avatar when the peer is NOT sharing a screen. - #9: screen-share button is highlighted (blue) while active, like mic/cam/record. - Unanswered call text is viewer-relative: the caller sees 'Call not answered', the callee sees 'Missed call'. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -424,6 +424,7 @@
|
||||
.meet-bar .meet-ic{width:46px;height:46px;padding:0;border-radius:50%;background:#e8edf5;color:var(--blue);display:inline-flex;align-items:center;justify-content:center;}
|
||||
.meet-bar .meet-ic:hover{background:#dbe4f0;}
|
||||
.meet-bar .meet-ic.off{background:#fee2e2;color:var(--red);}
|
||||
.meet-bar .meet-ic.on{background:var(--blue);color:#fff;} /* #9: screen-share highlighted while active (record keeps its red pulse via #meetRecBtn.on) */
|
||||
.meet-bar .meet-ic.leave,.meet-bar .meet-ic.leave.off{background:#dc2626;color:#fff;}
|
||||
.meet-bar .meet-ic.leave:hover{background:#b91c1c;}
|
||||
/* Meetings dashboard (full-width, scrollable) */
|
||||
@@ -826,7 +827,7 @@
|
||||
<body>
|
||||
<script src="/icons.js?v=5"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@twemoji/api@15.1.0/dist/twemoji.min.js" crossorigin="anonymous"></script>
|
||||
<script>window.__BUILD='2026-07-08-batch56';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
<script>window.__BUILD='2026-07-08-batch57';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
// Render modern (Twemoji) emojis in place of the OS's flat ones. No-op if the CDN didn't load
|
||||
// (emojis stay as plain Unicode). (#5)
|
||||
function twemojify(el){ try{ if(el && window.twemoji) window.twemoji.parse(el, { folder:'svg', ext:'.svg' }); }catch(_){} }</script>
|
||||
@@ -1456,6 +1457,8 @@ function convoShellHTML(it){
|
||||
function senderAvatar(id, name){ const mem=convoMembers.find(x=>x.id===id); const av=mem&&mem.avatar; return '<span class="snd-av" style="background:'+avColor(name||'?')+'">'+(av?'<img src="'+pEsc(av)+'" alt="" onerror="this.remove()">':'')+pEsc(initials(name||'?'))+'</span>'; }
|
||||
function bubbleHTML(m){
|
||||
if(m.evt==='call-start') return '<div class="sys-msg">📞 '+(m.from===ME.id?'You':pEsc(m.byName||'Someone'))+' started a call</div>';
|
||||
// Unanswered 1:1: the caller (message sender) sees "Call not answered"; the callee sees "Missed call".
|
||||
if(m.evt==='call-end' && /Missed call|not answered/i.test(m.body||'')) return '<div class="sys-msg">📞 '+(m.from===ME.id?'Call not answered':'Missed call')+'</div>';
|
||||
if(m.system||m.from==='__system__') return '<div class="sys-msg">'+pEsc(m.body)+'</div>';
|
||||
const mine=m.from===ME.id;
|
||||
if(m.deleted) return '<div class="bubble '+(mine?'mine':'them')+' deleted" data-id="'+pEsc(m.id)+'"><span class="del-msg">'+ic('trash',12)+' This message was deleted</span><span class="t">'+pEsc(fmtClock(m.created_at))+'</span></div>';
|
||||
@@ -3000,7 +3003,7 @@ function addTile(id, stream, label, muted){
|
||||
tile.innerHTML='<video autoplay playsinline'+(muted?' muted':'')+'></video><div class="meet-av" style="background:'+avColor(label||'?')+'">'+pEsc(initials(label||'?'))+(av?'<img src="'+pEsc(av)+'" alt="" onerror="this.remove()">':'')+'</div><div class="meet-mute" style="display:none">'+ic('micOff',14)+'</div><span class="nm">'+pEsc(label||'')+'</span>'; grid.appendChild(tile); }
|
||||
const v=tile.querySelector('video'); if(v && stream && v.srcObject!==stream) v.srcObject=stream;
|
||||
const hasVid=!!(stream && stream.getVideoTracks && stream.getVideoTracks().some(t=>t.enabled && t.readyState!=='ended'));
|
||||
tile.classList.toggle('novid', !hasVid || meetCamOff.get(id)===true); // camOff peer → avatar even if a (disabled) track arrives
|
||||
tile.classList.toggle('novid', !hasVid || (meetCamOff.get(id)===true && !meetSharers.has(id))); // camOff → avatar, UNLESS they're sharing a screen (#9: screen must show even with camera off)
|
||||
if(meetMuted.has(id)) setTileMute(id, meetMuted.get(id)); // apply any known mute state
|
||||
}
|
||||
function setTileMute(id, muted){ meetMuted.set(id, !!muted); const t=document.getElementById('meet-tile-'+id); if(t){ const b=t.querySelector('.meet-mute'); if(b) b.style.display=muted?'grid':'none'; if(muted) t.classList.remove('speaking'); } }
|
||||
@@ -3226,7 +3229,7 @@ async function onMeetMsg(e){
|
||||
if(meetScreen) meetSend({type:'meeting-screen', on:true});
|
||||
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); } refreshMeetPanel(); return; } // camOff -> show avatar, not a black tile
|
||||
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-host'){ const was=meetIsHost; meetHostId=m.hostPeerId; meetIsHost=(m.hostPeerId===meetMyId); if(meetIsHost&&!was){ toast('You are now the host'); try{ speak('You are now the host'); }catch(_){} } refreshMeetPanel(); updateHostControls(); return; }
|
||||
if(m.type==='meeting-transcribe-state'){ applyRoomTx(!!m.active); return; } // ≥1 subscriber → transcribe my mic
|
||||
if(m.type==='meeting-recording'){ recNotice(!!m.on, m.by); return; } // someone is recording — show + announce
|
||||
|
||||
Reference in New Issue
Block a user