Merge pull request #380 from thecodingmachine/jitsiQOL
opening and closing jitsi windows now trigger some transitions
This commit is contained in:
commit
dfd2b2048c
22
front/dist/index.html
vendored
22
front/dist/index.html
vendored
@ -42,30 +42,14 @@
|
|||||||
<body id="body" style="margin: 0">
|
<body id="body" style="margin: 0">
|
||||||
<div class="main-container" id="main-container">
|
<div class="main-container" id="main-container">
|
||||||
<!-- Create the editor container -->
|
<!-- Create the editor container -->
|
||||||
<div id="game" class="game" style="/*background: red;*/">
|
<div id="game" class="game">
|
||||||
<div id="game-overlay" class="game-overlay" style="/*background: violet*/;">
|
<div id="game-overlay" class="game-overlay">
|
||||||
<div id="main-section" class="main-section">
|
<div id="main-section" class="main-section">
|
||||||
<!--<div style="background: lightpink;">a</div>
|
|
||||||
<div style="background: lightpink;">a</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<aside id="sidebar" class="sidebar">
|
<aside id="sidebar" class="sidebar">
|
||||||
<!--<div style="background: lightgreen;">a</div>
|
|
||||||
<div style="background: green;">b</div>
|
|
||||||
<div style="background: darkgreen;">c</div>
|
|
||||||
<div style="background: darkgreen;">d</div>-->
|
|
||||||
</aside>
|
</aside>
|
||||||
<div id="chat-mode" class="chat-mode three-col" style="display: none;">
|
<div id="chat-mode" class="chat-mode three-col" style="display: none;">
|
||||||
<!--<div style="background: lightgreen;">a</div>
|
|
||||||
<div style="background: green;">b</div>
|
|
||||||
<div style="background: darkgreen;">c</div>
|
|
||||||
<div style="background: darkolivegreen;">d</div>
|
|
||||||
<div style="background: darkolivegreen;">d</div>
|
|
||||||
<div style="background: darkgreen;">c</div>
|
|
||||||
<div style="background: green;">b</div>
|
|
||||||
<div style="background: lightgreen;">last elem for game</div>-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div id="activeCam" class="activeCam">
|
<div id="activeCam" class="activeCam">
|
||||||
<div id="div-myCamVideo" class="video-container">
|
<div id="div-myCamVideo" class="video-container">
|
||||||
<video id="myCamVideo" autoplay muted></video>
|
<video id="myCamVideo" autoplay muted></video>
|
||||||
@ -88,7 +72,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="cowebsite" class="cowebsite"></div>
|
<div id="cowebsite" class="cowebsite hidden"></div>
|
||||||
<div class="audio-playing">
|
<div class="audio-playing">
|
||||||
<img src="/resources/logos/megaphone.svg"/>
|
<img src="/resources/logos/megaphone.svg"/>
|
||||||
</div>
|
</div>
|
||||||
|
56
front/dist/resources/style/style.css
vendored
56
front/dist/resources/style/style.css
vendored
@ -242,15 +242,10 @@ body {
|
|||||||
.main-container {
|
.main-container {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
display: flex;
|
position: absolute;
|
||||||
align-items: stretch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-aspect-ratio: 1/1) {
|
@media (min-aspect-ratio: 1/1) {
|
||||||
.main-container {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-overlay {
|
.game-overlay {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
@ -266,12 +261,21 @@ body {
|
|||||||
.sidebar > div:hover {
|
.sidebar > div:hover {
|
||||||
max-height: 25%;
|
max-height: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cowebsite {
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 50%;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
#cowebsite.loading {
|
||||||
|
transform: translateX(90%);
|
||||||
|
}
|
||||||
|
#cowebsite.hidden {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media (max-aspect-ratio: 1/1) {
|
@media (max-aspect-ratio: 1/1) {
|
||||||
.main-container {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-overlay {
|
.game-overlay {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@ -288,24 +292,36 @@ body {
|
|||||||
.sidebar > div:hover {
|
.sidebar > div:hover {
|
||||||
max-width: 25%;
|
max-width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cowebsite {
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
#cowebsite.loading {
|
||||||
|
transform: translateY(90%);
|
||||||
|
}
|
||||||
|
#cowebsite.hidden {
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.game {
|
#game {
|
||||||
flex-basis: 100%;
|
width: 100%;
|
||||||
position: relative; /* Position relative is needed for the game-overlay. */
|
position: relative; /* Position relative is needed for the game-overlay. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A potentially shared website could appear in an iframe in the cowebsite space. */
|
/* A potentially shared website could appear in an iframe in the cowebsite space. */
|
||||||
.cowebsite {
|
#cowebsite {
|
||||||
flex-basis: 100%;
|
position: fixed;
|
||||||
transition: flex-basis 0.5s;
|
transition: transform 0.5s;
|
||||||
|
}
|
||||||
|
#cowebsite.loading {
|
||||||
|
background-color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*.cowebsite:hover {
|
#cowebsite > iframe {
|
||||||
flex-basis: 100%;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
.cowebsite > iframe {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ import CanvasTexture = Phaser.Textures.CanvasTexture;
|
|||||||
import GameObject = Phaser.GameObjects.GameObject;
|
import GameObject = Phaser.GameObjects.GameObject;
|
||||||
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
||||||
import {GameMap} from "./GameMap";
|
import {GameMap} from "./GameMap";
|
||||||
import {CoWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
||||||
import {mediaManager} from "../../WebRtc/MediaManager";
|
import {mediaManager} from "../../WebRtc/MediaManager";
|
||||||
import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
|
import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
|
||||||
import {ItemFactoryInterface} from "../Items/ItemFactoryInterface";
|
import {ItemFactoryInterface} from "../Items/ItemFactoryInterface";
|
||||||
@ -292,13 +292,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST: let's load a module dynamically!
|
|
||||||
/*let foo = "http://maps.workadventure.localhost/computer.js";
|
|
||||||
import(/* webpackIgnore: true * / foo).then(result => {
|
|
||||||
console.log(result);
|
|
||||||
|
|
||||||
});*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//hook initialisation
|
//hook initialisation
|
||||||
@ -476,9 +469,9 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
|
|
||||||
this.gameMap.onPropertyChange('openWebsite', (newValue, oldValue) => {
|
this.gameMap.onPropertyChange('openWebsite', (newValue, oldValue) => {
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
CoWebsiteManager.closeCoWebsite();
|
coWebsiteManager.closeCoWebsite();
|
||||||
} else {
|
} else {
|
||||||
CoWebsiteManager.loadCoWebsite(newValue as string);
|
coWebsiteManager.loadCoWebsite(newValue as string);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange('jitsiRoom', (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange('jitsiRoom', (newValue, oldValue, allProps) => {
|
||||||
|
@ -2,47 +2,90 @@ import {HtmlUtils} from "./HtmlUtils";
|
|||||||
|
|
||||||
export type CoWebsiteStateChangedCallback = () => void;
|
export type CoWebsiteStateChangedCallback = () => void;
|
||||||
|
|
||||||
export class CoWebsiteManager {
|
enum iframeStates {
|
||||||
|
closed = 1,
|
||||||
|
loading, // loading an iframe can be slow, so we show some placeholder until it is ready
|
||||||
|
opened,
|
||||||
|
}
|
||||||
|
|
||||||
private static observers = new Array<CoWebsiteStateChangedCallback>();
|
const cowebsiteDivId = "cowebsite"; // the id of the parent div of the iframe.
|
||||||
|
const animationTime = 500; //time used by the css transitions, in ms.
|
||||||
|
|
||||||
public static loadCoWebsite(url: string): void {
|
class CoWebsiteManager {
|
||||||
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite");
|
|
||||||
|
private opened: iframeStates = iframeStates.closed;
|
||||||
|
|
||||||
|
private observers = new Array<CoWebsiteStateChangedCallback>();
|
||||||
|
|
||||||
|
private close(): HTMLDivElement {
|
||||||
|
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId);
|
||||||
|
cowebsiteDiv.classList.remove('loaded'); //edit the css class to trigger the transition
|
||||||
|
cowebsiteDiv.classList.add('hidden');
|
||||||
|
this.opened = iframeStates.closed;
|
||||||
|
return cowebsiteDiv;
|
||||||
|
}
|
||||||
|
private load(): HTMLDivElement {
|
||||||
|
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId);
|
||||||
|
cowebsiteDiv.classList.remove('hidden'); //edit the css class to trigger the transition
|
||||||
|
cowebsiteDiv.classList.add('loading');
|
||||||
|
this.opened = iframeStates.loading;
|
||||||
|
return cowebsiteDiv;
|
||||||
|
}
|
||||||
|
private open(): HTMLDivElement {
|
||||||
|
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId);
|
||||||
|
cowebsiteDiv.classList.remove('loading', 'hidden'); //edit the css class to trigger the transition
|
||||||
|
this.opened = iframeStates.opened;
|
||||||
|
return cowebsiteDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadCoWebsite(url: string): void {
|
||||||
|
const cowebsiteDiv = this.load();
|
||||||
cowebsiteDiv.innerHTML = '';
|
cowebsiteDiv.innerHTML = '';
|
||||||
|
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
iframe.id = 'cowebsite-iframe';
|
iframe.id = 'cowebsite-iframe';
|
||||||
iframe.src = url;
|
iframe.src = url;
|
||||||
|
const onloadPromise = new Promise((resolve) => {
|
||||||
|
iframe.onload = () => resolve();
|
||||||
|
});
|
||||||
cowebsiteDiv.appendChild(iframe);
|
cowebsiteDiv.appendChild(iframe);
|
||||||
//iframe.onload = () => {
|
const onTimeoutPromise = new Promise((resolve) => {
|
||||||
// onload can be long to trigger. Maybe we should display the website, whatever happens, after 1 second?
|
setTimeout(() => resolve(), 2000);
|
||||||
CoWebsiteManager.fire();
|
});
|
||||||
//}
|
Promise.race([onloadPromise, onTimeoutPromise]).then(() => {
|
||||||
|
this.open();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.fire();
|
||||||
|
}, animationTime)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Just like loadCoWebsite but the div can be filled by the user.
|
* Just like loadCoWebsite but the div can be filled by the user.
|
||||||
*/
|
*/
|
||||||
public static insertCoWebsite(callback: (cowebsite: HTMLDivElement) => void): void {
|
public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise<void>): void {
|
||||||
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite");
|
const cowebsiteDiv = this.load();
|
||||||
cowebsiteDiv.innerHTML = '';
|
callback(cowebsiteDiv).then(() => {
|
||||||
|
this.open();
|
||||||
callback(cowebsiteDiv);
|
setTimeout(() => {
|
||||||
//iframe.onload = () => {
|
this.fire();
|
||||||
// onload can be long to trigger. Maybe we should display the website, whatever happens, after 1 second?
|
}, animationTime)
|
||||||
CoWebsiteManager.fire();
|
});
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static closeCoWebsite(): void {
|
public closeCoWebsite(): Promise<void> {
|
||||||
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite");
|
return new Promise((resolve, reject) => {
|
||||||
cowebsiteDiv.innerHTML = '';
|
const cowebsiteDiv = this.close();
|
||||||
CoWebsiteManager.fire();
|
this.fire();
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
setTimeout(() => cowebsiteDiv.innerHTML = '', 500)
|
||||||
|
}, animationTime)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getGameSize(): {width: number, height: number} {
|
public getGameSize(): {width: number, height: number} {
|
||||||
const hasChildren = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite").children.length > 0;
|
if (this.opened !== iframeStates.opened) {
|
||||||
if (hasChildren === false) {
|
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight
|
height: window.innerHeight
|
||||||
@ -61,13 +104,15 @@ export class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static onStateChange(observer: CoWebsiteStateChangedCallback) {
|
public onStateChange(observer: CoWebsiteStateChangedCallback) {
|
||||||
CoWebsiteManager.observers.push(observer);
|
this.observers.push(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static fire(): void {
|
private fire(): void {
|
||||||
for (const callback of CoWebsiteManager.observers) {
|
for (const callback of this.observers) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const coWebsiteManager = new CoWebsiteManager();
|
@ -1,6 +1,6 @@
|
|||||||
import {CoWebsiteManager} from "./CoWebsiteManager";
|
|
||||||
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
||||||
import {mediaManager} from "./MediaManager";
|
import {mediaManager} from "./MediaManager";
|
||||||
|
import {coWebsiteManager} from "./CoWebsiteManager";
|
||||||
declare const window:any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
declare const window:any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
|
||||||
const interfaceConfig = {
|
const interfaceConfig = {
|
||||||
@ -31,9 +31,9 @@ class JitsiFactory {
|
|||||||
private videoCallback = this.onVideoChange.bind(this);
|
private videoCallback = this.onVideoChange.bind(this);
|
||||||
|
|
||||||
public start(roomName: string, playerName:string, jwt?: string): void {
|
public start(roomName: string, playerName:string, jwt?: string): void {
|
||||||
CoWebsiteManager.insertCoWebsite((cowebsiteDiv => {
|
coWebsiteManager.insertCoWebsite((cowebsiteDiv => {
|
||||||
const domain = JITSI_URL;
|
const domain = JITSI_URL;
|
||||||
const options = {
|
const options: any = { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
roomName: roomName,
|
roomName: roomName,
|
||||||
jwt: jwt,
|
jwt: jwt,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@ -49,19 +49,23 @@ class JitsiFactory {
|
|||||||
if (!options.jwt) {
|
if (!options.jwt) {
|
||||||
delete options.jwt;
|
delete options.jwt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
options.onload = () => resolve(); //we want for the iframe to be loaded before triggering animations.
|
||||||
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
||||||
this.jitsiApi.executeCommand('displayName', playerName);
|
this.jitsiApi.executeCommand('displayName', playerName);
|
||||||
|
|
||||||
this.jitsiApi.addListener('audioMuteStatusChanged', this.audioCallback);
|
this.jitsiApi.addListener('audioMuteStatusChanged', this.audioCallback);
|
||||||
this.jitsiApi.addListener('videoMuteStatusChanged', this.videoCallback);
|
this.jitsiApi.addListener('videoMuteStatusChanged', this.videoCallback);
|
||||||
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public stop(): void {
|
public async stop(): Promise<void> {
|
||||||
|
await coWebsiteManager.closeCoWebsite();
|
||||||
this.jitsiApi.removeListener('audioMuteStatusChanged', this.audioCallback);
|
this.jitsiApi.removeListener('audioMuteStatusChanged', this.audioCallback);
|
||||||
this.jitsiApi.removeListener('videoMuteStatusChanged', this.videoCallback);
|
this.jitsiApi.removeListener('videoMuteStatusChanged', this.videoCallback);
|
||||||
this.jitsiApi?.dispose();
|
this.jitsiApi?.dispose();
|
||||||
CoWebsiteManager.closeCoWebsite();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onAudioChange({muted}: {muted: boolean}): void {
|
private onAudioChange({muted}: {muted: boolean}): void {
|
||||||
|
@ -10,12 +10,9 @@ import {FourOFourScene} from "./Phaser/Reconnecting/FourOFourScene";
|
|||||||
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
|
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
|
||||||
import {OutlinePipeline} from "./Phaser/Shaders/OutlinePipeline";
|
import {OutlinePipeline} from "./Phaser/Shaders/OutlinePipeline";
|
||||||
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
|
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
|
||||||
import {CoWebsiteManager} from "./WebRtc/CoWebsiteManager";
|
|
||||||
import {gameManager} from "./Phaser/Game/GameManager";
|
|
||||||
import {ResizableScene} from "./Phaser/Login/ResizableScene";
|
import {ResizableScene} from "./Phaser/Login/ResizableScene";
|
||||||
import {EntryScene} from "./Phaser/Login/EntryScene";
|
import {EntryScene} from "./Phaser/Login/EntryScene";
|
||||||
|
import {coWebsiteManager} from "./WebRtc/CoWebsiteManager";
|
||||||
//CoWebsiteManager.loadCoWebsite('https://thecodingmachine.com');
|
|
||||||
|
|
||||||
// Load Jitsi if the environment variable is set.
|
// Load Jitsi if the environment variable is set.
|
||||||
if (JITSI_URL) {
|
if (JITSI_URL) {
|
||||||
@ -24,7 +21,7 @@ if (JITSI_URL) {
|
|||||||
document.head.appendChild(jitsiScript);
|
document.head.appendChild(jitsiScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {width, height} = CoWebsiteManager.getGameSize();
|
const {width, height} = coWebsiteManager.getGameSize();
|
||||||
|
|
||||||
const config: GameConfig = {
|
const config: GameConfig = {
|
||||||
title: "WorkAdventure",
|
title: "WorkAdventure",
|
||||||
@ -53,8 +50,7 @@ cypressAsserter.gameStarted();
|
|||||||
const game = new Phaser.Game(config);
|
const game = new Phaser.Game(config);
|
||||||
|
|
||||||
window.addEventListener('resize', function (event) {
|
window.addEventListener('resize', function (event) {
|
||||||
const {width, height} = CoWebsiteManager.getGameSize();
|
const {width, height} = coWebsiteManager.getGameSize();
|
||||||
|
|
||||||
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
||||||
|
|
||||||
// Let's trigger the onResize method of any active scene that is a ResizableScene
|
// Let's trigger the onResize method of any active scene that is a ResizableScene
|
||||||
@ -64,8 +60,7 @@ window.addEventListener('resize', function (event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
CoWebsiteManager.onStateChange(() => {
|
coWebsiteManager.onStateChange(() => {
|
||||||
const {width, height} = CoWebsiteManager.getGameSize();
|
const {width, height} = coWebsiteManager.getGameSize();
|
||||||
|
|
||||||
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user