diff --git a/src/lib/components/calling/CallScreen.svelte b/src/lib/components/calling/CallScreen.svelte
index e93467724..2cc87f2fe 100644
--- a/src/lib/components/calling/CallScreen.svelte
+++ b/src/lib/components/calling/CallScreen.svelte
@@ -13,11 +13,24 @@
import type { Chat } from "$lib/types"
import VolumeMixer from "./VolumeMixer.svelte"
import { createEventDispatcher, onDestroy, onMount } from "svelte"
- import { callInProgress, callScreenVisible, callTimeout, makeCallSound, TIME_TO_SHOW_CONNECTING, TIME_TO_SHOW_END_CALL_FEEDBACK, timeCallStarted, usersAcceptedTheCall, usersDeniedTheCall, VoiceRTCInstance } from "$lib/media/Voice"
+ import {
+ callInProgress,
+ callScreenVisible,
+ callTimeout,
+ makeCallSound,
+ showCallPopUp,
+ TIME_TO_SHOW_CONNECTING,
+ TIME_TO_SHOW_END_CALL_FEEDBACK,
+ timeCallStarted,
+ usersAcceptedTheCall,
+ usersDeniedTheCall,
+ VoiceRTCInstance,
+ } from "$lib/media/Voice"
import { log } from "$lib/utils/Logger"
import { playSound, Sounds } from "../utils/SoundHandler"
import { MultipassStoreInstance } from "$lib/wasm/MultipassStore"
import { debounce } from "$lib/utils/Functions"
+ import LiveLabel from "./LiveLabel.svelte"
const MIN_USER_SIZE = 250
export let expanded: boolean = false
@@ -196,6 +209,7 @@
onMount(async () => {
callScreenVisible.set(true)
+ showCallPopUp.set(false)
if ($makeCallSound) {
stopMakeCallSound()
}
@@ -269,6 +283,12 @@
if (get(Store.state.activeCall) === null && get(Store.state.devices.screenShare) === true) {
Store.state.devices.screenShare.set(false)
}
+
+ if ($callInProgress !== null) {
+ showCallPopUp.set(true)
+ } else {
+ showCallPopUp.set(false)
+ }
})
function updateUserListSplit() {
@@ -494,12 +514,7 @@
{$userCache[user].name}
- {#if $remoteStreams[user].user.screenShareEnabled}
-
@@ -813,28 +828,6 @@
z-index: 1;
}
- .live-label {
- position: absolute;
- top: 8px;
- left: 12px;
- display: inline-flex;
- align-items: center;
- background-color: rgba(0, 0, 0, 0.6);
- color: white;
- padding: 4px 8px;
- border-radius: 8px;
- font-size: 14px;
- z-index: 1;
- }
-
- .red-dot {
- width: 6px;
- height: 6px;
- background-color: red;
- border-radius: 50%;
- margin-right: 8px;
- }
-
.mute-status {
position: absolute;
display: flex;
diff --git a/src/lib/components/calling/LiveLabel.svelte b/src/lib/components/calling/LiveLabel.svelte
new file mode 100644
index 000000000..2ea0f3d91
--- /dev/null
+++ b/src/lib/components/calling/LiveLabel.svelte
@@ -0,0 +1,36 @@
+
+
+{#if screenShareEnabled}
+
+
+ {$_("settings.calling.live")}
+
+{/if}
+
+
diff --git a/src/lib/components/calling/VideoPreview.svelte b/src/lib/components/calling/VideoPreview.svelte
index 00af59c5c..ca2f6fcbd 100644
--- a/src/lib/components/calling/VideoPreview.svelte
+++ b/src/lib/components/calling/VideoPreview.svelte
@@ -1,54 +1,92 @@
-
+
@@ -138,6 +209,7 @@
overflow: hidden;
pointer-events: none;
}
+
#video-preview {
position: fixed;
top: 0;
@@ -156,7 +228,7 @@
height: 225px;
background: var(--background-alt);
border-radius: var(--border-radius);
- border: var(--border-width) solid var(--border-color);
+ border: var(--border-width) solid var(--color-muted);
position: absolute;
top: 0;
right: 0;
@@ -164,10 +236,127 @@
pointer-events: all;
transition: transform 0.3s ease;
margin: var(--padding);
- display: inline-flex;
+ display: flex;
+ flex-direction: column;
justify-content: center;
+ align-items: center;
+ padding: var(--padding);
+ box-sizing: border-box;
overflow: hidden;
align-items: center;
+
+ .users-in-call {
+ position: absolute;
+ display: flex;
+ gap: 4px;
+ bottom: 8px;
+ right: 12px;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(14, 13, 13, 0.5);
+ color: white;
+ padding: 4px 8px;
+ border-radius: 8px;
+ font-size: 14px;
+ z-index: 1;
+ }
+
+ .video-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+ justify-content: center;
+ align-items: center;
+ justify-items: center;
+ gap: 10px;
+ width: 100%;
+ height: 100%;
+ }
+
+ .video-container {
+ position: relative;
+ display: inline-block;
+ border-radius: 12px;
+ overflow: hidden;
+ border: 2px solid var(--color-muted);
+ cursor: pointer;
+ &.talking {
+ border: 2px solid var(--success-color);
+ }
+ width: 100%;
+ height: 100%;
+ aspect-ratio: 4 / 3;
+
+ .user-name {
+ position: absolute;
+ bottom: 8px;
+ left: 12px;
+ background-color: rgba(0, 0, 0, 0.6);
+ color: white;
+ padding: 4px 8px;
+ border-radius: 8px;
+ font-size: 14px;
+ z-index: 1;
+ }
+
+ .mute-status {
+ position: absolute;
+ display: flex;
+ bottom: 8px;
+ right: 12px;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(0, 0, 0, 0.6);
+ color: white;
+ padding: 4px 8px;
+ border-radius: 8px;
+ font-size: 14px;
+ z-index: 1;
+ }
+
+ video {
+ object-fit: cover;
+ border-radius: 12px;
+ background-color: var(--black);
+ width: 100%;
+ height: 100%;
+
+ &.disabled {
+ width: 0;
+ height: 0;
+ }
+ }
+ }
}
}
+
+ .spinner {
+ width: 48px;
+ height: 48px;
+ border: 8px solid #f3f3f3;
+ border-top: 8px solid #3498db;
+ border-radius: 50%;
+ animation: spin 2s linear infinite;
+ }
+
+ @keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+ }
+
+ .loading-when-no-answer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ text-align: center;
+ margin: 32px;
+ }
+
+ .loading-when-no-answer p {
+ margin-top: 16px;
+ }
diff --git a/src/lib/lang/en.json b/src/lib/lang/en.json
index ce8c4f671..f99a4c769 100644
--- a/src/lib/lang/en.json
+++ b/src/lib/lang/en.json
@@ -379,6 +379,7 @@
"hasCancelled": "Has cancelled the call.",
"disconnecting": "Disconnecting...",
"userInviteToAGroupCall": "{user} has started a group call in {group}",
+ "waitingOthersToJoin": "Waiting for others to join...",
"noAnswer": "No answer, leaving the call...",
"everybodyDeniedTheCall": "Everybody Denied the call. Disconnecting...",
"acceptedCall": "Joined, loading...",
diff --git a/src/lib/media/Voice.ts b/src/lib/media/Voice.ts
index 600285271..0a1bd7c64 100644
--- a/src/lib/media/Voice.ts
+++ b/src/lib/media/Voice.ts
@@ -28,6 +28,8 @@ export const timeCallStarted: Writable = writable(null)
export const callInProgress: Writable = writable(null)
export const makeCallSound = writable(undefined)
export const callScreenVisible = writable(false)
+export const usersDidInActiveCall = writable([])
+export const showCallPopUp = writable(false)
const relaysToTest = [
"wss://nostr-pub.wellorder.net",
@@ -158,6 +160,7 @@ async function handleStreamMeta(did: string, stream: MediaStream): Promise("did_sync")
did_rv((did, peer) => {
+ if (!get(usersDidInActiveCall).includes(did)) {
+ usersDidInActiveCall.update(u => [...u, did])
+ }
this.participants[did] = new Participant(did, peer)
})
room.onPeerJoin(async peer => {
@@ -253,13 +259,14 @@ export class CallRoom {
this.start = new Date()
}
})
- room.onPeerTrack((stream, peer, _meta) => {
+ room.onPeerTrack((_, peer, _meta) => {
log.debug(`Receiving track from ${peer}`)
})
room.onPeerLeave(peer => {
log.debug(`Peer ${peer} left the room`)
let participant = Object.entries(this.participants).find(p => p[1].remotePeerId === peer)
if (participant) {
+ usersDidInActiveCall.update(u => u.filter(did => did !== participant[0]))
VoiceRTCInstance.remoteVideoCreator.delete(participant[0])
delete this.participants[participant[0]]
}
@@ -276,8 +283,6 @@ export class CallRoom {
participant[1].handleRemoteStream(stream)
}
})
- room.onPeerTrack((stream, peer, _meta) => {})
- // room.onPeerTrack((stream, peer, meta) => {})
}
toggleStreams(state: boolean, type: ToggleType) {
@@ -809,9 +814,9 @@ export class VoiceRTC {
}
async leaveCall(sendEndCallMessage = false) {
- callScreenVisible.set(false)
callInProgress.set(null)
timeCallStarted.set(null)
+ showCallPopUp.set(false)
usersDeniedTheCall.set([])
callTimeout.set(false)
connectionOpened.set(false)
@@ -834,6 +839,7 @@ export class VoiceRTC {
if (get(Store.state.activeCall)) {
Store.endCall()
}
+ callScreenVisible.set(false)
if (get(Store.state.pendingCall)) {
Store.denyCall()
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 652eb5af8..327a34af6 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -290,7 +290,7 @@
-
+
UIStore.toggleMarket()} />