Merge branch 'develop' of github.com:thecodingmachine/workadventure into trigger-message-refv3

This commit is contained in:
David Négrier 2021-08-05 09:24:05 +02:00
commit 92fee33b64
6 changed files with 176 additions and 119 deletions

View File

@ -33,6 +33,8 @@
import {textMessageVisibleStore} from "../Stores/TypeMessageStore/TextMessageStore"; import {textMessageVisibleStore} from "../Stores/TypeMessageStore/TextMessageStore";
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;
@ -79,6 +81,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>

View 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>

View File

@ -20,7 +20,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,
@ -87,6 +86,8 @@ import { playersStore } from "../../Stores/PlayersStore";
import { chatVisibilityStore } from "../../Stores/ChatStore"; import { chatVisibilityStore } from "../../Stores/ChatStore";
import Tileset = Phaser.Tilemaps.Tileset; import Tileset = Phaser.Tilemaps.Tileset;
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;
@ -791,7 +792,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 = () => {
@ -801,7 +802,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);
@ -810,14 +811,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();
} }
@ -825,7 +825,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 = () => {
@ -838,7 +838,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);
@ -847,14 +847,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();
} }

View 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();

View File

@ -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 };

View File

@ -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;
} }
}); });