Changing the way we focus a video element.
Now, only one video element can be important.
This commit is contained in:
parent
ac7fa164b6
commit
5cf5e0ce2b
@ -1,5 +1,6 @@
|
||||
<script lang="typescript">
|
||||
import {ScreenSharingLocalMedia} from "../../Stores/ScreenSharingStore";
|
||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
||||
|
||||
function srcObject(node, stream) {
|
||||
node.srcObject = stream;
|
||||
@ -18,6 +19,6 @@
|
||||
</script>
|
||||
|
||||
|
||||
<div class="video-container {cssClass}" class:hide={!stream}>
|
||||
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline on:click={() => peer.importanceStore.toggle()}></video>
|
||||
<div class="video-container {cssClass ? cssClass : ''}" class:hide={!stream}>
|
||||
<video use:srcObject={stream} autoplay muted playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {ScreenSharingPeer} from "../../WebRtc/ScreenSharingPeer";
|
||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
||||
|
||||
export let peer: ScreenSharingPeer;
|
||||
let streamStore = peer.streamStore;
|
||||
@ -45,7 +46,7 @@
|
||||
{#if $streamStore === null}
|
||||
<i style="background-color: {getColorByString(name)};">{name}</i>
|
||||
{/if}
|
||||
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => peer.importanceStore.toggle()}></video>
|
||||
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -5,13 +5,13 @@
|
||||
import reportImg from "./images/report.svg";
|
||||
import blockSignImg from "./images/blockSign.svg";
|
||||
import {DivImportance} from "../../WebRtc/LayoutManager";
|
||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
||||
|
||||
export let peer: VideoPeer;
|
||||
let streamStore = peer.streamStore;
|
||||
let name = peer.userName;
|
||||
let statusStore = peer.statusStore;
|
||||
let constraintStore = peer.constraintsStore;
|
||||
let importanceStore = peer.importanceStore;
|
||||
|
||||
constraintStore.subscribe((vl) => console.log('CONS', vl));
|
||||
|
||||
@ -62,17 +62,10 @@
|
||||
<img alt="Report this user" src={reportImg}>
|
||||
<span>Report/Block</span>
|
||||
</button>
|
||||
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => peer.importanceStore.toggle()}></video>
|
||||
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
|
||||
<img src={blockSignImg} class="block-logo" alt="Block">
|
||||
{#if $constraintStore && $constraintStore.audio !== false}
|
||||
<SoundMeterWidget stream={$streamStore}></SoundMeterWidget>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.video-container {
|
||||
video {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -3,18 +3,23 @@
|
||||
import {DivImportance} from "../../WebRtc/LayoutManager";
|
||||
import Peer from "./Peer.svelte";
|
||||
import {layoutStore} from "../../Stores/LayoutStore";
|
||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
||||
|
||||
</script>
|
||||
|
||||
<div class="video-overlay">
|
||||
<div class="main-section">
|
||||
{#each [...$layoutStore.get(DivImportance.Important).values()] as peer (peer.uniqueId)}
|
||||
<Peer peer={peer}></Peer>
|
||||
{#each [...$layoutStore.values()] as peer (peer.uniqueId)}
|
||||
{#if $videoFocusStore && peer === $videoFocusStore }
|
||||
<Peer peer={peer}></Peer>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
{#each [...$layoutStore.get(DivImportance.Normal).values()] as peer (peer.uniqueId)}
|
||||
<Peer peer={peer}></Peer>
|
||||
{#each [...$layoutStore.values()] as peer (peer.uniqueId)}
|
||||
{#if peer !== $videoFocusStore }
|
||||
<Peer peer={peer}></Peer>
|
||||
{/if}
|
||||
{/each}
|
||||
</aside>
|
||||
<div class="chat-mode three-col" style="display: none;">
|
||||
|
@ -95,6 +95,7 @@ import {DEPTH_OVERLAY_INDEX} from "./DepthIndexes";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
import {peerStore, screenSharingPeerStore} from "../../Stores/PeerStore";
|
||||
import {EmoteManager} from "./EmoteManager";
|
||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
||||
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface|null,
|
||||
@ -647,6 +648,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
||||
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.playerName);
|
||||
peerStore.connectToSimplePeer(this.simplePeer);
|
||||
screenSharingPeerStore.connectToSimplePeer(this.simplePeer);
|
||||
videoFocusStore.connectToSimplePeer(this.simplePeer);
|
||||
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
||||
userMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
|
||||
|
||||
|
@ -1,26 +0,0 @@
|
||||
import {VideoPeer} from "../WebRtc/VideoPeer";
|
||||
import {Subscriber, Unsubscriber, writable} from "svelte/store";
|
||||
import {RemotePeer, SimplePeer} from "../WebRtc/SimplePeer";
|
||||
import {DivImportance} from "../WebRtc/LayoutManager";
|
||||
|
||||
export interface ImportanceStore {
|
||||
subscribe: (this:void, run: Subscriber<DivImportance>, invalidate?: ((value?: DivImportance) => void | undefined)) => Unsubscriber,
|
||||
toggle: () => void,
|
||||
}
|
||||
|
||||
export function createImportanceStore(defaultImportance: DivImportance): ImportanceStore {
|
||||
const { subscribe, set, update } = writable<DivImportance>(defaultImportance);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
toggle: () => {
|
||||
update((importance) => {
|
||||
if (importance === DivImportance.Important) {
|
||||
return DivImportance.Normal;
|
||||
} else {
|
||||
return DivImportance.Important;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import {derived, get} from "svelte/store";
|
||||
import {derived, get, writable} from "svelte/store";
|
||||
import {ScreenSharingLocalMedia, screenSharingLocalMedia} from "./ScreenSharingStore";
|
||||
import {DivImportance} from "../WebRtc/LayoutManager";
|
||||
import { peerStore, screenSharingStreamStore} from "./PeerStore";
|
||||
import type {RemotePeer} from "../WebRtc/SimplePeer";
|
||||
|
||||
@ -27,26 +26,15 @@ function createLayoutStore() {
|
||||
}
|
||||
unsubscribes = [];
|
||||
|
||||
const peers = new Map<DivImportance, Map<string, DisplayableMedia>>();
|
||||
peers.set(DivImportance.Normal, new Map<string, DisplayableMedia>());
|
||||
peers.set(DivImportance.Important, new Map<string, DisplayableMedia>());
|
||||
const peers = new Map<string, DisplayableMedia>();
|
||||
|
||||
const addPeer = (peer: DisplayableMedia) => {
|
||||
const importance = get(peer.importanceStore);
|
||||
|
||||
peers.get(importance)?.set(peer.uniqueId, peer);
|
||||
|
||||
unsubscribes.push(peer.importanceStore.subscribe((importance) => {
|
||||
peers.forEach((category) => {
|
||||
category.delete(peer.uniqueId);
|
||||
});
|
||||
peers.get(importance)?.set(peer.uniqueId, peer);
|
||||
set(peers);
|
||||
}));
|
||||
peers.set(peer.uniqueId, peer);
|
||||
};
|
||||
|
||||
$screenSharingStreamStore.forEach(addPeer);
|
||||
$peerStore.forEach(addPeer);
|
||||
|
||||
if ($screenSharingLocalMedia?.stream) {
|
||||
addPeer($screenSharingLocalMedia);
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import type {
|
||||
} from "./MediaStore";
|
||||
import {DivImportance} from "../WebRtc/LayoutManager";
|
||||
import {gameOverlayVisibilityStore} from "./GameOverlayStoreVisibility";
|
||||
import {createImportanceStore, ImportanceStore} from "./ImportanceStore";
|
||||
|
||||
declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
@ -189,7 +188,6 @@ export const screenSharingAvailableStore = derived(peerStore, ($peerStore, set)
|
||||
|
||||
export interface ScreenSharingLocalMedia {
|
||||
uniqueId: string;
|
||||
importanceStore: ImportanceStore;
|
||||
stream: MediaStream|null;
|
||||
//subscribe(this: void, run: Subscriber<ScreenSharingLocalMedia>, invalidate?: (value?: ScreenSharingLocalMedia) => void): Unsubscriber;
|
||||
}
|
||||
@ -201,7 +199,6 @@ export const screenSharingLocalMedia = readable<ScreenSharingLocalMedia|null>(nu
|
||||
|
||||
const localMedia: ScreenSharingLocalMedia = {
|
||||
uniqueId: "localScreenSharingStream",
|
||||
importanceStore: createImportanceStore(DivImportance.Normal),
|
||||
stream: null
|
||||
}
|
||||
|
||||
|
48
front/src/Stores/VideoFocusStore.ts
Normal file
48
front/src/Stores/VideoFocusStore.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import {writable} from "svelte/store";
|
||||
import type {RemotePeer, SimplePeer} from "../WebRtc/SimplePeer";
|
||||
import {VideoPeer} from "../WebRtc/VideoPeer";
|
||||
import {ScreenSharingPeer} from "../WebRtc/ScreenSharingPeer";
|
||||
import type {DisplayableMedia} from "./LayoutStore";
|
||||
|
||||
/**
|
||||
* A store that contains the peer / media that has currently the "importance" focus.
|
||||
*/
|
||||
function createVideoFocusStore() {
|
||||
const { subscribe, set, update } = writable<DisplayableMedia | null>(null);
|
||||
|
||||
let focusedMedia: DisplayableMedia | null = null;
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
focus: (media: DisplayableMedia) => {
|
||||
focusedMedia = media;
|
||||
set(media);
|
||||
},
|
||||
removeFocus: () => {
|
||||
focusedMedia = null;
|
||||
set(null);
|
||||
},
|
||||
toggleFocus: (media: DisplayableMedia) => {
|
||||
if (media !== focusedMedia) {
|
||||
focusedMedia = media;
|
||||
} else {
|
||||
focusedMedia = null;
|
||||
}
|
||||
console.log('MEDIA', focusedMedia)
|
||||
set(focusedMedia);
|
||||
},
|
||||
connectToSimplePeer: (simplePeer: SimplePeer) => {
|
||||
simplePeer.registerPeerConnectionListener({
|
||||
onConnect(peer: RemotePeer) {
|
||||
},
|
||||
onDisconnect(userId: number) {
|
||||
if ((focusedMedia instanceof VideoPeer || focusedMedia instanceof ScreenSharingPeer) && focusedMedia.userId === userId) {
|
||||
set(null);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const videoFocusStore = createVideoFocusStore();
|
@ -5,9 +5,7 @@ import type {RoomConnection} from "../Connexion/RoomConnection";
|
||||
import {MESSAGE_TYPE_CONSTRAINT} from "./VideoPeer";
|
||||
import type {UserSimplePeerInterface} from "./SimplePeer";
|
||||
import {Readable, readable, writable, Writable} from "svelte/store";
|
||||
import {DivImportance} from "./LayoutManager";
|
||||
import type {ImportanceStore} from "../Stores/ImportanceStore";
|
||||
import {createImportanceStore} from "../Stores/ImportanceStore";
|
||||
import {videoFocusStore} from "../Stores/VideoFocusStore";
|
||||
|
||||
const Peer: SimplePeerNamespace.SimplePeer = require('simple-peer');
|
||||
|
||||
@ -24,7 +22,6 @@ export class ScreenSharingPeer extends Peer {
|
||||
public readonly userId: number;
|
||||
public readonly uniqueId: string;
|
||||
public readonly streamStore: Readable<MediaStream | null>;
|
||||
public readonly importanceStore: ImportanceStore;
|
||||
public readonly statusStore: Readable<"connecting" | "connected" | "error" | "closed">;
|
||||
|
||||
constructor(user: UserSimplePeerInterface, initiator: boolean, public readonly userName: string, private connection: RoomConnection, stream: MediaStream | null) {
|
||||
@ -50,6 +47,7 @@ export class ScreenSharingPeer extends Peer {
|
||||
|
||||
this.streamStore = readable<MediaStream|null>(null, (set) => {
|
||||
const onStream = (stream: MediaStream|null) => {
|
||||
videoFocusStore.focus(this);
|
||||
set(stream);
|
||||
};
|
||||
const onData = (chunk: Buffer) => {
|
||||
@ -73,8 +71,6 @@ export class ScreenSharingPeer extends Peer {
|
||||
};
|
||||
});
|
||||
|
||||
this.importanceStore = createImportanceStore(DivImportance.Important);
|
||||
|
||||
this.statusStore = readable<"connecting" | "connected" | "error" | "closed">("connecting", (set) => {
|
||||
const onConnect = () => {
|
||||
set('connected');
|
||||
|
@ -5,11 +5,9 @@ import type {RoomConnection} from "../Connexion/RoomConnection";
|
||||
import {blackListManager} from "./BlackListManager";
|
||||
import type {Subscription} from "rxjs";
|
||||
import type {UserSimplePeerInterface} from "./SimplePeer";
|
||||
import {get, readable, Readable, writable, Writable} from "svelte/store";
|
||||
import {get, readable, Readable} from "svelte/store";
|
||||
import {obtainedMediaConstraintStore} from "../Stores/MediaStore";
|
||||
import {DivImportance} from "./LayoutManager";
|
||||
import type {ImportanceStore} from "../Stores/ImportanceStore";
|
||||
import {createImportanceStore} from "../Stores/ImportanceStore";
|
||||
|
||||
const Peer: SimplePeerNamespace.SimplePeer = require('simple-peer');
|
||||
|
||||
@ -30,7 +28,6 @@ export class VideoPeer extends Peer {
|
||||
private onBlockSubscribe: Subscription;
|
||||
private onUnBlockSubscribe: Subscription;
|
||||
public readonly streamStore: Readable<MediaStream | null>;
|
||||
public readonly importanceStore: ImportanceStore;
|
||||
public readonly statusStore: Readable<"connecting" | "connected" | "error" | "closed">;
|
||||
public readonly constraintsStore: Readable<MediaStreamConstraints|null>;
|
||||
|
||||
@ -94,8 +91,6 @@ export class VideoPeer extends Peer {
|
||||
};
|
||||
});
|
||||
|
||||
this.importanceStore = createImportanceStore(DivImportance.Normal);
|
||||
|
||||
this.statusStore = readable<"connecting" | "connected" | "error" | "closed">("connecting", (set) => {
|
||||
const onConnect = () => {
|
||||
set('connected');
|
||||
|
@ -35,102 +35,108 @@ body .message-info.info{
|
||||
body .message-info.warning{
|
||||
background: #ffa500d6;
|
||||
}
|
||||
.video-container{
|
||||
|
||||
.video-container {
|
||||
position: relative;
|
||||
transition: all 0.2s ease;
|
||||
background-color: #00000099;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
}
|
||||
.video-container i{
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
left: calc(50% - 50px);
|
||||
top: calc(50% - 50px);
|
||||
background-color: black;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
padding-top: 32px;
|
||||
font-size: 28px;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-container img{
|
||||
position: absolute;
|
||||
display: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
padding: 10px;
|
||||
z-index: 2;
|
||||
}
|
||||
.video-container img.block-logo {
|
||||
left: 30%;
|
||||
bottom: 15%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
}
|
||||
|
||||
.video-container button.report{
|
||||
display: block;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
background: none;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border: none;
|
||||
background-color: black;
|
||||
border-radius: 15px;
|
||||
position: absolute;
|
||||
width: 0px;
|
||||
height: 35px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
padding: 0px;
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
transition: all .5s ease;
|
||||
}
|
||||
i {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
left: calc(50% - 50px);
|
||||
top: calc(50% - 50px);
|
||||
background-color: black;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
padding-top: 32px;
|
||||
font-size: 28px;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-container:hover button.report{
|
||||
width: 35px;
|
||||
padding: 10px;
|
||||
}
|
||||
img {
|
||||
position: absolute;
|
||||
display: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
padding: 10px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.video-container button.report:hover {
|
||||
width: 160px;
|
||||
}
|
||||
img.block-logo {
|
||||
left: 30%;
|
||||
bottom: 15%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.video-container button.report img{
|
||||
position: absolute;
|
||||
display: block;
|
||||
bottom: 5px;
|
||||
left: 5px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
.video-container button.report span{
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
left: 36px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
}
|
||||
.video-container img.active {
|
||||
display: block !important;
|
||||
}
|
||||
button.report{
|
||||
display: block;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
background: none;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border: none;
|
||||
background-color: black;
|
||||
border-radius: 15px;
|
||||
position: absolute;
|
||||
width: 0px;
|
||||
height: 35px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
padding: 0px;
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
transition: all .5s ease;
|
||||
|
||||
.video-container video{
|
||||
height: 100%;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
}
|
||||
img{
|
||||
position: absolute;
|
||||
display: block;
|
||||
bottom: 5px;
|
||||
left: 5px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.video-container video:focus{
|
||||
outline: none;
|
||||
span {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
left: 36px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
}
|
||||
|
||||
img.active {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover button.report{
|
||||
width: 35px;
|
||||
padding: 10px;
|
||||
|
||||
&:hover {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
video:focus{
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.video-container.div-myCamVideo{
|
||||
|
Loading…
Reference in New Issue
Block a user