Migrate layoutManager in Svelte
This commit is contained in:
parent
3ab069d650
commit
1436b15328
@ -29,6 +29,8 @@
|
|||||||
import ConsoleGlobalMessageManager from "./ConsoleGlobalMessageManager/ConsoleGlobalMessageManager.svelte";
|
import ConsoleGlobalMessageManager from "./ConsoleGlobalMessageManager/ConsoleGlobalMessageManager.svelte";
|
||||||
import {warningContainerStore} from "../Stores/MenuStore";
|
import {warningContainerStore} from "../Stores/MenuStore";
|
||||||
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
||||||
|
import {layoutManagerVisibilityStore} from "../Stores/LayoutManagerStore";
|
||||||
|
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
|
|
||||||
@ -65,6 +67,11 @@
|
|||||||
<AudioPlaying url={$soundPlayingStore} />
|
<AudioPlaying url={$soundPlayingStore} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $layoutManagerVisibilityStore}
|
||||||
|
<div>
|
||||||
|
<LayoutManager></LayoutManager>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if $gameOverlayVisibilityStore}
|
{#if $gameOverlayVisibilityStore}
|
||||||
<div>
|
<div>
|
||||||
<VideoOverlay></VideoOverlay>
|
<VideoOverlay></VideoOverlay>
|
||||||
|
78
front/src/Components/LayoutManager/LayoutManager.svelte
Normal file
78
front/src/Components/LayoutManager/LayoutManager.svelte
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
||||||
|
import { onDestroy, onMount } from "svelte";
|
||||||
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
for (const action of get(layoutManagerActionStore)) {
|
||||||
|
action.userInputManager?.addSpaceEventListner(action.callback);
|
||||||
|
if ( action.type === 'warning') {
|
||||||
|
//remove it after 10 sec
|
||||||
|
setTimeout(() => {
|
||||||
|
layoutManagerActionStore.removeAction(action);
|
||||||
|
}, 10000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
for (const action of get(layoutManagerActionStore)) {
|
||||||
|
action.userInputManager?.removeSpaceEventListner(action.callback);
|
||||||
|
}
|
||||||
|
layoutManagerActionStore.clearActions();
|
||||||
|
})
|
||||||
|
|
||||||
|
function onClick(callback: () => void) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="layout-manager-list">
|
||||||
|
{#each $layoutManagerActionStore as action}
|
||||||
|
<div class="nes-container is-rounded {action.type}" on:click={() => onClick(action.callback)}>
|
||||||
|
<p>{action.message}</p>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.layout-manager-list {
|
||||||
|
pointer-events: auto;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 40px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
width: clamp(200px, 20vw, 20vw);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
animation: moveMessage .5s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.nes-container.is-rounded {
|
||||||
|
padding: 8px 4px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
font-family: Lato;
|
||||||
|
color: whitesmoke;
|
||||||
|
background-color: rgb(0,0,0,0.5);
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
background-color: #ff9800eb;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes moveMessage {
|
||||||
|
0% {bottom: 40px;}
|
||||||
|
50% {bottom: 30px;}
|
||||||
|
100% {bottom: 40px;}
|
||||||
|
}
|
||||||
|
</style>
|
@ -21,7 +21,6 @@ import {
|
|||||||
AUDIO_VOLUME_PROPERTY,
|
AUDIO_VOLUME_PROPERTY,
|
||||||
Box,
|
Box,
|
||||||
JITSI_MESSAGE_PROPERTIES,
|
JITSI_MESSAGE_PROPERTIES,
|
||||||
layoutManager,
|
|
||||||
ON_ACTION_TRIGGER_BUTTON,
|
ON_ACTION_TRIGGER_BUTTON,
|
||||||
TRIGGER_JITSI_PROPERTIES,
|
TRIGGER_JITSI_PROPERTIES,
|
||||||
TRIGGER_WEBSITE_PROPERTIES,
|
TRIGGER_WEBSITE_PROPERTIES,
|
||||||
@ -89,6 +88,8 @@ import { SharedVariablesManager } from "./SharedVariablesManager";
|
|||||||
import { playersStore } from "../../Stores/PlayersStore";
|
import { playersStore } from "../../Stores/PlayersStore";
|
||||||
import { chatVisibilityStore } from "../../Stores/ChatStore";
|
import { chatVisibilityStore } from "../../Stores/ChatStore";
|
||||||
import { userIsAdminStore } from "../../Stores/GameStore";
|
import { userIsAdminStore } from "../../Stores/GameStore";
|
||||||
|
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../../Stores/LayoutManagerStore";
|
||||||
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
@ -793,7 +794,7 @@ export class GameScene extends DirtyScene {
|
|||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange("openWebsite", (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange("openWebsite", (newValue, oldValue, allProps) => {
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
layoutManager.removeActionButton("openWebsite", this.userInputManager);
|
layoutManagerVisibilityStore.set(false);
|
||||||
coWebsiteManager.closeCoWebsite();
|
coWebsiteManager.closeCoWebsite();
|
||||||
} else {
|
} else {
|
||||||
const openWebsiteFunction = () => {
|
const openWebsiteFunction = () => {
|
||||||
@ -803,7 +804,7 @@ export class GameScene extends DirtyScene {
|
|||||||
allProps.get("openWebsiteAllowApi") as boolean | undefined,
|
allProps.get("openWebsiteAllowApi") as boolean | undefined,
|
||||||
allProps.get("openWebsitePolicy") as string | undefined
|
allProps.get("openWebsitePolicy") as string | undefined
|
||||||
);
|
);
|
||||||
layoutManager.removeActionButton("openWebsite", this.userInputManager);
|
layoutManagerVisibilityStore.set(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openWebsiteTriggerValue = allProps.get(TRIGGER_WEBSITE_PROPERTIES);
|
const openWebsiteTriggerValue = allProps.get(TRIGGER_WEBSITE_PROPERTIES);
|
||||||
@ -812,14 +813,13 @@ export class GameScene extends DirtyScene {
|
|||||||
if (message === undefined) {
|
if (message === undefined) {
|
||||||
message = "Press SPACE or touch here to open web site";
|
message = "Press SPACE or touch here to open web site";
|
||||||
}
|
}
|
||||||
layoutManager.addActionButton(
|
layoutManagerActionStore.addAction({
|
||||||
"openWebsite",
|
type: "openWebsite",
|
||||||
message.toString(),
|
message: message,
|
||||||
() => {
|
callback: () => openWebsiteFunction(),
|
||||||
openWebsiteFunction();
|
userInputManager: this.userInputManager,
|
||||||
},
|
});
|
||||||
this.userInputManager
|
layoutManagerVisibilityStore.set(true);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
openWebsiteFunction();
|
openWebsiteFunction();
|
||||||
}
|
}
|
||||||
@ -827,7 +827,7 @@ export class GameScene extends DirtyScene {
|
|||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange("jitsiRoom", (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange("jitsiRoom", (newValue, oldValue, allProps) => {
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
layoutManager.removeActionButton("jitsiRoom", this.userInputManager);
|
layoutManagerVisibilityStore.set(false);
|
||||||
this.stopJitsi();
|
this.stopJitsi();
|
||||||
} else {
|
} else {
|
||||||
const openJitsiRoomFunction = () => {
|
const openJitsiRoomFunction = () => {
|
||||||
@ -840,7 +840,7 @@ export class GameScene extends DirtyScene {
|
|||||||
} else {
|
} else {
|
||||||
this.startJitsi(roomName, undefined);
|
this.startJitsi(roomName, undefined);
|
||||||
}
|
}
|
||||||
layoutManager.removeActionButton("jitsiRoom", this.userInputManager);
|
layoutManagerVisibilityStore.set(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const jitsiTriggerValue = allProps.get(TRIGGER_JITSI_PROPERTIES);
|
const jitsiTriggerValue = allProps.get(TRIGGER_JITSI_PROPERTIES);
|
||||||
@ -849,14 +849,13 @@ export class GameScene extends DirtyScene {
|
|||||||
if (message === undefined) {
|
if (message === undefined) {
|
||||||
message = "Press SPACE or touch here to enter Jitsi Meet room";
|
message = "Press SPACE or touch here to enter Jitsi Meet room";
|
||||||
}
|
}
|
||||||
layoutManager.addActionButton(
|
layoutManagerActionStore.addAction({
|
||||||
"jitsiRoom",
|
type: "jitsiRoom",
|
||||||
message.toString(),
|
message: message,
|
||||||
() => {
|
callback: () => openJitsiRoomFunction(),
|
||||||
openJitsiRoomFunction();
|
userInputManager: this.userInputManager,
|
||||||
},
|
});
|
||||||
this.userInputManager
|
layoutManagerVisibilityStore.set(true);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
openJitsiRoomFunction();
|
openJitsiRoomFunction();
|
||||||
}
|
}
|
||||||
@ -1153,7 +1152,7 @@ ${escapedMessage}
|
|||||||
let targetRoom: Room;
|
let targetRoom: Room;
|
||||||
try {
|
try {
|
||||||
targetRoom = await Room.createRoom(roomUrl);
|
targetRoom = await Room.createRoom(roomUrl);
|
||||||
} catch (e: unknown) {
|
} catch (e) {
|
||||||
console.error('Error while fetching new room "' + roomUrl.toString() + '"', e);
|
console.error('Error while fetching new room "' + roomUrl.toString() + '"', e);
|
||||||
this.mapTransitioning = false;
|
this.mapTransitioning = false;
|
||||||
return;
|
return;
|
||||||
@ -1279,7 +1278,7 @@ ${escapedMessage}
|
|||||||
try {
|
try {
|
||||||
const room = await Room.createRoom(exitRoomPath);
|
const room = await Room.createRoom(exitRoomPath);
|
||||||
return gameManager.loadMap(room, this.scene);
|
return gameManager.loadMap(room, this.scene);
|
||||||
} catch (e: unknown) {
|
} catch (e) {
|
||||||
console.warn('Error while pre-loading exit room "' + exitRoomPath.toString() + '"', e);
|
console.warn('Error while pre-loading exit room "' + exitRoomPath.toString() + '"', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
53
front/src/Stores/LayoutManagerStore.ts
Normal file
53
front/src/Stores/LayoutManagerStore.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
|
||||||
|
|
||||||
|
export interface LayoutManagerAction {
|
||||||
|
type: string;
|
||||||
|
message: string | number | boolean | undefined;
|
||||||
|
callback: () => void;
|
||||||
|
userInputManager: UserInputManager | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const layoutManagerVisibilityStore = writable(false);
|
||||||
|
|
||||||
|
function createLayoutManagerAction() {
|
||||||
|
const { subscribe, set, update } = writable<LayoutManagerAction[]>([]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
addAction: (newAction: LayoutManagerAction): void => {
|
||||||
|
update((list: LayoutManagerAction[]) => {
|
||||||
|
let found = false;
|
||||||
|
for (const actions of list) {
|
||||||
|
if (actions.type === newAction.type && actions.message === newAction.message) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
list.push(newAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeAction: (oldAction: LayoutManagerAction): void => {
|
||||||
|
update((list: LayoutManagerAction[]) => {
|
||||||
|
const index = list.findIndex(
|
||||||
|
(actions) => actions.type === oldAction.type && actions.message === oldAction.message
|
||||||
|
);
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
list.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearActions: (): void => {
|
||||||
|
set([]);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const layoutManagerActionStore = createLayoutManagerAction();
|
@ -1,6 +1,3 @@
|
|||||||
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
|
|
||||||
import { HtmlUtils } from "./HtmlUtils";
|
|
||||||
|
|
||||||
export enum LayoutMode {
|
export enum LayoutMode {
|
||||||
// All videos are displayed on the right side of the screen. If there is a screen sharing, it is displayed in the middle.
|
// All videos are displayed on the right side of the screen. If there is a screen sharing, it is displayed in the middle.
|
||||||
Presentation = "Presentation",
|
Presentation = "Presentation",
|
||||||
@ -27,85 +24,3 @@ export const AUDIO_VOLUME_PROPERTY = "audioVolume";
|
|||||||
export const AUDIO_LOOP_PROPERTY = "audioLoop";
|
export const AUDIO_LOOP_PROPERTY = "audioLoop";
|
||||||
|
|
||||||
export type Box = { xStart: number; yStart: number; xEnd: number; yEnd: number };
|
export type Box = { xStart: number; yStart: number; xEnd: number; yEnd: number };
|
||||||
|
|
||||||
class LayoutManager {
|
|
||||||
private actionButtonTrigger: Map<string, Function> = new Map<string, Function>();
|
|
||||||
private actionButtonInformation: Map<string, HTMLDivElement> = new Map<string, HTMLDivElement>();
|
|
||||||
|
|
||||||
public addActionButton(id: string, text: string, callBack: Function, userInputManager: UserInputManager) {
|
|
||||||
//delete previous element
|
|
||||||
this.removeActionButton(id, userInputManager);
|
|
||||||
|
|
||||||
//create div and text html component
|
|
||||||
const p = document.createElement("p");
|
|
||||||
p.classList.add("action-body");
|
|
||||||
p.innerText = text;
|
|
||||||
|
|
||||||
const div = document.createElement("div");
|
|
||||||
div.classList.add("action");
|
|
||||||
div.id = id;
|
|
||||||
div.appendChild(p);
|
|
||||||
|
|
||||||
this.actionButtonInformation.set(id, div);
|
|
||||||
|
|
||||||
const mainContainer = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("main-container");
|
|
||||||
mainContainer.appendChild(div);
|
|
||||||
|
|
||||||
//add trigger action
|
|
||||||
div.onpointerdown = () => callBack();
|
|
||||||
this.actionButtonTrigger.set(id, callBack);
|
|
||||||
userInputManager.addSpaceEventListner(callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeActionButton(id: string, userInputManager?: UserInputManager) {
|
|
||||||
//delete previous element
|
|
||||||
const previousDiv = this.actionButtonInformation.get(id);
|
|
||||||
if (previousDiv) {
|
|
||||||
previousDiv.remove();
|
|
||||||
this.actionButtonInformation.delete(id);
|
|
||||||
}
|
|
||||||
const previousEventCallback = this.actionButtonTrigger.get(id);
|
|
||||||
if (previousEventCallback && userInputManager) {
|
|
||||||
userInputManager.removeSpaceEventListner(previousEventCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public addInformation(id: string, text: string, callBack?: Function, userInputManager?: UserInputManager) {
|
|
||||||
//delete previous element
|
|
||||||
for (const [key, value] of this.actionButtonInformation) {
|
|
||||||
this.removeActionButton(key, userInputManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
//create div and text html component
|
|
||||||
const p = document.createElement("p");
|
|
||||||
p.classList.add("action-body");
|
|
||||||
p.innerText = text;
|
|
||||||
|
|
||||||
const div = document.createElement("div");
|
|
||||||
div.classList.add("action");
|
|
||||||
div.classList.add(id);
|
|
||||||
div.id = id;
|
|
||||||
div.appendChild(p);
|
|
||||||
|
|
||||||
this.actionButtonInformation.set(id, div);
|
|
||||||
|
|
||||||
const mainContainer = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("main-container");
|
|
||||||
mainContainer.appendChild(div);
|
|
||||||
//add trigger action
|
|
||||||
if (callBack) {
|
|
||||||
div.onpointerdown = () => {
|
|
||||||
callBack();
|
|
||||||
this.removeActionButton(id, userInputManager);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove it after 10 sec
|
|
||||||
setTimeout(() => {
|
|
||||||
this.removeActionButton(id, userInputManager);
|
|
||||||
}, 10000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const layoutManager = new LayoutManager();
|
|
||||||
|
|
||||||
export { layoutManager };
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { layoutManager } from "./LayoutManager";
|
|
||||||
import { HtmlUtils } from "./HtmlUtils";
|
import { HtmlUtils } from "./HtmlUtils";
|
||||||
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
|
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
|
||||||
import { localStreamStore } from "../Stores/MediaStore";
|
import { localStreamStore } from "../Stores/MediaStore";
|
||||||
@ -10,6 +9,8 @@ export type StopScreenSharingCallback = (media: MediaStream) => void;
|
|||||||
|
|
||||||
import { cowebsiteCloseButtonId } from "./CoWebsiteManager";
|
import { cowebsiteCloseButtonId } from "./CoWebsiteManager";
|
||||||
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
|
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
|
||||||
|
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
|
||||||
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
export class MediaManager {
|
export class MediaManager {
|
||||||
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
||||||
@ -23,14 +24,16 @@ export class MediaManager {
|
|||||||
localStreamStore.subscribe((result) => {
|
localStreamStore.subscribe((result) => {
|
||||||
if (result.type === "error") {
|
if (result.type === "error") {
|
||||||
console.error(result.error);
|
console.error(result.error);
|
||||||
layoutManager.addInformation(
|
layoutManagerActionStore.addAction({
|
||||||
"warning",
|
type: "warning",
|
||||||
"Camera access denied. Click here and check your browser permissions.",
|
message: "Camera access denied. Click here and check your browser permissions.",
|
||||||
() => {
|
callback: () => {
|
||||||
helpCameraSettingsVisibleStore.set(true);
|
helpCameraSettingsVisibleStore.set(true);
|
||||||
|
layoutManagerVisibilityStore.set(false);
|
||||||
},
|
},
|
||||||
this.userInputManager
|
userInputManager: this.userInputManager,
|
||||||
);
|
});
|
||||||
|
layoutManagerVisibilityStore.set(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -38,14 +41,16 @@ export class MediaManager {
|
|||||||
screenSharingLocalStreamStore.subscribe((result) => {
|
screenSharingLocalStreamStore.subscribe((result) => {
|
||||||
if (result.type === "error") {
|
if (result.type === "error") {
|
||||||
console.error(result.error);
|
console.error(result.error);
|
||||||
layoutManager.addInformation(
|
layoutManagerActionStore.addAction({
|
||||||
"warning",
|
type: "warning",
|
||||||
"Screen sharing denied. Click here and check your browser permissions.",
|
message: "Screen sharing denied. Click here and check your browser permissions.",
|
||||||
() => {
|
callback: () => {
|
||||||
helpCameraSettingsVisibleStore.set(true);
|
helpCameraSettingsVisibleStore.set(true);
|
||||||
|
layoutManagerVisibilityStore.set(false);
|
||||||
},
|
},
|
||||||
this.userInputManager
|
userInputManager: this.userInputManager,
|
||||||
);
|
});
|
||||||
|
layoutManagerVisibilityStore.set(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user