2021-05-10 21:48:11 +02:00
|
|
|
import { HtmlUtils } from "./HtmlUtils";
|
2021-05-18 15:18:35 +02:00
|
|
|
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
|
2021-06-25 18:14:40 +02:00
|
|
|
import { localStreamStore } from "../Stores/MediaStore";
|
|
|
|
import { screenSharingLocalStreamStore } from "../Stores/ScreenSharingStore";
|
|
|
|
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore";
|
2021-05-05 01:49:04 +02:00
|
|
|
|
2020-08-31 15:21:05 +02:00
|
|
|
export type StartScreenSharingCallback = (media: MediaStream) => void;
|
|
|
|
export type StopScreenSharingCallback = (media: MediaStream) => void;
|
2020-06-23 14:56:57 +02:00
|
|
|
|
2021-06-25 18:14:40 +02:00
|
|
|
import { cowebsiteCloseButtonId } from "./CoWebsiteManager";
|
|
|
|
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
|
2022-01-21 17:06:03 +01:00
|
|
|
import { layoutManagerActionStore } from "../Stores/LayoutManagerStore";
|
2021-09-05 19:36:57 +02:00
|
|
|
import { MediaStreamConstraintsError } from "../Stores/Errors/MediaStreamConstraintsError";
|
2022-01-21 17:06:03 +01:00
|
|
|
import { localUserStore } from "../Connexion/LocalUserStore";
|
|
|
|
import LL from "../i18n/i18n-svelte";
|
|
|
|
import { get } from "svelte/store";
|
|
|
|
import { localeDetector } from "../i18n/locales";
|
2021-06-03 20:15:50 +02:00
|
|
|
|
2020-06-23 12:24:36 +02:00
|
|
|
export class MediaManager {
|
2021-06-25 18:14:40 +02:00
|
|
|
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
|
|
|
stopScreenSharingCallBacks: Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
|
2021-05-11 10:56:50 +02:00
|
|
|
|
2021-05-10 21:48:11 +02:00
|
|
|
private triggerCloseJistiFrame: Map<String, Function> = new Map<String, Function>();
|
2020-11-17 18:03:44 +01:00
|
|
|
|
2021-05-05 01:49:04 +02:00
|
|
|
private userInputManager?: UserInputManager;
|
|
|
|
|
2020-08-18 00:12:38 +02:00
|
|
|
constructor() {
|
2022-01-21 17:06:03 +01:00
|
|
|
localeDetector()
|
|
|
|
.catch(() => {
|
|
|
|
throw new Error("Cannot load locale on media manager");
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
localStreamStore.subscribe((result) => {
|
|
|
|
if (result.type === "error") {
|
|
|
|
if (result.error.name !== MediaStreamConstraintsError.NAME) {
|
|
|
|
layoutManagerActionStore.addAction({
|
|
|
|
uuid: "cameraAccessDenied",
|
|
|
|
type: "warning",
|
|
|
|
message: get(LL).warning.accessDenied.camera(),
|
|
|
|
callback: () => {
|
|
|
|
helpCameraSettingsVisibleStore.set(true);
|
|
|
|
},
|
|
|
|
userInputManager: this.userInputManager,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
//remove it after 10 sec
|
|
|
|
setTimeout(() => {
|
|
|
|
layoutManagerActionStore.removeAction("cameraAccessDenied");
|
|
|
|
}, 10000);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
});
|
2021-05-20 18:05:03 +02:00
|
|
|
|
2022-01-21 17:06:03 +01:00
|
|
|
screenSharingLocalStreamStore.subscribe((result) => {
|
|
|
|
if (result.type === "error") {
|
|
|
|
console.error(result.error);
|
|
|
|
layoutManagerActionStore.addAction({
|
|
|
|
uuid: "screenSharingAccessDenied",
|
|
|
|
type: "warning",
|
|
|
|
message: get(LL).warning.accessDenied.screenSharing(),
|
|
|
|
callback: () => {
|
|
|
|
helpCameraSettingsVisibleStore.set(true);
|
|
|
|
},
|
|
|
|
userInputManager: this.userInputManager,
|
|
|
|
});
|
|
|
|
//remove it after 10 sec
|
|
|
|
setTimeout(() => {
|
|
|
|
layoutManagerActionStore.removeAction("screenSharingAccessDenied");
|
|
|
|
}, 10000);
|
|
|
|
return;
|
|
|
|
}
|
2021-08-03 11:13:08 +02:00
|
|
|
});
|
2022-01-21 17:06:03 +01:00
|
|
|
});
|
2020-04-26 20:55:20 +02:00
|
|
|
}
|
2020-04-19 19:32:38 +02:00
|
|
|
|
2021-05-11 14:52:51 +02:00
|
|
|
public showGameOverlay(): void {
|
2021-06-25 18:14:40 +02:00
|
|
|
const gameOverlay = HtmlUtils.getElementByIdOrFail("game-overlay");
|
|
|
|
gameOverlay.classList.add("active");
|
2020-11-17 18:03:44 +01:00
|
|
|
|
2021-06-03 20:05:39 +02:00
|
|
|
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
2020-11-17 18:03:44 +01:00
|
|
|
const functionTrigger = () => {
|
|
|
|
this.triggerCloseJitsiFrameButton();
|
2021-06-25 18:14:40 +02:00
|
|
|
};
|
|
|
|
buttonCloseFrame.removeEventListener("click", () => {
|
2021-06-03 20:05:39 +02:00
|
|
|
buttonCloseFrame.blur();
|
|
|
|
functionTrigger();
|
|
|
|
});
|
2021-05-18 16:38:56 +02:00
|
|
|
|
|
|
|
gameOverlayVisibilityStore.showGameOverlay();
|
2020-04-19 19:32:38 +02:00
|
|
|
}
|
|
|
|
|
2021-05-11 14:52:51 +02:00
|
|
|
public hideGameOverlay(): void {
|
2021-06-25 18:14:40 +02:00
|
|
|
const gameOverlay = HtmlUtils.getElementByIdOrFail("game-overlay");
|
|
|
|
gameOverlay.classList.remove("active");
|
2020-11-17 18:03:44 +01:00
|
|
|
|
2021-06-03 20:05:39 +02:00
|
|
|
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
2020-11-17 18:03:44 +01:00
|
|
|
const functionTrigger = () => {
|
|
|
|
this.triggerCloseJitsiFrameButton();
|
2021-06-25 18:14:40 +02:00
|
|
|
};
|
|
|
|
buttonCloseFrame.addEventListener("click", () => {
|
2021-06-03 20:05:39 +02:00
|
|
|
buttonCloseFrame.blur();
|
|
|
|
functionTrigger();
|
|
|
|
});
|
2021-05-18 16:38:56 +02:00
|
|
|
|
|
|
|
gameOverlayVisibilityStore.hideGameOverlay();
|
2020-09-01 14:43:21 +02:00
|
|
|
}
|
|
|
|
|
2021-02-02 18:19:51 +01:00
|
|
|
private getScreenSharingId(userId: string): string {
|
|
|
|
return `screen-sharing-${userId}`;
|
|
|
|
}
|
|
|
|
|
2021-05-10 21:48:11 +02:00
|
|
|
disabledMicrophoneByUserId(userId: number) {
|
2020-06-09 23:13:26 +02:00
|
|
|
const element = document.getElementById(`microphone-${userId}`);
|
2021-05-10 21:48:11 +02:00
|
|
|
if (!element) {
|
2020-05-14 20:39:30 +02:00
|
|
|
return;
|
|
|
|
}
|
2021-06-25 18:14:40 +02:00
|
|
|
element.classList.add("active"); //todo: why does a method 'disable' add a class 'active'?
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
2021-05-11 10:56:50 +02:00
|
|
|
|
2021-05-10 21:48:11 +02:00
|
|
|
enabledMicrophoneByUserId(userId: number) {
|
2020-06-09 23:13:26 +02:00
|
|
|
const element = document.getElementById(`microphone-${userId}`);
|
2021-05-10 21:48:11 +02:00
|
|
|
if (!element) {
|
2020-05-14 20:39:30 +02:00
|
|
|
return;
|
|
|
|
}
|
2021-06-25 18:14:40 +02:00
|
|
|
element.classList.remove("active"); //todo: why does a method 'enable' remove a class 'active'?
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
2021-05-11 10:56:50 +02:00
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
disabledVideoByUserId(userId: number) {
|
2020-05-14 20:39:30 +02:00
|
|
|
let element = document.getElementById(`${userId}`);
|
2020-05-14 20:54:34 +02:00
|
|
|
if (element) {
|
|
|
|
element.style.opacity = "0";
|
|
|
|
}
|
2020-08-16 23:19:04 +02:00
|
|
|
element = document.getElementById(`name-${userId}`);
|
|
|
|
if (element) {
|
|
|
|
element.style.display = "block";
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-11 10:56:50 +02:00
|
|
|
|
2021-05-10 21:48:11 +02:00
|
|
|
enabledVideoByUserId(userId: number) {
|
2020-05-14 20:39:30 +02:00
|
|
|
let element = document.getElementById(`${userId}`);
|
2021-05-10 21:48:11 +02:00
|
|
|
if (element) {
|
2020-05-14 20:54:34 +02:00
|
|
|
element.style.opacity = "1";
|
|
|
|
}
|
2020-08-16 23:19:04 +02:00
|
|
|
element = document.getElementById(`name-${userId}`);
|
2021-05-10 21:48:11 +02:00
|
|
|
if (element) {
|
2020-08-16 23:19:04 +02:00
|
|
|
element.style.display = "none";
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-02 18:19:51 +01:00
|
|
|
toggleBlockLogo(userId: number, show: boolean): void {
|
2021-06-25 18:14:40 +02:00
|
|
|
const blockLogoElement = HtmlUtils.getElementByIdOrFail<HTMLImageElement>("blocking-" + userId);
|
|
|
|
show ? blockLogoElement.classList.add("active") : blockLogoElement.classList.remove("active");
|
2020-06-06 22:49:55 +02:00
|
|
|
}
|
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
isError(userId: string): void {
|
2020-11-27 16:24:07 +01:00
|
|
|
console.info("isError", `div-${userId}`);
|
2020-06-09 23:13:26 +02:00
|
|
|
const element = document.getElementById(`div-${userId}`);
|
2021-05-10 21:48:11 +02:00
|
|
|
if (!element) {
|
2020-06-06 22:49:55 +02:00
|
|
|
return;
|
|
|
|
}
|
2021-06-25 18:14:40 +02:00
|
|
|
const errorDiv = element.getElementsByClassName("rtc-error").item(0) as HTMLDivElement | null;
|
2020-06-06 22:49:55 +02:00
|
|
|
if (errorDiv === null) {
|
|
|
|
return;
|
|
|
|
}
|
2021-06-25 18:14:40 +02:00
|
|
|
errorDiv.style.display = "block";
|
2020-06-06 22:49:55 +02:00
|
|
|
}
|
2020-09-18 13:57:38 +02:00
|
|
|
isErrorScreenSharing(userId: string): void {
|
2021-02-02 18:19:51 +01:00
|
|
|
this.isError(this.getScreenSharingId(userId));
|
2020-06-14 14:47:16 +02:00
|
|
|
}
|
|
|
|
|
2021-05-10 21:48:11 +02:00
|
|
|
private getSpinner(userId: string): HTMLDivElement | null {
|
2020-06-09 23:13:26 +02:00
|
|
|
const element = document.getElementById(`div-${userId}`);
|
2021-05-10 21:48:11 +02:00
|
|
|
if (!element) {
|
2020-06-06 22:49:55 +02:00
|
|
|
return null;
|
|
|
|
}
|
2021-06-25 18:14:40 +02:00
|
|
|
const connectingSpinnerDiv = element
|
|
|
|
.getElementsByClassName("connecting-spinner")
|
|
|
|
.item(0) as HTMLDivElement | null;
|
2021-06-17 18:48:56 +02:00
|
|
|
return connectingSpinnerDiv;
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
2020-06-03 11:55:31 +02:00
|
|
|
|
2021-06-25 18:14:40 +02:00
|
|
|
public addTriggerCloseJitsiFrameButton(id: String, Function: Function) {
|
2020-11-17 18:03:44 +01:00
|
|
|
this.triggerCloseJistiFrame.set(id, Function);
|
|
|
|
}
|
|
|
|
|
2021-05-10 21:48:11 +02:00
|
|
|
public removeTriggerCloseJitsiFrameButton(id: String) {
|
2020-11-17 18:03:44 +01:00
|
|
|
this.triggerCloseJistiFrame.delete(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
private triggerCloseJitsiFrameButton(): void {
|
|
|
|
for (const callback of this.triggerCloseJistiFrame.values()) {
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
}
|
2020-10-13 19:56:42 +02:00
|
|
|
|
2021-06-25 18:14:40 +02:00
|
|
|
public setUserInputManager(userInputManager: UserInputManager) {
|
2021-05-05 01:49:04 +02:00
|
|
|
this.userInputManager = userInputManager;
|
2020-11-10 12:38:32 +01:00
|
|
|
}
|
2021-01-29 21:09:10 +01:00
|
|
|
|
2021-07-13 11:06:37 +02:00
|
|
|
public hasNotification(): boolean {
|
2021-08-26 12:01:07 +02:00
|
|
|
if (Notification.permission === "granted") {
|
|
|
|
return localUserStore.getNotification() === "granted";
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2021-05-07 01:37:05 +02:00
|
|
|
}
|
|
|
|
|
2021-07-13 11:06:37 +02:00
|
|
|
public requestNotification() {
|
|
|
|
if (window.Notification && Notification.permission !== "granted") {
|
|
|
|
return Notification.requestPermission();
|
|
|
|
} else {
|
|
|
|
return Promise.reject();
|
2021-06-03 10:17:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-25 18:14:40 +02:00
|
|
|
public createNotification(userName: string) {
|
2021-07-13 11:06:37 +02:00
|
|
|
if (document.hasFocus()) {
|
2021-05-07 01:37:05 +02:00
|
|
|
return;
|
|
|
|
}
|
2021-07-13 11:06:37 +02:00
|
|
|
|
|
|
|
if (this.hasNotification()) {
|
|
|
|
const title = `${userName} wants to discuss with you`;
|
2021-05-07 01:37:05 +02:00
|
|
|
const options = {
|
2021-06-25 18:14:40 +02:00
|
|
|
icon: "/resources/logos/logo-WA-min.png",
|
|
|
|
image: "/resources/logos/logo-WA-min.png",
|
|
|
|
badge: "/resources/logos/logo-WA-min.png",
|
2021-05-07 01:37:05 +02:00
|
|
|
};
|
|
|
|
new Notification(title, options);
|
|
|
|
}
|
|
|
|
}
|
2020-06-03 11:55:31 +02:00
|
|
|
}
|
2020-06-23 14:56:57 +02:00
|
|
|
|
|
|
|
export const mediaManager = new MediaManager();
|