diff --git a/front/dist/index.html b/front/dist/index.html
index a680c59a..92a7bf3c 100644
--- a/front/dist/index.html
+++ b/front/dist/index.html
@@ -39,7 +39,53 @@
diff --git a/front/dist/resources/style/style.css b/front/dist/resources/style/style.css
index 5f0e1cab..45b61679 100644
--- a/front/dist/resources/style/style.css
+++ b/front/dist/resources/style/style.css
@@ -27,7 +27,7 @@ video{
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
}
-.webrtc{
+/*.webrtc{
display: none;
position: absolute;
right: 0px;
@@ -36,21 +36,22 @@ video{
}
.webrtc.active{
display: block;
-}
+}*/
-.webrtc, .activeCam{}
-.activeCam .video-container{
- position: absolute;
- height: 25%;
+/*.webrtc, .activeCam{}*/
+/*.activeCam*/ .video-container{
+ position: relative;
+ /*height: 25%;
top: 10px;
margin: 5px;
right: -100px;
- transition: all 0.2s ease;
- border-color: black;
+ transition: all 0.2s ease;*/
+ /*border-color: black;
border-style: solid;
- border-width: 0.2px;
+ border-width: 0.2px;*/
+ background-color: #00000099;
}
-.activeCam .video-container i{
+/*.activeCam*/ .video-container i{
position: absolute;
width: 100px;
height: 65px;
@@ -63,10 +64,10 @@ video{
font-size: 28px;
color: white;
}
-.activeCam .video-container img.active{
+/*.activeCam*/ .video-container img.active{
display: block;
}
-.activeCam .video-container img{
+/*.activeCam*/ .video-container img{
position: absolute;
display: none;
width: 15px;
@@ -78,34 +79,28 @@ video{
padding: 10px;
z-index: 2;
}
-.activeCam .video-container video{
+/*.activeCam*/ .video-container video{
height: 100%;
}
-.webrtc:hover .activeCam .video-container{
+/*.webrtc:hover .activeCam .video-container{
right: 10px;
-}
-.activeCam .video-container#div-myCamVideo{
+}*/
+/*.activeCam*/ .video-container#div-myCamVideo{
border: none;
}
-.activeCam .video-container video#myCamVideo{
- width: 200px;
- height: 113px;
+/*.activeCam*/
+
+#div-myCamVideo {
+ position: fixed;
+ right: 0;
+ bottom: 0;
}
-/*CSS size for 2 - 3 elements*/
-.activeCam .video-container:nth-child(1){
- /*this is for camera of user*/
- top: 75%;
-}
-.activeCam .video-container:nth-child(2){
- top: 0%;
-}
-.activeCam .video-container:nth-child(3){
- top: 25%;
-}
-.activeCam .video-container:nth-child(4) {
- top: 50%;
+video#myCamVideo{
+ width: 15vw;
+ /*width: 200px;*/
+ /*height: 113px;*/
}
/*btn animation*/
@@ -122,7 +117,7 @@ video{
transition-timing-function: ease-in-out;
bottom: 20px;
}
-.webrtc:hover .btn-cam-action div{
+#activeCam:hover .btn-cam-action div{
transform: translateY(0);
}
.btn-cam-action div:hover{
@@ -237,3 +232,138 @@ video{
.webrtcsetup.active{
display: block;
}
+
+
+/* New layout */
+body {
+ margin: 0;
+ height: 100vh;
+ width: 100vw;
+}
+.main-container {
+ height: 100vh;
+ width: 100vw;
+ display: flex;
+ align-items: stretch;
+}
+
+@media (min-aspect-ratio: 1/1) {
+ .main-container {
+ flex-direction: row
+ }
+
+ .game-overlay {
+ flex-direction: row
+ }
+
+ .sidebar {
+ flex-direction: column
+ }
+}
+@media (max-aspect-ratio: 1/1) {
+ .main-container {
+ flex-direction: column
+ }
+
+ .game-overlay {
+ flex-direction: column
+ }
+
+ .sidebar {
+ flex-direction: row
+ }
+}
+
+.game {
+ flex-basis: 100%;
+ position: relative; /* Position relative is needed for the game-overlay. */
+}
+
+/* A potentially shared website could appear in an iframe in the cowebsite space. */
+.cowebsite {
+ flex-basis: 100%;
+ transition: flex-basis 0.5s;
+}
+
+/*.cowebsite:hover {
+ flex-basis: 100%;
+}*/
+
+.cowebsite iframe {
+ width: 100%;
+ height: 100%;
+}
+
+
+.game-overlay {
+ display: none;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ /* TODO: DO WE NEED FLEX HERE???? WE WANT A SIDEBAR OF EXACTLY 25% (note: flex useful for direction!!!) */
+}
+
+.game-overlay.active {
+ display: flex;
+}
+
+.game-overlay video {
+ width: 100%
+}
+
+.main-section {
+ flex: 0 0 75%;
+ display: flex;
+ justify-content: start;
+ /*align-items: flex-start;*/
+ flex-wrap: wrap;
+}
+
+.main-section div {
+ margin: 5%;
+ flex-basis: 90%;
+ /*flex-shrink: 2;*/
+}
+
+.sidebar {
+ flex: 0 0 25%;
+ display: flex;
+}
+
+.sidebar > div {
+ height: 15%;
+ margin: 5%;
+}
+
+.chat-mode {
+ display: flex;
+ width: 100%;
+
+ flex-wrap: wrap;
+
+ padding: 1%;
+}
+
+.chat-mode div {
+ margin: 1%;
+}
+
+.chat-mode.one-col div {
+ flex-basis: 98%;
+}
+
+.chat-mode.two-col div {
+ flex-basis: 48%;
+}
+
+.chat-mode.three-col div {
+ flex-basis: 31.333333%;
+}
+
+.chat-mode.four-col div {
+ flex-basis: 23%;
+}
+
+.chat-mode div:last-child {
+ flex-grow: 5;
+}
diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts
new file mode 100644
index 00000000..0150760c
--- /dev/null
+++ b/front/src/WebRtc/CoWebsiteManager.ts
@@ -0,0 +1,56 @@
+import {HtmlUtils} from "./HtmlUtils";
+
+export type CoWebsiteStateChangedCallback = () => void;
+
+export class CoWebsiteManager {
+
+ private static observers = new Array
();
+
+ public static loadCoWebsite(url: string): void {
+ const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite");
+ cowebsiteDiv.innerHTML = '';
+
+ const iframe = document.createElement('iframe');
+ iframe.id = 'cowebsite-iframe';
+ iframe.src = url;
+ cowebsiteDiv.appendChild(iframe);
+ CoWebsiteManager.fire();
+ }
+
+ public static closeCoWebsite(): void {
+ const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite");
+ cowebsiteDiv.innerHTML = '';
+ CoWebsiteManager.fire();
+ }
+
+ public static getGameSize(): {width: number, height: number} {
+ const iframe = document.getElementById('cowebsite-iframe');
+ if (iframe === null) {
+ return {
+ width: window.innerWidth,
+ height: window.innerHeight
+ }
+ }
+ if (window.innerWidth >= window.innerHeight) {
+ return {
+ width: window.innerWidth / 2,
+ height: window.innerHeight
+ }
+ } else {
+ return {
+ width: window.innerWidth,
+ height: window.innerHeight / 2
+ }
+ }
+ }
+
+ public static onStateChange(observer: CoWebsiteStateChangedCallback) {
+ CoWebsiteManager.observers.push(observer);
+ }
+
+ private static fire(): void {
+ for (const callback of CoWebsiteManager.observers) {
+ callback();
+ }
+ }
+}
diff --git a/front/src/WebRtc/LayoutManager.ts b/front/src/WebRtc/LayoutManager.ts
index 63a02356..670e05bd 100644
--- a/front/src/WebRtc/LayoutManager.ts
+++ b/front/src/WebRtc/LayoutManager.ts
@@ -18,7 +18,7 @@ export enum DivImportance {
* This class is in charge of the video-conference layout.
* It receives positioning requests for videos and does its best to place them on the screen depending on the active layout mode.
*/
-export class LayoutManager {
+class LayoutManager {
private mode: LayoutMode = LayoutMode.Presentation;
private importantDivs: Map = new Map();
@@ -26,7 +26,7 @@ export class LayoutManager {
public add(importance: DivImportance, userId: string, html: string): void {
const div = document.createElement('div');
- div.append(html);
+ div.innerHTML = html;
div.id = "user-"+userId;
if (importance === DivImportance.Important) {
@@ -65,6 +65,7 @@ export class LayoutManager {
* Removes the DIV matching userId.
*/
public remove(userId: string): void {
+ console.log('Removing video for userID '+userId+'.');
let div = this.importantDivs.get(userId);
if (div !== undefined) {
div.remove();
@@ -81,7 +82,8 @@ export class LayoutManager {
return;
}
- throw new Error('Could not find user ID "'+userId+'"');
+ console.log('Cannot remove userID '+userId+'. Already removed?');
+ //throw new Error('Could not find user ID "'+userId+'"');
}
private adjustVideoChatClass(): void {
@@ -104,6 +106,16 @@ export class LayoutManager {
private switchLayoutMode(layoutMode: LayoutMode) {
this.mode = layoutMode;
+ if (layoutMode === LayoutMode.Presentation) {
+ HtmlUtils.getElementByIdOrFail('sidebar').style.display = 'block';
+ HtmlUtils.getElementByIdOrFail('main-section').style.display = 'block';
+ HtmlUtils.getElementByIdOrFail('chat-mode').style.display = 'none';
+ } else {
+ HtmlUtils.getElementByIdOrFail('sidebar').style.display = 'none';
+ HtmlUtils.getElementByIdOrFail('main-section').style.display = 'none';
+ HtmlUtils.getElementByIdOrFail('chat-mode').style.display = 'block';
+ }
+
for (let div of this.importantDivs.values()) {
this.positionDiv(div, DivImportance.Important);
}
@@ -112,3 +124,7 @@ export class LayoutManager {
}
}
}
+
+const layoutManager = new LayoutManager();
+
+export { layoutManager };
diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts
index e69850a2..fb7c34f1 100644
--- a/front/src/WebRtc/MediaManager.ts
+++ b/front/src/WebRtc/MediaManager.ts
@@ -1,3 +1,5 @@
+import {DivImportance, layoutManager} from "./LayoutManager";
+
const videoConstraint: boolean|MediaTrackConstraints = {
width: { ideal: 1280 },
height: { ideal: 720 },
@@ -73,8 +75,8 @@ export class MediaManager {
}
activeVisio(){
- const webRtc = this.getElementByIdOrFail('webRtc');
- webRtc.classList.add('active');
+ const gameOverlay = this.getElementByIdOrFail('game-overlay');
+ gameOverlay.classList.add('active');
}
enabledCamera() {
@@ -184,10 +186,11 @@ export class MediaManager {
*/
addActiveVideo(userId : string, userName: string = ""){
this.webrtcInAudio.play();
- const elementRemoteVideo = this.getElementByIdOrFail("activeCam");
+
+ //const elementRemoteVideo = this.getElementByIdOrFail("activeCam");
userName = userName.toUpperCase();
const color = this.getColorByString(userName);
- elementRemoteVideo.insertAdjacentHTML('beforeend', `
+ /*elementRemoteVideo.insertAdjacentHTML('beforeend', `
@@ -195,7 +198,20 @@ export class MediaManager {
- `);
+ `);*/
+
+ const html = `
+
+
+
+
${userName}
+

+
+
+ `;
+
+ layoutManager.add(DivImportance.Normal, userId, html);
+
this.remoteVideo.set(userId, this.getElementByIdOrFail(userId));
}
@@ -274,11 +290,12 @@ export class MediaManager {
* @param userId
*/
removeActiveVideo(userId : string){
- const element = document.getElementById(`div-${userId}`);
+ /*const element = document.getElementById(`div-${userId}`);
if(!element){
return;
}
- element.remove();
+ element.remove();*/
+ layoutManager.remove(userId);
this.remoteVideo.delete(userId);
}
diff --git a/front/src/index.ts b/front/src/index.ts
index d64a8f2e..75ad0fe6 100644
--- a/front/src/index.ts
+++ b/front/src/index.ts
@@ -4,16 +4,21 @@ import {DEBUG_MODE, RESOLUTION} from "./Enum/EnvironmentVariable";
import {cypressAsserter} from "./Cypress/CypressAsserter";
import {LoginScene} from "./Phaser/Login/LoginScene";
import {ReconnectingScene} from "./Phaser/Reconnecting/ReconnectingScene";
-import {gameManager} from "./Phaser/Game/GameManager";
import {SelectCharacterScene} from "./Phaser/Login/SelectCharacterScene";
import {EnableCameraScene} from "./Phaser/Login/EnableCameraScene";
import {FourOFourScene} from "./Phaser/Reconnecting/FourOFourScene";
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
+import {HtmlUtils} from "./WebRtc/HtmlUtils";
+import {CoWebsiteManager} from "./WebRtc/CoWebsiteManager";
+
+//CoWebsiteManager.loadCoWebsite('https://thecodingmachine.com');
+
+const {width, height} = CoWebsiteManager.getGameSize();
const config: GameConfig = {
title: "WorkAdventure",
- width: window.innerWidth / RESOLUTION,
- height: window.innerHeight / RESOLUTION,
+ width: width / RESOLUTION,
+ height: height / RESOLUTION,
parent: "game",
scene: [LoginScene, SelectCharacterScene, EnableCameraScene, ReconnectingScene, FourOFourScene, CustomizeScene],
zoom: RESOLUTION,
@@ -30,5 +35,12 @@ cypressAsserter.gameStarted();
const game = new Phaser.Game(config);
window.addEventListener('resize', function (event) {
- game.scale.resize(window.innerWidth / RESOLUTION, window.innerHeight / RESOLUTION);
+ const {width, height} = CoWebsiteManager.getGameSize();
+
+ game.scale.resize(width / RESOLUTION, height / RESOLUTION);
+});
+CoWebsiteManager.onStateChange(() => {
+ const {width, height} = CoWebsiteManager.getGameSize();
+
+ game.scale.resize(width / RESOLUTION, height / RESOLUTION);
});