SHA256
feat(call-ui): полноценное окно звонка, статусы, звуки и тех-история вызовов
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import {
|
||||
acceptIncomingCall,
|
||||
declineIncomingCall,
|
||||
hangupActiveCall,
|
||||
setMicMuted,
|
||||
subscribeCallState,
|
||||
} from './call-service.js';
|
||||
|
||||
let shellEl = null;
|
||||
let panelEl = null;
|
||||
let titleEl = null;
|
||||
let statusEl = null;
|
||||
let muteBtn = null;
|
||||
let acceptBtn = null;
|
||||
let declineBtn = null;
|
||||
let hangupBtn = null;
|
||||
let unbind = null;
|
||||
|
||||
function ensureUi() {
|
||||
if (shellEl) return;
|
||||
|
||||
shellEl = document.createElement('section');
|
||||
shellEl.className = 'call-overlay';
|
||||
shellEl.hidden = true;
|
||||
|
||||
panelEl = document.createElement('div');
|
||||
panelEl.className = 'call-overlay-panel';
|
||||
|
||||
titleEl = document.createElement('h2');
|
||||
titleEl.className = 'call-overlay-title';
|
||||
|
||||
statusEl = document.createElement('div');
|
||||
statusEl.className = 'call-overlay-status';
|
||||
|
||||
const controls = document.createElement('div');
|
||||
controls.className = 'call-overlay-controls';
|
||||
|
||||
muteBtn = document.createElement('button');
|
||||
muteBtn.type = 'button';
|
||||
muteBtn.className = 'secondary-btn';
|
||||
muteBtn.textContent = 'Микрофон';
|
||||
muteBtn.addEventListener('click', async () => {
|
||||
const nowMuted = muteBtn.dataset.muted === '1';
|
||||
await setMicMuted(!nowMuted);
|
||||
});
|
||||
|
||||
acceptBtn = document.createElement('button');
|
||||
acceptBtn.type = 'button';
|
||||
acceptBtn.className = 'primary-btn';
|
||||
acceptBtn.textContent = 'Ответить';
|
||||
acceptBtn.addEventListener('click', async () => {
|
||||
await acceptIncomingCall();
|
||||
});
|
||||
|
||||
declineBtn = document.createElement('button');
|
||||
declineBtn.type = 'button';
|
||||
declineBtn.className = 'ghost-btn';
|
||||
declineBtn.textContent = 'Отклонить';
|
||||
declineBtn.addEventListener('click', async () => {
|
||||
await declineIncomingCall();
|
||||
});
|
||||
|
||||
hangupBtn = document.createElement('button');
|
||||
hangupBtn.type = 'button';
|
||||
hangupBtn.className = 'destructive-btn';
|
||||
hangupBtn.textContent = 'Положить';
|
||||
hangupBtn.addEventListener('click', async () => {
|
||||
await hangupActiveCall();
|
||||
});
|
||||
|
||||
controls.append(muteBtn, acceptBtn, declineBtn, hangupBtn);
|
||||
panelEl.append(titleEl, statusEl, controls);
|
||||
shellEl.append(panelEl);
|
||||
document.body.append(shellEl);
|
||||
}
|
||||
|
||||
function applyCallState(snapshot) {
|
||||
ensureUi();
|
||||
|
||||
if (!snapshot) {
|
||||
shellEl.hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
shellEl.hidden = false;
|
||||
titleEl.textContent = `Звонок: ${snapshot.peerLogin || 'пользователь'}`;
|
||||
statusEl.textContent = snapshot.statusText || '';
|
||||
|
||||
const muted = Boolean(snapshot.muted);
|
||||
muteBtn.dataset.muted = muted ? '1' : '0';
|
||||
muteBtn.textContent = muted ? 'Микрофон выкл' : 'Микрофон вкл';
|
||||
|
||||
muteBtn.hidden = !snapshot.canMute;
|
||||
muteBtn.disabled = !snapshot.canMute;
|
||||
|
||||
acceptBtn.hidden = !snapshot.canAnswer;
|
||||
declineBtn.hidden = !snapshot.canDecline;
|
||||
|
||||
hangupBtn.hidden = !snapshot.canHangup;
|
||||
}
|
||||
|
||||
export function initCallUiOverlay() {
|
||||
ensureUi();
|
||||
if (unbind) {
|
||||
unbind();
|
||||
unbind = null;
|
||||
}
|
||||
unbind = subscribeCallState(applyCallState);
|
||||
}
|
||||
Reference in New Issue
Block a user