Many features
This commit is contained in:
@@ -7,6 +7,36 @@
|
||||
[title]="(peer()?.displayName ?? 'Peer') + ' webcam'"
|
||||
(closeRequested)="closeRemoteVideoModal()"
|
||||
></app-peer-video-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
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
type="button"
|
||||
(click)="rejectIncomingVoiceCall(callingPeer.id)"
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="chat-header d-flex flex-column flex-lg-row justify-content-between align-items-start align-items-lg-center gap-3 mb-4">
|
||||
<div>
|
||||
@@ -49,7 +79,11 @@
|
||||
}
|
||||
|
||||
@for (connectedPeer of session.peers(); track connectedPeer.id) {
|
||||
<article class="peer-tile" [class.peer-tile-active]="connectedPeer.id === peerId()">
|
||||
<article
|
||||
class="peer-tile"
|
||||
[class.peer-tile-active]="connectedPeer.id === peerId()"
|
||||
[class.peer-tile-unread]="isPeerUnread(connectedPeer.id)"
|
||||
>
|
||||
<button
|
||||
class="peer-tile-main text-start"
|
||||
type="button"
|
||||
@@ -189,6 +223,19 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@case ('voice') {
|
||||
<div class="voice-bubble">
|
||||
<div class="voice-bubble-label">Voice message</div>
|
||||
@if (entry.downloadUrl) {
|
||||
<audio
|
||||
class="voice-player"
|
||||
[src]="entry.downloadUrl"
|
||||
controls
|
||||
preload="metadata"
|
||||
></audio>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@default {
|
||||
@if (entry.showSpinner) {
|
||||
<div class="bubble-system-status">
|
||||
@@ -205,39 +252,6 @@
|
||||
</div>
|
||||
|
||||
<div class="composer">
|
||||
@if (peer(); as selectedPeer) {
|
||||
<div class="composer-actions">
|
||||
<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>
|
||||
|
||||
<input
|
||||
#fileInput
|
||||
class="composer-file-input"
|
||||
type="file"
|
||||
[disabled]="selectedPeer.channelState !== 'open'"
|
||||
(change)="sendFile(selectedPeer.id, fileInput)"
|
||||
/>
|
||||
<button
|
||||
class="composer-plus"
|
||||
type="button"
|
||||
[disabled]="selectedPeer.channelState !== 'open'"
|
||||
(click)="fileInput.click()"
|
||||
title="Send file"
|
||||
aria-label="Send file"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
<textarea
|
||||
#composerTextarea
|
||||
class="form-control composer-textarea"
|
||||
@@ -252,7 +266,73 @@
|
||||
placeholder="Write a text message to your peer"
|
||||
></textarea>
|
||||
|
||||
<div class="composer-send">
|
||||
<div class="composer-toolbar">
|
||||
@if (peer(); as selectedPeer) {
|
||||
<button
|
||||
class="composer-call"
|
||||
type="button"
|
||||
[disabled]="!canStartSelectedVoiceCall()"
|
||||
(click)="startVoiceCall(selectedPeer.id)"
|
||||
title="Start voice call"
|
||||
aria-label="Start voice call"
|
||||
>
|
||||
📞
|
||||
</button>
|
||||
|
||||
@if (canEndSelectedVoiceCall()) {
|
||||
<button
|
||||
class="composer-hangup"
|
||||
type="button"
|
||||
(click)="endVoiceCall(selectedPeer.id)"
|
||||
title="End voice call"
|
||||
aria-label="End voice 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"
|
||||
[disabled]="selectedPeer.channelState !== 'open' && !isRecordingVoice()"
|
||||
(click)="toggleVoiceRecording()"
|
||||
[title]="isRecordingVoice() ? 'Stop and send voice message' : 'Record voice message'"
|
||||
[attr.aria-label]="isRecordingVoice() ? 'Stop and send voice message' : 'Record voice message'"
|
||||
[class.composer-voice-recording]="isRecordingVoice()"
|
||||
>
|
||||
{{ isRecordingVoice() ? '⏹️' : '🎙️' }}
|
||||
</button>
|
||||
|
||||
<input
|
||||
#fileInput
|
||||
class="composer-file-input"
|
||||
type="file"
|
||||
[disabled]="selectedPeer.channelState !== 'open'"
|
||||
(change)="sendFile(selectedPeer.id, fileInput)"
|
||||
/>
|
||||
<button
|
||||
class="composer-plus"
|
||||
type="button"
|
||||
[disabled]="selectedPeer.channelState !== 'open'"
|
||||
(click)="fileInput.click()"
|
||||
title="Send file"
|
||||
aria-label="Send file"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
}
|
||||
|
||||
<button
|
||||
class="composer-image-generate"
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user