video call

This commit is contained in:
2026-03-11 08:05:54 +01:00
parent f0e2b60f43
commit ffdea4fe62
9 changed files with 644 additions and 412 deletions

View File

@@ -1,37 +1,39 @@
<main class="chat-shell py-4">
<div class="container-lg">
<section class="chat-page panel p-3 p-lg-4">
<app-peer-video-modal
[visible]="remoteVideoModalVisible()"
[stream]="remoteVideoStream()"
[title]="(peer()?.displayName ?? 'Peer') + ' webcam'"
(closeRequested)="closeRemoteVideoModal()"
></app-peer-video-modal>
<app-peer-call-modal
[visible]="callModalVisible()"
[peerName]="callModalPeer()?.displayName ?? 'Peer'"
[callState]="callModalState()"
[callMode]="callModalMode()"
[statusText]="callModalStatusText()"
[localStream]="localCallStream()"
[remoteStream]="remoteCallVideoStream()"
(acceptRequested)="callModalPeer() && acceptIncomingVoiceCall(callModalPeer()!.id)"
(rejectRequested)="callModalPeer() && rejectIncomingVoiceCall(callModalPeer()!.id)"
(hangupRequested)="callModalPeer() && endVoiceCall(callModalPeer()!.id)"
></app-peer-call-modal>
<audio #callAudioElement hidden autoplay playsinline></audio>
@if (incomingVoiceCallPeer(); as callingPeer) {
<div class="call-modal-backdrop">
<section class="panel p-4" style="width:min(100%,24rem)" (click)="$event.stopPropagation()">
<div class="mb-3">
<div>
<h2 class="h5 mb-1">Incoming voice call</h2>
<p class="small mb-0">{{ callingPeer.displayName }} is calling you.</p>
</div>
</div>
<div class="d-flex flex-wrap gap-2 justify-content-end">
<button
class="btn btn-success"
type="button"
(click)="acceptIncomingVoiceCall(callingPeer.id)"
>
Accept
@if (callChoicePeer(); as selectedCallPeer) {
<div class="call-choice-backdrop" (click)="closeCallChoice()">
<section class="call-choice-card panel p-4" (click)="$event.stopPropagation()">
<p class="call-choice-eyebrow">Start a call</p>
<h2 class="h5 mb-2">{{ selectedCallPeer.displayName }}</h2>
<p class="small mb-3">Choose whether to place a full video call or audio only.</p>
<div class="call-choice-actions">
<button class="call-choice-button" type="button" (click)="startSelectedCall('video')">
<span class="call-choice-icon">📹</span>
<span>Video call</span>
</button>
<button
class="btn btn-outline-secondary"
type="button"
(click)="rejectIncomingVoiceCall(callingPeer.id)"
>
Reject
<button class="call-choice-button" type="button" (click)="startSelectedCall('audio')">
<span class="call-choice-icon">🎙️</span>
<span>Audio only</span>
</button>
</div>
<div class="d-flex justify-content-end mt-3">
<button class="btn btn-outline-secondary" type="button" (click)="closeCallChoice()">
Cancel
</button>
</div>
</section>
@@ -272,9 +274,9 @@
class="composer-call"
type="button"
[disabled]="!canStartSelectedVoiceCall()"
(click)="startVoiceCall(selectedPeer.id)"
title="Start voice call"
aria-label="Start voice call"
(click)="openCallChoice(selectedPeer.id)"
title="Start call"
aria-label="Start call"
>
📞
</button>
@@ -284,24 +286,13 @@
class="composer-hangup"
type="button"
(click)="endVoiceCall(selectedPeer.id)"
title="End voice call"
aria-label="End voice call"
title="End call"
aria-label="End call"
>
🛑
</button>
}
<button
class="composer-camera"
type="button"
[disabled]="selectedPeer.channelState !== 'open' && !isStreamingCameraToSelectedPeer()"
(click)="toggleCameraStream(selectedPeer.id)"
[title]="isStreamingCameraToSelectedPeer() ? 'Stop webcam' : 'Start webcam'"
[attr.aria-label]="isStreamingCameraToSelectedPeer() ? 'Stop webcam' : 'Start webcam'"
>
{{ isStreamingCameraToSelectedPeer() ? '🛑' : '📹' }}
</button>
<button
class="composer-voice"
type="button"