fix(desktop): custom screen picker, single restart prompt, reliable call Join (0.1.8/batch61)
- Custom branded screen/window picker (picker.html) — useSystemPicker was silently no-op on Win11 and auto-shared the primary display with no choice. - Use checkForUpdates (not ...AndNotify): drops electron-updater's own native "Update ready" toast that duplicated our in-app banner (two restart prompts). - Call notification DP: wait up to 2.5s for the caller photo on persistent (call) toasts instead of 600ms so the DP actually shows. - Re-surface Join/Decline invite when opening a chat with an active incoming call, so a call-notification click always lands on a joinable call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+13
-5
@@ -840,7 +840,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-batch60';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
<script>window.__BUILD='2026-07-08-batch61';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>
|
||||
@@ -1749,7 +1749,8 @@ async function startOrJoinGroupCall(group){
|
||||
}
|
||||
function updateCallBtn(active){ const cc=document.getElementById('convoCall'); if(!cc) return; cc.classList.toggle('joinable',active); cc.title=active?'Join call':'Start call'; cc.innerHTML=ic(active?'video':'phone',18)+(active?'<span>Join</span>':''); }
|
||||
function onGroupCall(d){
|
||||
if(!d||!d.group) return; const it=rowFor('group',d.group); if(it){ it.callActive=!!d.active; it.callRoom=d.room||null; }
|
||||
if(!d||!d.group) return; const it=rowFor('group',d.group); if(it){ it.callActive=!!d.active; it.callRoom=d.room||null;
|
||||
if(d.active && d.by && d.by!==ME.id){ it.incomingRoom=d.room; it.callByName=d.startedByName; } else if(!d.active){ it.incomingRoom=null; it.callByName=null; } }
|
||||
if(selected&&selected.kind==='group'&&selected.id===d.group) updateCallBtn(!!d.active);
|
||||
if(d.active && d.by && d.by!==ME.id && meetRoom!==d.room) showCallInvite(d.room, d.startedByName, {kind:'group',id:d.group}, d.groupName||(it&&it.name)||'Group'); // ring members in
|
||||
if(!d.active) dismissCallInvite(d.room); // call ended — stop ringing
|
||||
@@ -1773,7 +1774,8 @@ function onPresence(d){
|
||||
}
|
||||
}
|
||||
function onDmCall(d){
|
||||
if(!d) return; const it=rowFor('dm', d.with); if(it){ it.callActive=!!d.active; it.callRoom=d.room||null; if(!d.active && it.status==='incall') it.status='active'; } // #4: drop the stuck "in call" status
|
||||
if(!d) return; const it=rowFor('dm', d.with); if(it){ it.callActive=!!d.active; it.callRoom=d.room||null; if(!d.active && it.status==='incall') it.status='active'; // #4: drop the stuck "in call" status
|
||||
if(d.active && d.by && d.by!==ME.id){ it.incomingRoom=d.room; it.callByName=d.byName; } else if(!d.active){ it.incomingRoom=null; it.callByName=null; } } // remember an incoming call so opening the chat can re-show Join
|
||||
if(selected&&selected.kind==='dm'&&selected.id===d.with){ updateCallBtn(!!d.active); const s=document.querySelector('#convoTitle .st'); if(s&&it) s.textContent=dmSubLabel(it); } // refresh the header subtitle live
|
||||
if(d.active && d.by && d.by!==ME.id) showCallInvite(d.room, d.byName, {kind:'dm',id:d.with}); // incoming 1:1 call
|
||||
if(!d.active) dismissCallInvite(d.room); // call ended/declined — stop ringing
|
||||
@@ -1782,7 +1784,7 @@ function onDmCall(d){
|
||||
// Incoming-call banner (1:1 call or an add-participant invite) with Join / Dismiss.
|
||||
// ret: where to land when the call ends (the originating chat), or null for the meetings tab.
|
||||
// sub: a second line under the caller — e.g. the group name for a group call.
|
||||
function showCallInvite(room, byName, ret, sub){
|
||||
function showCallInvite(room, byName, ret, sub, quiet){
|
||||
if(!room || document.getElementById('ci-'+room)) return;
|
||||
startRing();
|
||||
const who=byName||'Someone';
|
||||
@@ -1792,7 +1794,7 @@ function showCallInvite(room, byName, ret, sub){
|
||||
+'<button class="ci-join">'+ic('video',16)+' Join</button>'
|
||||
+'<button class="ci-decline" title="Decline">'+ic('callEnd',16)+' Decline</button>';
|
||||
document.body.appendChild(el);
|
||||
try{ notify('📞 '+who, (sub?('Group call · '+sub):'is calling you'), ret&&ret.kind, ret&&ret.id, {persistent:true}); }catch(_){} // OS notification too (stays until clicked/ended)
|
||||
if(!quiet){ try{ notify('📞 '+who, (sub?('Group call · '+sub):'is calling you'), ret&&ret.kind, ret&&ret.id, {persistent:true}); }catch(_){} } // OS notification too (skip when merely re-showing on chat open)
|
||||
let closed=false;
|
||||
const close=()=>{ if(closed) return; closed=true; try{ el.remove(); }catch(_){} stopRing(); };
|
||||
el.querySelector('.ci-join').onclick=()=>{ close(); meetReturn=ret||null; switchTab('meeting'); enterMeeting(room); };
|
||||
@@ -1973,6 +1975,12 @@ async function openConvo(kind,id){
|
||||
const ci=document.getElementById('convoInfo'); if(ci) ci.onclick=()=>openGroupInfo(id);
|
||||
const ct=document.getElementById('convoTitle'); if(ct) ct.onclick=()=>{ if(kind==='group') openGroupInfo(id); else { const r=rowFor(kind,id); openSharedItems('dm', id, (r&&r.name)||it.name||''); } }; // name → group: info+media; DM: media/files
|
||||
const cc=document.getElementById('convoCall'); if(cc) cc.onclick=()=>(kind==='group'?startOrJoinGroupCall(id):startOrJoinDmCall(id));
|
||||
// If this conversation has an active INCOMING call, (re)show the Join/Decline invite. When the chat
|
||||
// is opened from a call notification, the original transient invite popup may already have closed —
|
||||
// this guarantees a landing Join button. `quiet` avoids firing a duplicate OS notification.
|
||||
if(it.callActive && it.incomingRoom && meetRoom!==it.incomingRoom && !document.getElementById('ci-'+it.incomingRoom)){
|
||||
showCallInvite(it.incomingRoom, it.callByName||it.name, kind==='group'?{kind:'group',id}:{kind:'dm',id}, kind==='group'?it.name:undefined, true);
|
||||
}
|
||||
const csb=document.getElementById('convoSearch'); const cshead=document.getElementById('convoSearchHead'); const csin=document.getElementById('convoSearchInput');
|
||||
if(csb) csb.onclick=()=>{ if(!cshead) return; cshead.style.display='flex'; if(csin){ csin.value=''; setTimeout(()=>csin.focus(),0); } };
|
||||
if(csin) csin.oninput=()=>runSearch(csin.value);
|
||||
|
||||
Reference in New Issue
Block a user