Merge branch 'develop' of github.com:thecodingmachine/workadventure into main
@ -473,7 +473,22 @@ export class GameRoom {
|
|||||||
const variablesManager = new VariablesManager(this.roomUrl, null);
|
const variablesManager = new VariablesManager(this.roomUrl, null);
|
||||||
return variablesManager.init();
|
return variablesManager.init();
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
// An error occurred while loading the map
|
||||||
|
// Right now, let's bypass the error. In the future, we should make sure the user is aware of that
|
||||||
|
// and that he/she will act on it to fix the problem.
|
||||||
|
|
||||||
|
// Note: we run this message inside a setTimeout so that the room listeners can have time to connect.
|
||||||
|
setTimeout(() => {
|
||||||
|
for (const roomListener of this.roomListeners) {
|
||||||
|
emitErrorOnRoomSocket(
|
||||||
|
roomListener,
|
||||||
|
"Your map does not seem accessible from the WorkAdventure servers. Is it behind a firewall or a proxy? Your map should be accessible from the WorkAdventure servers. If you use the scripting API in this map, please be aware that server-side checks and variable persistence is disabled."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
const variablesManager = new VariablesManager(this.roomUrl, null);
|
||||||
|
return variablesManager.init();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
31
front/dist/index.tmpl.html
vendored
@ -60,37 +60,6 @@
|
|||||||
<img src="resources/logos/close.svg"/>
|
<img src="resources/logos/close.svg"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="audioplayerctrl" class="hidden">
|
|
||||||
<div class="audioplayer">
|
|
||||||
<button type="button" id="audioplayer_mute" class="fa fa-volump-up">
|
|
||||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-volume-up" fill="white" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path fill-rule="evenodd" d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04L4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96V5.04z" />
|
|
||||||
<g id="audioplayer_volume_icon_playing">
|
|
||||||
<g id="audioplayer_volume_icon_playing_high">
|
|
||||||
<path d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303l.708.707z" />
|
|
||||||
</g>
|
|
||||||
<g id="audioplayer_volume_icon_playing_mid">
|
|
||||||
<path d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89l.706.706z" />
|
|
||||||
</g>
|
|
||||||
<g id="audioplayer_volume_icon_playing_low">
|
|
||||||
<path d="M8.707 11.182A4.486 4.486 0 0 0 10.025 8a4.486 4.486 0 0 0-1.318-3.182L8 5.525A3.489 3.489 0 0 1 9.025 8 3.49 3.49 0 0 1 8 10.475l.707.707z" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<div class="audioplayer">
|
|
||||||
<input type="range" id="audioplayer_volume" min="0" max="1" step="0.025" value="1" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="audioplayer">
|
|
||||||
<label id="label-audioplayer_decrease_while_talking" for="audioplayer_decrease_while_talking" title="decrease background volume by 50% when entering conversations">
|
|
||||||
<input type="checkbox" class="nes-checkbox is-dark" id="audioplayer_decrease_while_talking" checked />
|
|
||||||
<span>reduce in conversations</span>
|
|
||||||
</label>
|
|
||||||
<div id="audioplayer" style="visibility: hidden"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="activeScreenSharing" class="active-screen-sharing active">
|
<div id="activeScreenSharing" class="active-screen-sharing active">
|
||||||
|
2
front/dist/resources/html/gameMenu.html
vendored
@ -49,7 +49,7 @@
|
|||||||
<button id="toggleFullscreen" class="nes-btn">Toggle fullscreen</button>
|
<button id="toggleFullscreen" class="nes-btn">Toggle fullscreen</button>
|
||||||
</section>
|
</section>
|
||||||
<!-- TODO activate authentication -->
|
<!-- TODO activate authentication -->
|
||||||
<section>
|
<section hidden>
|
||||||
<button id="oidcLogin" class="nes-btn">we.bstly Login</button>
|
<button id="oidcLogin" class="nes-btn">we.bstly Login</button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
62
front/dist/resources/service-worker.html
vendored
@ -1,62 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
|
|
||||||
<!-- TRACK CODE -->
|
|
||||||
<!-- END TRACK CODE -->
|
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="/static/images/favicons/apple-icon-57x57.png">
|
|
||||||
<link rel="apple-touch-icon" sizes="60x60" href="/static/images/favicons/apple-icon-60x60.png">
|
|
||||||
<link rel="apple-touch-icon" sizes="72x72" href="/static/images/favicons/apple-icon-72x72.png">
|
|
||||||
<link rel="apple-touch-icon" sizes="76x76" href="/static/images/favicons/apple-icon-76x76.png">
|
|
||||||
<link rel="apple-touch-icon" sizes="114x114" href="/static/images/favicons/apple-icon-114x114.png">
|
|
||||||
<link rel="apple-touch-icon" sizes="120x120" href="/static/images/favicons/apple-icon-120x120.png">
|
|
||||||
<link rel="apple-touch-icon" sizes="144x144" href="/static/images/favicons/apple-icon-144x144.png">
|
|
||||||
<link rel="apple-touch-icon" sizes="152x152" href="/static/images/favicons/apple-icon-152x152.png">
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/static/images/favicons/apple-icon-180x180.png">
|
|
||||||
<link rel="icon" type="image/png" sizes="192x192" href="/static/images/favicons/android-icon-192x192.png">
|
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/static/images/favicons/favicon-32x32.png">
|
|
||||||
<link rel="icon" type="image/png" sizes="96x96" href="/static/images/favicons/favicon-96x96.png">
|
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/static/images/favicons/favicon-16x16.png">
|
|
||||||
<meta name="msapplication-TileColor" content="#000000">
|
|
||||||
<meta name="msapplication-TileImage" content="/static/images/favicons/ms-icon-144x144.png">
|
|
||||||
<meta name="theme-color" content="#000000">
|
|
||||||
|
|
||||||
<title>WorkAdventure PWA</title>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body{
|
|
||||||
font-family: Whitney, Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
||||||
}
|
|
||||||
body img{
|
|
||||||
position: absolute;
|
|
||||||
top: calc( 50% - 25px);
|
|
||||||
height: 59px;
|
|
||||||
width: 307px;
|
|
||||||
left: calc( 50% - 150px);
|
|
||||||
}
|
|
||||||
body p{
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
top: calc( 50% + 50px);
|
|
||||||
left: calc( 50% - 150px);
|
|
||||||
height: 59px;
|
|
||||||
width: 307px;
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<img src="/static/images/logo.png" alt="WorkAdventure logo"/>
|
|
||||||
<p>Charging your workspace ...</p>
|
|
||||||
<script>
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location = localStorage.getItem('lastRoomUrl');
|
|
||||||
}, 4000);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -8,7 +8,6 @@ self.addEventListener('install', function(event) {
|
|||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
caches.open(CACHE_NAME)
|
caches.open(CACHE_NAME)
|
||||||
.then(function(cache) {
|
.then(function(cache) {
|
||||||
console.log('Opened cache');
|
|
||||||
return cache.addAll(urlsToCache);
|
return cache.addAll(urlsToCache);
|
||||||
})
|
})
|
||||||
);
|
);
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 978 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 985 B After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
front/dist/static/images/favicons/apple-icon.png
vendored
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
BIN
front/dist/static/images/favicons/icon-512x512.png
vendored
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 3.4 KiB |
60
front/dist/static/images/favicons/manifest.json
vendored
@ -48,41 +48,10 @@
|
|||||||
"type": "image\/png"
|
"type": "image\/png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/static/images/favicons/android-icon-36x36.png",
|
"src": "/static/images/favicons/apple-icon.png",
|
||||||
"sizes": "36x36",
|
"sizes": "192x192",
|
||||||
"type": "image\/png",
|
"type": "image\/png",
|
||||||
"density": "0.75"
|
"purpose": "any"
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/static/images/favicons/android-icon-48x48.png",
|
|
||||||
"sizes": "48x48",
|
|
||||||
"type": "image\/png",
|
|
||||||
"density": "1.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/static/images/favicons/android-icon-72x72.png",
|
|
||||||
"sizes": "72x72",
|
|
||||||
"type": "image\/png",
|
|
||||||
"density": "1.5"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"src": "/static/images/favicons/favicon-16x16.png",
|
|
||||||
"sizes": "16x16",
|
|
||||||
"type": "image\/png",
|
|
||||||
"density": "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/static/images/favicons/favicon-32x32.png",
|
|
||||||
"sizes": "32x32",
|
|
||||||
"type": "image\/png",
|
|
||||||
"density": "1.5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/static/images/favicons/favicon-96x96.png",
|
|
||||||
"sizes": "96x96",
|
|
||||||
"type": "image\/png",
|
|
||||||
"density": "2.0"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -122,18 +91,37 @@
|
|||||||
"density": "4.0",
|
"density": "4.0",
|
||||||
"purpose": "any maskable"
|
"purpose": "any maskable"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"src": "/static/images/favicons/favicon-16x16.png",
|
||||||
|
"sizes": "16x16",
|
||||||
|
"type": "image\/png",
|
||||||
|
"density": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/images/favicons/favicon-32x32.png",
|
||||||
|
"sizes": "32x32",
|
||||||
|
"type": "image\/png",
|
||||||
|
"density": "1.5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/images/favicons/favicon-96x96.png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"type": "image\/png",
|
||||||
|
"density": "2.0"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"src": "/static/images/favicons/icon-512x512.png",
|
"src": "/static/images/favicons/icon-512x512.png",
|
||||||
"sizes": "512x512",
|
"sizes": "512x512",
|
||||||
"type": "image\/png"
|
"type": "image\/png"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"start_url": "/resources/service-worker.html",
|
"start_url": "/",
|
||||||
"background_color": "#000000",
|
"background_color": "#000000",
|
||||||
"display_override": ["window-control-overlay", "minimal-ui"],
|
"display_override": ["window-control-overlay", "minimal-ui"],
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"orientation": "portrait-primary",
|
"orientation": "portrait-primary",
|
||||||
"scope": "/resources/",
|
"scope": "/",
|
||||||
"lang": "en",
|
"lang": "en",
|
||||||
"theme_color": "#000000",
|
"theme_color": "#000000",
|
||||||
"shortcuts": [
|
"shortcuts": [
|
||||||
|
@ -3,9 +3,9 @@ import {
|
|||||||
isTriggerActionMessageEvent,
|
isTriggerActionMessageEvent,
|
||||||
removeActionMessage,
|
removeActionMessage,
|
||||||
triggerActionMessage,
|
triggerActionMessage,
|
||||||
} from './TriggerActionMessageEvent';
|
} from "./TriggerActionMessageEvent";
|
||||||
|
|
||||||
import * as tg from 'generic-type-guard';
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
const isTriggerMessageEventObject = new tg.IsInterface()
|
const isTriggerMessageEventObject = new tg.IsInterface()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
||||||
import {layoutManagerVisibilityStore} from "../Stores/LayoutManagerStore";
|
import {layoutManagerVisibilityStore} from "../Stores/LayoutManagerStore";
|
||||||
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
|
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
|
||||||
|
import {audioManagerVisibilityStore} from "../Stores/AudioManagerStore";
|
||||||
|
import AudioManager from "./AudioManager/AudioManager.svelte"
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
|
|
||||||
@ -81,6 +83,11 @@
|
|||||||
<AudioPlaying url={$soundPlayingStore} />
|
<AudioPlaying url={$soundPlayingStore} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $audioManagerVisibilityStore}
|
||||||
|
<div>
|
||||||
|
<AudioManager></AudioManager>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if $layoutManagerVisibilityStore}
|
{#if $layoutManagerVisibilityStore}
|
||||||
<div>
|
<div>
|
||||||
<LayoutManager></LayoutManager>
|
<LayoutManager></LayoutManager>
|
||||||
|
189
front/src/Components/AudioManager/AudioManager.svelte
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
|
import type {audioManagerVolume} from "../../Stores/AudioManagerStore";
|
||||||
|
import {
|
||||||
|
audioManagerFileStore,
|
||||||
|
audioManagerVolumeStore,
|
||||||
|
} from "../../Stores/AudioManagerStore";
|
||||||
|
import {get} from "svelte/store";
|
||||||
|
import type {Unsubscriber} from "svelte/store";
|
||||||
|
import {onDestroy,onMount} from "svelte";
|
||||||
|
|
||||||
|
let HTMLAudioPlayer: HTMLAudioElement;
|
||||||
|
let audioPlayerVolumeIcon: HTMLElement;
|
||||||
|
let audioPlayerVol: HTMLInputElement;
|
||||||
|
let unsubscriberFileStore: Unsubscriber|null=null;
|
||||||
|
let unsubscriberVolumeStore: Unsubscriber|null=null;
|
||||||
|
|
||||||
|
let volume: number=1;
|
||||||
|
let decreaseWhileTalking: boolean=true;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
unsubscriberFileStore=audioManagerFileStore.subscribe(() => {
|
||||||
|
HTMLAudioPlayer.pause();
|
||||||
|
HTMLAudioPlayer.loop=get(audioManagerVolumeStore).loop;
|
||||||
|
HTMLAudioPlayer.volume=get(audioManagerVolumeStore).volume;
|
||||||
|
HTMLAudioPlayer.muted=get(audioManagerVolumeStore).muted;
|
||||||
|
HTMLAudioPlayer.play();
|
||||||
|
});
|
||||||
|
unsubscriberVolumeStore=audioManagerVolumeStore.subscribe((audioManager: audioManagerVolume) => {
|
||||||
|
const reduceVolume=audioManager.talking&&audioManager.decreaseWhileTalking;
|
||||||
|
if(reduceVolume&&!audioManager.volumeReduced) {
|
||||||
|
audioManager.volume*=0.5;
|
||||||
|
} else if(!reduceVolume&&audioManager.volumeReduced) {
|
||||||
|
audioManager.volume*=2.0;
|
||||||
|
}
|
||||||
|
audioManager.volumeReduced=reduceVolume;
|
||||||
|
HTMLAudioPlayer.volume=audioManager.volume;
|
||||||
|
HTMLAudioPlayer.muted=audioManager.muted;
|
||||||
|
HTMLAudioPlayer.loop=audioManager.loop;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if(unsubscriberFileStore) {
|
||||||
|
unsubscriberFileStore();
|
||||||
|
}
|
||||||
|
if(unsubscriberVolumeStore) {
|
||||||
|
unsubscriberVolumeStore();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function onMute() {
|
||||||
|
audioManagerVolumeStore.setMuted(!get(audioManagerVolumeStore).muted);
|
||||||
|
localUserStore.setAudioPlayerMuted(get(audioManagerVolumeStore).muted);
|
||||||
|
setVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setVolume() {
|
||||||
|
if(get(audioManagerVolumeStore).muted) {
|
||||||
|
audioPlayerVolumeIcon.classList.add('muted');
|
||||||
|
audioPlayerVol.value="0";
|
||||||
|
} else {
|
||||||
|
audioPlayerVol.value=""+volume;
|
||||||
|
audioPlayerVolumeIcon.classList.remove('muted');
|
||||||
|
if(volume<0.3) {
|
||||||
|
audioPlayerVolumeIcon.classList.add('low');
|
||||||
|
} else if(volume<0.7) {
|
||||||
|
audioPlayerVolumeIcon.classList.remove('low');
|
||||||
|
audioPlayerVolumeIcon.classList.add('mid');
|
||||||
|
} else {
|
||||||
|
audioPlayerVolumeIcon.classList.remove('low');
|
||||||
|
audioPlayerVolumeIcon.classList.remove('mid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
audioManagerVolumeStore.setVolume(volume)
|
||||||
|
localUserStore.setAudioPlayerVolume(get(audioManagerVolumeStore).volume);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDecrease() {
|
||||||
|
audioManagerVolumeStore.setDecreaseWhileTalking(decreaseWhileTalking);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="main-audio-manager nes-container is-rounded">
|
||||||
|
<div class="audio-manager-player-volume">
|
||||||
|
<span id="audioplayer_volume_icon_playing" alt="player volume" bind:this={audioPlayerVolumeIcon}
|
||||||
|
on:click={onMute}>
|
||||||
|
<svg width="2em" height="2em" viewBox="0 0 16 16" class="bi bi-volume-up" fill="white"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd"
|
||||||
|
d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04L4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96V5.04z" />
|
||||||
|
<g id="audioplayer_volume_icon_playing_high">
|
||||||
|
<path
|
||||||
|
d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303l.708.707z" />
|
||||||
|
</g>
|
||||||
|
<g id="audioplayer_volume_icon_playing_mid">
|
||||||
|
<path
|
||||||
|
d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89l.706.706z" />
|
||||||
|
</g>
|
||||||
|
<g id="audioplayer_volume_icon_playing_low">
|
||||||
|
<path
|
||||||
|
d="M8.707 11.182A4.486 4.486 0 0 0 10.025 8a4.486 4.486 0 0 0-1.318-3.182L8 5.525A3.489 3.489 0 0 1 9.025 8 3.49 3.49 0 0 1 8 10.475l.707.707z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<input type="range" min="0" max="1" step="0.025" bind:value={volume} bind:this={audioPlayerVol}
|
||||||
|
on:change={setVolume}>
|
||||||
|
</div>
|
||||||
|
<div class="audio-manager-reduce-conversation">
|
||||||
|
<label>
|
||||||
|
reduce in conversations
|
||||||
|
<input type="checkbox" bind:checked={decreaseWhileTalking} on:change={setDecrease}>
|
||||||
|
</label>
|
||||||
|
<section class="audio-manager-file">
|
||||||
|
<audio class="audio-manager-audioplayer" bind:this={HTMLAudioPlayer}>
|
||||||
|
<source src={$audioManagerFileStore}>
|
||||||
|
</audio>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.main-audio-manager.nes-container.is-rounded {
|
||||||
|
position: relative;
|
||||||
|
top: 0.5rem;
|
||||||
|
max-height: clamp(150px, 10vh, 15vh); //replace @media for small screen
|
||||||
|
width: clamp(200px, 15vw, 15vw);
|
||||||
|
padding: 3px 3px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
|
||||||
|
background-color: rgb(0, 0, 0, 0.5);
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 50% 50%;
|
||||||
|
color: whitesmoke;
|
||||||
|
text-align: center;
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
div.audio-manager-player-volume {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50px 1fr;
|
||||||
|
|
||||||
|
span svg {
|
||||||
|
height: 100%;
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.audio-manager-file {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#audioplayer_volume_icon_playing.muted {
|
||||||
|
#audioplayer_volume_icon_playing_low {
|
||||||
|
visibility: hidden;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#audioplayer_volume_icon_playing_mid {
|
||||||
|
visibility: hidden;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#audioplayer_volume_icon_playing_high {
|
||||||
|
visibility: hidden;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#audioplayer_volume_icon_playing.low #audioplayer_volume_icon_playing_high {
|
||||||
|
visibility: hidden;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#audioplayer_volume_icon_playing.low #audioplayer_volume_icon_playing_mid {
|
||||||
|
visibility: hidden;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#audioplayer_volume_icon_playing.mid #audioplayer_volume_icon_playing_high {
|
||||||
|
visibility: hidden;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
3
front/src/Components/images/audio-mute.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="2em" height="2em" viewBox="0 0 16 16" class="bi bi-volume-up" fill="white" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04L4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96V5.04z" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 376 B |
8
front/src/Components/images/audio.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<svg width="2em" height="2em" viewBox="0 0 16 16" class="bi bi-volume-up" fill="white" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04L4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96V5.04z" />
|
||||||
|
<g>
|
||||||
|
<path d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303l.708.707z" />
|
||||||
|
<path d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89l.706.706z" />
|
||||||
|
<path d="M8.707 11.182A4.486 4.486 0 0 0 10.025 8a4.486 4.486 0 0 0-1.318-3.182L8 5.525A3.489 3.489 0 0 1 9.025 8 3.49 3.49 0 0 1 8 10.475l.707.707z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 885 B |
@ -76,7 +76,17 @@ class ConnectionManager {
|
|||||||
);
|
);
|
||||||
localUserStore.setAuthToken(authToken);
|
localUserStore.setAuthToken(authToken);
|
||||||
this.authToken = authToken;
|
this.authToken = authToken;
|
||||||
room = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
|
|
||||||
|
let roomPath: string;
|
||||||
|
|
||||||
|
roomPath = window.location.protocol + "//" + window.location.host + START_ROOM_URL;
|
||||||
|
|
||||||
|
const lastRoomUrl = localUserStore.getLastRoomUrl();
|
||||||
|
if (lastRoomUrl != undefined && lastRoomUrl != "") {
|
||||||
|
roomPath = lastRoomUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
room = await Room.createRoom(new URL(roomPath));
|
||||||
urlManager.pushRoomIdToUrl(room);
|
urlManager.pushRoomIdToUrl(room);
|
||||||
} else if (connexionType === GameConnexionTypes.register) {
|
} else if (connexionType === GameConnexionTypes.register) {
|
||||||
//@deprecated
|
//@deprecated
|
||||||
@ -111,12 +121,22 @@ class ConnectionManager {
|
|||||||
//todo: add here some kind of warning if authToken has expired.
|
//todo: add here some kind of warning if authToken has expired.
|
||||||
if (!this.authToken) {
|
if (!this.authToken) {
|
||||||
await this.anonymousLogin();
|
await this.anonymousLogin();
|
||||||
|
// this.loadOpenIDScreen();
|
||||||
}
|
}
|
||||||
this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null
|
this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null
|
||||||
|
|
||||||
let roomPath: string;
|
let roomPath: string;
|
||||||
if (connexionType === GameConnexionTypes.empty) {
|
if (connexionType === GameConnexionTypes.empty) {
|
||||||
roomPath = window.location.protocol + "//" + window.location.host + START_ROOM_URL;
|
roomPath = window.location.protocol + "//" + window.location.host + START_ROOM_URL;
|
||||||
|
//get last room path from cache api
|
||||||
|
try {
|
||||||
|
const lastRoomUrl = await localUserStore.getLastRoomUrlCacheApi();
|
||||||
|
if (lastRoomUrl != undefined) {
|
||||||
|
roomPath = lastRoomUrl;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
roomPath =
|
roomPath =
|
||||||
window.location.protocol +
|
window.location.protocol +
|
||||||
|
@ -17,6 +17,8 @@ const authToken = "authToken";
|
|||||||
const state = "state";
|
const state = "state";
|
||||||
const nonce = "nonce";
|
const nonce = "nonce";
|
||||||
|
|
||||||
|
const cacheAPIIndex = "workavdenture-cache-v1";
|
||||||
|
|
||||||
class LocalUserStore {
|
class LocalUserStore {
|
||||||
saveUser(localUser: LocalUser) {
|
saveUser(localUser: LocalUser) {
|
||||||
localStorage.setItem("localUser", JSON.stringify(localUser));
|
localStorage.setItem("localUser", JSON.stringify(localUser));
|
||||||
@ -116,10 +118,23 @@ class LocalUserStore {
|
|||||||
|
|
||||||
setLastRoomUrl(roomUrl: string): void {
|
setLastRoomUrl(roomUrl: string): void {
|
||||||
localStorage.setItem(lastRoomUrl, roomUrl.toString());
|
localStorage.setItem(lastRoomUrl, roomUrl.toString());
|
||||||
|
caches.open(cacheAPIIndex).then((cache) => {
|
||||||
|
const stringResponse = new Response(JSON.stringify({ roomUrl }));
|
||||||
|
cache.put(`/${lastRoomUrl}`, stringResponse);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
getLastRoomUrl(): string {
|
getLastRoomUrl(): string {
|
||||||
return localStorage.getItem(lastRoomUrl) ?? "";
|
return localStorage.getItem(lastRoomUrl) ?? "";
|
||||||
}
|
}
|
||||||
|
getLastRoomUrlCacheApi(): Promise<string | undefined> {
|
||||||
|
return caches.open(cacheAPIIndex).then((cache) => {
|
||||||
|
return cache.match(`/${lastRoomUrl}`).then((res) => {
|
||||||
|
return res?.json().then((data) => {
|
||||||
|
return data.roomUrl;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setAuthToken(value: string | null) {
|
setAuthToken(value: string | null) {
|
||||||
value ? localStorage.setItem(authToken, value) : localStorage.removeItem(authToken);
|
value ? localStorage.setItem(authToken, value) : localStorage.removeItem(authToken);
|
||||||
|
@ -6,15 +6,13 @@ export class _ServiceWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
window.addEventListener("load", () => {
|
|
||||||
navigator.serviceWorker
|
navigator.serviceWorker
|
||||||
.register("/resources/service-worker.js")
|
.register("/service-worker.js")
|
||||||
.then((serviceWorker) => {
|
.then((serviceWorker) => {
|
||||||
console.info("Service Worker registered: ", serviceWorker);
|
console.info("Service Worker registered: ", serviceWorker);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Error registering the Service Worker: ", error);
|
console.error("Error registering the Service Worker: ", error);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import VirtualJoystick from 'phaser3-rex-plugins/plugins/virtualjoystick.js';
|
import VirtualJoystick from "phaser3-rex-plugins/plugins/virtualjoystick.js";
|
||||||
import {waScaleManager} from "../Services/WaScaleManager";
|
import { waScaleManager } from "../Services/WaScaleManager";
|
||||||
import {DEPTH_INGAME_TEXT_INDEX} from "../Game/DepthIndexes";
|
import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes";
|
||||||
|
|
||||||
//the assets were found here: https://hannemann.itch.io/virtual-joystick-pack-free
|
//the assets were found here: https://hannemann.itch.io/virtual-joystick-pack-free
|
||||||
export const joystickBaseKey = 'joystickBase';
|
export const joystickBaseKey = "joystickBase";
|
||||||
export const joystickBaseImg = 'resources/objects/joystickSplitted.png';
|
export const joystickBaseImg = "resources/objects/joystickSplitted.png";
|
||||||
export const joystickThumbKey = 'joystickThumb';
|
export const joystickThumbKey = "joystickThumb";
|
||||||
export const joystickThumbImg = 'resources/objects/smallHandleFilledGrey.png';
|
export const joystickThumbImg = "resources/objects/smallHandleFilledGrey.png";
|
||||||
|
|
||||||
const baseSize = 50;
|
const baseSize = 50;
|
||||||
const thumbSize = 25;
|
const thumbSize = 25;
|
||||||
@ -20,15 +20,27 @@ export class MobileJoystick extends VirtualJoystick {
|
|||||||
x: -1000,
|
x: -1000,
|
||||||
y: -1000,
|
y: -1000,
|
||||||
radius: radius * window.devicePixelRatio,
|
radius: radius * window.devicePixelRatio,
|
||||||
base: scene.add.image(0, 0, joystickBaseKey).setDisplaySize(baseSize * window.devicePixelRatio, baseSize * window.devicePixelRatio).setDepth(DEPTH_INGAME_TEXT_INDEX),
|
base: scene.add
|
||||||
thumb: scene.add.image(0, 0, joystickThumbKey).setDisplaySize(thumbSize * window.devicePixelRatio, thumbSize * window.devicePixelRatio).setDepth(DEPTH_INGAME_TEXT_INDEX),
|
.image(0, 0, joystickBaseKey)
|
||||||
|
.setDisplaySize(
|
||||||
|
(baseSize / waScaleManager.zoomModifier) * window.devicePixelRatio,
|
||||||
|
(baseSize / waScaleManager.zoomModifier) * window.devicePixelRatio
|
||||||
|
)
|
||||||
|
.setDepth(DEPTH_INGAME_TEXT_INDEX),
|
||||||
|
thumb: scene.add
|
||||||
|
.image(0, 0, joystickThumbKey)
|
||||||
|
.setDisplaySize(
|
||||||
|
(thumbSize / waScaleManager.zoomModifier) * window.devicePixelRatio,
|
||||||
|
(thumbSize / waScaleManager.zoomModifier) * window.devicePixelRatio
|
||||||
|
)
|
||||||
|
.setDepth(DEPTH_INGAME_TEXT_INDEX),
|
||||||
enable: true,
|
enable: true,
|
||||||
dir: "8dir",
|
dir: "8dir",
|
||||||
});
|
});
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
this.enable = false;
|
this.enable = false;
|
||||||
|
|
||||||
this.scene.input.on('pointerdown', (pointer: Phaser.Input.Pointer) => {
|
this.scene.input.on("pointerdown", (pointer: Phaser.Input.Pointer) => {
|
||||||
if (!pointer.wasTouch) {
|
if (!pointer.wasTouch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -44,7 +56,7 @@ export class MobileJoystick extends VirtualJoystick {
|
|||||||
this.enable = false;
|
this.enable = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.scene.input.on('pointerup', () => {
|
this.scene.input.on("pointerup", () => {
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
this.enable = false;
|
this.enable = false;
|
||||||
});
|
});
|
||||||
@ -52,10 +64,16 @@ export class MobileJoystick extends VirtualJoystick {
|
|||||||
this.scene.scale.on(Phaser.Scale.Events.RESIZE, this.resizeCallback);
|
this.scene.scale.on(Phaser.Scale.Events.RESIZE, this.resizeCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private resize() {
|
public resize() {
|
||||||
this.base.setDisplaySize(baseSize / waScaleManager.zoomModifier * window.devicePixelRatio, baseSize / waScaleManager.zoomModifier * window.devicePixelRatio);
|
this.base.setDisplaySize(this.getDisplaySizeByElement(baseSize), this.getDisplaySizeByElement(baseSize));
|
||||||
this.thumb.setDisplaySize(thumbSize / waScaleManager.zoomModifier * window.devicePixelRatio, thumbSize / waScaleManager.zoomModifier * window.devicePixelRatio);
|
this.thumb.setDisplaySize(this.getDisplaySizeByElement(thumbSize), this.getDisplaySizeByElement(thumbSize));
|
||||||
this.setRadius(radius / waScaleManager.zoomModifier * window.devicePixelRatio);
|
this.setRadius(
|
||||||
|
(radius / (waScaleManager.zoomModifier * waScaleManager.uiScalingFactor)) * window.devicePixelRatio
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDisplaySizeByElement(element: integer): integer {
|
||||||
|
return (element / (waScaleManager.zoomModifier * waScaleManager.uiScalingFactor)) * window.devicePixelRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
|
|
||||||
const IGNORED_KEYS = new Set([
|
|
||||||
'Esc',
|
|
||||||
'Escape',
|
|
||||||
'Alt',
|
|
||||||
'Meta',
|
|
||||||
'Control',
|
|
||||||
'Ctrl',
|
|
||||||
'Space',
|
|
||||||
'Backspace'
|
|
||||||
])
|
|
||||||
|
|
||||||
export class TextInput extends Phaser.GameObjects.BitmapText {
|
|
||||||
private minUnderLineLength = 4;
|
|
||||||
private underLine: Phaser.GameObjects.Text;
|
|
||||||
private domInput = document.createElement('input');
|
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene, x: number, y: number, maxLength: number, text: string,
|
|
||||||
onChange: (text: string) => void) {
|
|
||||||
super(scene, x, y, 'main_font', text, 32);
|
|
||||||
this.setOrigin(0.5).setCenterAlign();
|
|
||||||
this.scene.add.existing(this);
|
|
||||||
|
|
||||||
const style = {fontFamily: 'Arial', fontSize: "32px", color: '#ffffff'};
|
|
||||||
this.underLine = this.scene.add.text(x, y+1, this.getUnderLineBody(text.length), style);
|
|
||||||
this.underLine.setOrigin(0.5);
|
|
||||||
|
|
||||||
this.domInput.maxLength = maxLength;
|
|
||||||
this.domInput.style.opacity = "0";
|
|
||||||
if (text) {
|
|
||||||
this.domInput.value = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.domInput.addEventListener('keydown', event => {
|
|
||||||
if (IGNORED_KEYS.has(event.key)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!/[a-zA-Z0-9:.!&?()+-]/.exec(event.key)) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.domInput.addEventListener('input', (event) => {
|
|
||||||
if (event.defaultPrevented) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.text = this.domInput.value;
|
|
||||||
this.underLine.text = this.getUnderLineBody(this.text.length);
|
|
||||||
onChange(this.text);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.body.append(this.domInput);
|
|
||||||
this.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private getUnderLineBody(textLength:number): string {
|
|
||||||
if (textLength < this.minUnderLineLength) textLength = this.minUnderLineLength;
|
|
||||||
let text = '_______';
|
|
||||||
for (let i = this.minUnderLineLength; i < textLength; i++) {
|
|
||||||
text += '__';
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
getText(): string {
|
|
||||||
return this.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
setX(x: number): this {
|
|
||||||
super.setX(x);
|
|
||||||
this.underLine.x = x;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
setY(y: number): this {
|
|
||||||
super.setY(y);
|
|
||||||
this.underLine.y = y+1;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
focus() {
|
|
||||||
this.domInput.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy(): void {
|
|
||||||
super.destroy();
|
|
||||||
this.domInput.remove();
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,7 +32,6 @@ import type { RoomConnection } from "../../Connexion/RoomConnection";
|
|||||||
import { Room } from "../../Connexion/Room";
|
import { Room } from "../../Connexion/Room";
|
||||||
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||||
import { urlManager } from "../../Url/UrlManager";
|
import { urlManager } from "../../Url/UrlManager";
|
||||||
import { audioManager } from "../../WebRtc/AudioManager";
|
|
||||||
import { TextureError } from "../../Exception/TextureError";
|
import { TextureError } from "../../Exception/TextureError";
|
||||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
@ -84,6 +83,11 @@ import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStor
|
|||||||
import { SharedVariablesManager } from "./SharedVariablesManager";
|
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 {
|
||||||
|
audioManagerFileStore,
|
||||||
|
audioManagerVisibilityStore,
|
||||||
|
audioManagerVolumeStore,
|
||||||
|
} from "../../Stores/AudioManagerStore";
|
||||||
import { PropertyUtils } from "../Map/PropertyUtils";
|
import { PropertyUtils } from "../Map/PropertyUtils";
|
||||||
import Tileset = Phaser.Tilemaps.Tileset;
|
import Tileset = Phaser.Tilemaps.Tileset;
|
||||||
import { userIsAdminStore } from "../../Stores/GameStore";
|
import { userIsAdminStore } from "../../Stores/GameStore";
|
||||||
@ -727,12 +731,12 @@ export class GameScene extends DirtyScene {
|
|||||||
this.simplePeer.registerPeerConnectionListener({
|
this.simplePeer.registerPeerConnectionListener({
|
||||||
onConnect(peer) {
|
onConnect(peer) {
|
||||||
//self.openChatIcon.setVisible(true);
|
//self.openChatIcon.setVisible(true);
|
||||||
audioManager.decreaseVolume();
|
audioManagerVolumeStore.setTalking(true);
|
||||||
},
|
},
|
||||||
onDisconnect(userId: number) {
|
onDisconnect(userId: number) {
|
||||||
if (self.simplePeer.getNbConnections() === 0) {
|
if (self.simplePeer.getNbConnections() === 0) {
|
||||||
//self.openChatIcon.setVisible(false);
|
//self.openChatIcon.setVisible(false);
|
||||||
audioManager.restoreVolume();
|
audioManagerVolumeStore.setTalking(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -898,14 +902,16 @@ export class GameScene extends DirtyScene {
|
|||||||
const volume = allProps.get(AUDIO_VOLUME_PROPERTY) as number | undefined;
|
const volume = allProps.get(AUDIO_VOLUME_PROPERTY) as number | undefined;
|
||||||
const loop = allProps.get(AUDIO_LOOP_PROPERTY) as boolean | undefined;
|
const loop = allProps.get(AUDIO_LOOP_PROPERTY) as boolean | undefined;
|
||||||
newValue === undefined
|
newValue === undefined
|
||||||
? audioManager.unloadAudio()
|
? audioManagerFileStore.unloadAudio()
|
||||||
: audioManager.playAudio(newValue, this.getMapDirUrl(), volume, loop);
|
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), volume, loop);
|
||||||
|
audioManagerVisibilityStore.set(!(newValue === undefined));
|
||||||
});
|
});
|
||||||
// TODO: This legacy property should be removed at some point
|
// TODO: This legacy property should be removed at some point
|
||||||
this.gameMap.onPropertyChange("playAudioLoop", (newValue, oldValue) => {
|
this.gameMap.onPropertyChange("playAudioLoop", (newValue, oldValue) => {
|
||||||
newValue === undefined
|
newValue === undefined
|
||||||
? audioManager.unloadAudio()
|
? audioManagerFileStore.unloadAudio()
|
||||||
: audioManager.playAudio(newValue, this.getMapDirUrl(), undefined, true);
|
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), undefined, true);
|
||||||
|
audioManagerVisibilityStore.set(!(newValue === undefined));
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gameMap.onPropertyChange("zone", (newValue, oldValue) => {
|
this.gameMap.onPropertyChange("zone", (newValue, oldValue) => {
|
||||||
@ -1362,7 +1368,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.stopJitsi();
|
this.stopJitsi();
|
||||||
audioManager.unloadAudio();
|
audioManagerFileStore.unloadAudio();
|
||||||
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
||||||
this.connection?.closeConnection();
|
this.connection?.closeConnection();
|
||||||
this.simplePeer?.closeAllConnections();
|
this.simplePeer?.closeAllConnections();
|
||||||
|
105
front/src/Stores/AudioManagerStore.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { get, writable } from "svelte/store";
|
||||||
|
|
||||||
|
export interface audioManagerVolume {
|
||||||
|
muted: boolean;
|
||||||
|
volume: number;
|
||||||
|
decreaseWhileTalking: boolean;
|
||||||
|
volumeReduced: boolean;
|
||||||
|
loop: boolean;
|
||||||
|
talking: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAudioManagerVolumeStore() {
|
||||||
|
const { subscribe, update } = writable<audioManagerVolume>({
|
||||||
|
muted: false,
|
||||||
|
volume: 1,
|
||||||
|
decreaseWhileTalking: true,
|
||||||
|
volumeReduced: false,
|
||||||
|
loop: false,
|
||||||
|
talking: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
setMuted: (newMute: boolean): void => {
|
||||||
|
update((audioPlayerVolume: audioManagerVolume) => {
|
||||||
|
audioPlayerVolume.muted = newMute;
|
||||||
|
return audioPlayerVolume;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setVolume: (newVolume: number): void => {
|
||||||
|
update((audioPlayerVolume: audioManagerVolume) => {
|
||||||
|
audioPlayerVolume.volume = newVolume;
|
||||||
|
return audioPlayerVolume;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setDecreaseWhileTalking: (newDecrease: boolean): void => {
|
||||||
|
update((audioManagerVolume: audioManagerVolume) => {
|
||||||
|
audioManagerVolume.decreaseWhileTalking = newDecrease;
|
||||||
|
return audioManagerVolume;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setVolumeReduced: (newVolumeReduced: boolean): void => {
|
||||||
|
update((audioManagerVolume: audioManagerVolume) => {
|
||||||
|
audioManagerVolume.volumeReduced = newVolumeReduced;
|
||||||
|
return audioManagerVolume;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setLoop: (newLoop: boolean): void => {
|
||||||
|
update((audioManagerVolume: audioManagerVolume) => {
|
||||||
|
audioManagerVolume.loop = newLoop;
|
||||||
|
return audioManagerVolume;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setTalking: (newTalk: boolean): void => {
|
||||||
|
update((audioManagerVolume: audioManagerVolume) => {
|
||||||
|
audioManagerVolume.talking = newTalk;
|
||||||
|
return audioManagerVolume;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAudioManagerFileStore() {
|
||||||
|
const { subscribe, update } = writable<string>("");
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
playAudio: (
|
||||||
|
url: string | number | boolean,
|
||||||
|
mapDirUrl: string,
|
||||||
|
volume: number | undefined,
|
||||||
|
loop = false
|
||||||
|
): void => {
|
||||||
|
update((file: string) => {
|
||||||
|
const audioPath = url as string;
|
||||||
|
|
||||||
|
if (audioPath.indexOf("://") > 0) {
|
||||||
|
// remote file or stream
|
||||||
|
file = audioPath;
|
||||||
|
} else {
|
||||||
|
// local file, include it relative to map directory
|
||||||
|
file = mapDirUrl + "/" + url;
|
||||||
|
}
|
||||||
|
audioManagerVolumeStore.setVolume(
|
||||||
|
volume ? Math.min(volume, get(audioManagerVolumeStore).volume) : get(audioManagerVolumeStore).volume
|
||||||
|
);
|
||||||
|
audioManagerVolumeStore.setLoop(loop);
|
||||||
|
|
||||||
|
return file;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
unloadAudio: () => {
|
||||||
|
update((file: string) => {
|
||||||
|
audioManagerVolumeStore.setLoop(false);
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const audioManagerVisibilityStore = writable(false);
|
||||||
|
|
||||||
|
export const audioManagerVolumeStore = createAudioManagerVolumeStore();
|
||||||
|
|
||||||
|
export const audioManagerFileStore = createAudioManagerFileStore();
|
@ -1,196 +0,0 @@
|
|||||||
import {HtmlUtils} from "./HtmlUtils";
|
|
||||||
import {isUndefined} from "generic-type-guard";
|
|
||||||
import {localUserStore} from "../Connexion/LocalUserStore";
|
|
||||||
|
|
||||||
enum audioStates {
|
|
||||||
closed = 0,
|
|
||||||
loading = 1,
|
|
||||||
playing = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
const audioPlayerDivId = "audioplayer";
|
|
||||||
const audioPlayerCtrlId = "audioplayerctrl";
|
|
||||||
const audioPlayerVolId = "audioplayer_volume";
|
|
||||||
const audioPlayerVolumeIconId = "audioplayer_volume_icon_playing";
|
|
||||||
const animationTime = 500;
|
|
||||||
|
|
||||||
class AudioManager {
|
|
||||||
private opened = audioStates.closed;
|
|
||||||
|
|
||||||
private audioPlayerDiv: HTMLDivElement;
|
|
||||||
private audioPlayerCtrl: HTMLDivElement;
|
|
||||||
private audioPlayerElem: HTMLAudioElement | undefined;
|
|
||||||
private audioPlayerVol: HTMLInputElement;
|
|
||||||
private audioPlayerVolumeIcon: HTMLInputElement;
|
|
||||||
|
|
||||||
private volume = 1;
|
|
||||||
private muted = false;
|
|
||||||
private decreaseWhileTalking = true;
|
|
||||||
private volumeReduced = false;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.audioPlayerDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(audioPlayerDivId);
|
|
||||||
this.audioPlayerCtrl = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(audioPlayerCtrlId);
|
|
||||||
this.audioPlayerVol = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(audioPlayerVolId);
|
|
||||||
this.audioPlayerVolumeIcon = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(audioPlayerVolumeIconId);
|
|
||||||
|
|
||||||
this.volume = localUserStore.getAudioPlayerVolume();
|
|
||||||
this.audioPlayerVol.value = '' + this.volume;
|
|
||||||
|
|
||||||
this.muted = localUserStore.getAudioPlayerMuted();
|
|
||||||
}
|
|
||||||
|
|
||||||
public playAudio(url: string|number|boolean, mapDirUrl: string, volume: number|undefined, loop=false): void {
|
|
||||||
const audioPath = url as string;
|
|
||||||
let realAudioPath = '';
|
|
||||||
|
|
||||||
if (audioPath.indexOf('://') > 0) {
|
|
||||||
// remote file or stream
|
|
||||||
realAudioPath = audioPath;
|
|
||||||
} else {
|
|
||||||
// local file, include it relative to map directory
|
|
||||||
realAudioPath = mapDirUrl + '/' + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loadAudio(realAudioPath, volume);
|
|
||||||
|
|
||||||
if (loop) {
|
|
||||||
this.loop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private close(): void {
|
|
||||||
this.audioPlayerCtrl.classList.remove('loading');
|
|
||||||
this.audioPlayerCtrl.classList.add('hidden');
|
|
||||||
this.opened = audioStates.closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private load(): void {
|
|
||||||
this.audioPlayerCtrl.classList.remove('hidden');
|
|
||||||
this.audioPlayerCtrl.classList.add('loading');
|
|
||||||
this.opened = audioStates.loading;
|
|
||||||
}
|
|
||||||
|
|
||||||
private open(): void {
|
|
||||||
this.audioPlayerCtrl.classList.remove('hidden', 'loading');
|
|
||||||
this.opened = audioStates.playing;
|
|
||||||
}
|
|
||||||
|
|
||||||
private changeVolume(talking = false): void {
|
|
||||||
if (isUndefined(this.audioPlayerElem)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const reduceVolume = talking && this.decreaseWhileTalking;
|
|
||||||
if (reduceVolume && !this.volumeReduced) {
|
|
||||||
this.volume *= 0.5;
|
|
||||||
} else if (!reduceVolume && this.volumeReduced) {
|
|
||||||
this.volume *= 2.0;
|
|
||||||
}
|
|
||||||
this.volumeReduced = reduceVolume;
|
|
||||||
|
|
||||||
this.audioPlayerElem.volume = this.volume;
|
|
||||||
if (this.muted) {
|
|
||||||
this.audioPlayerVol.value = '0';
|
|
||||||
this.audioPlayerVolumeIcon.classList.add('muted');
|
|
||||||
} else {
|
|
||||||
this.audioPlayerVol.value = '' + this.volume;
|
|
||||||
this.audioPlayerVolumeIcon.classList.remove('muted');
|
|
||||||
if (this.volume < 0.3) {
|
|
||||||
this.audioPlayerVolumeIcon.classList.add('low');
|
|
||||||
} else if (this.volume < 0.7) {
|
|
||||||
this.audioPlayerVolumeIcon.classList.remove('low');
|
|
||||||
this.audioPlayerVolumeIcon.classList.add('mid');
|
|
||||||
} else {
|
|
||||||
this.audioPlayerVolumeIcon.classList.remove('low');
|
|
||||||
this.audioPlayerVolumeIcon.classList.remove('mid');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.audioPlayerElem.muted = this.muted;
|
|
||||||
}
|
|
||||||
|
|
||||||
private setVolume(volume: number): void {
|
|
||||||
this.volume = volume;
|
|
||||||
localUserStore.setAudioPlayerVolume(volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadAudio(url: string, volume: number|undefined): void {
|
|
||||||
this.load();
|
|
||||||
|
|
||||||
/* Solution 1, remove whole audio player */
|
|
||||||
this.audioPlayerDiv.innerHTML = ''; // necessary, if switching from one audio context to another! (else both streams would play simultaneously)
|
|
||||||
|
|
||||||
this.audioPlayerElem = document.createElement('audio');
|
|
||||||
this.audioPlayerElem.id = 'audioplayerelem';
|
|
||||||
this.audioPlayerElem.controls = false;
|
|
||||||
this.audioPlayerElem.preload = 'none';
|
|
||||||
|
|
||||||
const srcElem = document.createElement('source');
|
|
||||||
srcElem.type = "audio/mp3";
|
|
||||||
srcElem.src = url;
|
|
||||||
|
|
||||||
this.audioPlayerElem.append(srcElem);
|
|
||||||
|
|
||||||
this.audioPlayerDiv.append(this.audioPlayerElem);
|
|
||||||
this.volume = volume ? Math.min(volume, this.volume) : this.volume;
|
|
||||||
this.changeVolume();
|
|
||||||
this.audioPlayerElem.play();
|
|
||||||
|
|
||||||
const muteElem = HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_mute');
|
|
||||||
muteElem.onclick = (ev: Event) => {
|
|
||||||
this.muted = !this.muted;
|
|
||||||
this.changeVolume();
|
|
||||||
localUserStore.setAudioPlayerMuted(this.muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.audioPlayerVol.oninput = (ev: Event)=> {
|
|
||||||
this.setVolume(parseFloat((<HTMLInputElement>ev.currentTarget).value));
|
|
||||||
this.muted = false;
|
|
||||||
this.changeVolume();
|
|
||||||
localUserStore.setAudioPlayerMuted(this.muted);
|
|
||||||
|
|
||||||
(<HTMLInputElement>ev.currentTarget).blur();
|
|
||||||
}
|
|
||||||
|
|
||||||
const decreaseElem = HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_decrease_while_talking');
|
|
||||||
decreaseElem.oninput = (ev: Event)=> {
|
|
||||||
this.decreaseWhileTalking = (<HTMLInputElement>ev.currentTarget).checked;
|
|
||||||
this.changeVolume();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
private loop(): void {
|
|
||||||
if (this.audioPlayerElem !== undefined) {
|
|
||||||
this.audioPlayerElem.loop = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unloadAudio(): void {
|
|
||||||
try {
|
|
||||||
const audioElem = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('audioplayerelem');
|
|
||||||
this.volume = audioElem.volume;
|
|
||||||
this.muted = audioElem.muted;
|
|
||||||
audioElem.pause();
|
|
||||||
audioElem.loop = false;
|
|
||||||
audioElem.src = "";
|
|
||||||
audioElem.innerHTML = "";
|
|
||||||
audioElem.load();
|
|
||||||
} catch (e) {
|
|
||||||
console.log('No audio element loaded to unload');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public decreaseVolume(): void {
|
|
||||||
this.changeVolume(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public restoreVolume(): void {
|
|
||||||
this.changeVolume(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const audioManager = new AudioManager();
|
|
@ -1,7 +1,8 @@
|
|||||||
import {HtmlUtils} from "./HtmlUtils";
|
import { HtmlUtils } from "./HtmlUtils";
|
||||||
import {Subject} from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import {iframeListener} from "../Api/IframeListener";
|
import { iframeListener } from "../Api/IframeListener";
|
||||||
import {touchScreenManager} from "../Touch/TouchScreenManager";
|
import { touchScreenManager } from "../Touch/TouchScreenManager";
|
||||||
|
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
|
||||||
|
|
||||||
enum iframeStates {
|
enum iframeStates {
|
||||||
closed = 1,
|
closed = 1,
|
||||||
@ -9,13 +10,13 @@ enum iframeStates {
|
|||||||
opened,
|
opened,
|
||||||
}
|
}
|
||||||
|
|
||||||
const cowebsiteDivId = 'cowebsite'; // the id of the whole container.
|
const cowebsiteDivId = "cowebsite"; // the id of the whole container.
|
||||||
const cowebsiteMainDomId = 'cowebsite-main'; // the id of the parent div of the iframe.
|
const cowebsiteMainDomId = "cowebsite-main"; // the id of the parent div of the iframe.
|
||||||
const cowebsiteAsideDomId = 'cowebsite-aside'; // the id of the parent div of the iframe.
|
const cowebsiteAsideDomId = "cowebsite-aside"; // the id of the parent div of the iframe.
|
||||||
export const cowebsiteCloseButtonId = 'cowebsite-close';
|
export const cowebsiteCloseButtonId = "cowebsite-close";
|
||||||
const cowebsiteFullScreenButtonId = 'cowebsite-fullscreen';
|
const cowebsiteFullScreenButtonId = "cowebsite-fullscreen";
|
||||||
const cowebsiteOpenFullScreenImageId = 'cowebsite-fullscreen-open';
|
const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open";
|
||||||
const cowebsiteCloseFullScreenImageId = 'cowebsite-fullscreen-close';
|
const cowebsiteCloseFullScreenImageId = "cowebsite-fullscreen-close";
|
||||||
const animationTime = 500; //time used by the css transitions, in ms.
|
const animationTime = 500; //time used by the css transitions, in ms.
|
||||||
|
|
||||||
interface TouchMoveCoordinates {
|
interface TouchMoveCoordinates {
|
||||||
@ -24,7 +25,6 @@ interface TouchMoveCoordinates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CoWebsiteManager {
|
class CoWebsiteManager {
|
||||||
|
|
||||||
private opened: iframeStates = iframeStates.closed;
|
private opened: iframeStates = iframeStates.closed;
|
||||||
|
|
||||||
private _onResize: Subject<void> = new Subject();
|
private _onResize: Subject<void> = new Subject();
|
||||||
@ -38,14 +38,14 @@ class CoWebsiteManager {
|
|||||||
private resizing: boolean = false;
|
private resizing: boolean = false;
|
||||||
private cowebsiteMainDom: HTMLDivElement;
|
private cowebsiteMainDom: HTMLDivElement;
|
||||||
private cowebsiteAsideDom: HTMLDivElement;
|
private cowebsiteAsideDom: HTMLDivElement;
|
||||||
private previousTouchMoveCoordinates: TouchMoveCoordinates|null = null; //only use on touchscreens to track touch movement
|
private previousTouchMoveCoordinates: TouchMoveCoordinates | null = null; //only use on touchscreens to track touch movement
|
||||||
|
|
||||||
get width(): number {
|
get width(): number {
|
||||||
return this.cowebsiteDiv.clientWidth;
|
return this.cowebsiteDiv.clientWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
set width(width: number) {
|
set width(width: number) {
|
||||||
this.cowebsiteDiv.style.width = width+'px';
|
this.cowebsiteDiv.style.width = width + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
get height(): number {
|
get height(): number {
|
||||||
@ -53,7 +53,7 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set height(height: number) {
|
set height(height: number) {
|
||||||
this.cowebsiteDiv.style.height = height+'px';
|
this.cowebsiteDiv.style.height = height + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
get verticalMode(): boolean {
|
get verticalMode(): boolean {
|
||||||
@ -75,56 +75,55 @@ class CoWebsiteManager {
|
|||||||
this.initResizeListeners(false);
|
this.initResizeListeners(false);
|
||||||
|
|
||||||
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
||||||
buttonCloseFrame.addEventListener('click', () => {
|
buttonCloseFrame.addEventListener("click", () => {
|
||||||
buttonCloseFrame.blur();
|
buttonCloseFrame.blur();
|
||||||
this.closeCoWebsite();
|
this.closeCoWebsite();
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
|
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
|
||||||
buttonFullScreenFrame.addEventListener('click', () => {
|
buttonFullScreenFrame.addEventListener("click", () => {
|
||||||
buttonFullScreenFrame.blur();
|
buttonFullScreenFrame.blur();
|
||||||
this.fullscreen();
|
this.fullscreen();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private initResizeListeners(touchMode:boolean) {
|
private initResizeListeners(touchMode: boolean) {
|
||||||
const movecallback = (event:MouseEvent|TouchEvent) => {
|
const movecallback = (event: MouseEvent | TouchEvent) => {
|
||||||
let x, y;
|
let x, y;
|
||||||
if (event.type === 'mousemove') {
|
if (event.type === "mousemove") {
|
||||||
x = (event as MouseEvent).movementX / this.getDevicePixelRatio();
|
x = (event as MouseEvent).movementX / this.getDevicePixelRatio();
|
||||||
y = (event as MouseEvent).movementY / this.getDevicePixelRatio();
|
y = (event as MouseEvent).movementY / this.getDevicePixelRatio();
|
||||||
} else {
|
} else {
|
||||||
const touchEvent = (event as TouchEvent).touches[0];
|
const touchEvent = (event as TouchEvent).touches[0];
|
||||||
const last = {x: touchEvent.pageX, y: touchEvent.pageY};
|
const last = { x: touchEvent.pageX, y: touchEvent.pageY };
|
||||||
const previous = this.previousTouchMoveCoordinates as TouchMoveCoordinates;
|
const previous = this.previousTouchMoveCoordinates as TouchMoveCoordinates;
|
||||||
this.previousTouchMoveCoordinates = last;
|
this.previousTouchMoveCoordinates = last;
|
||||||
x = last.x - previous.x;
|
x = last.x - previous.x;
|
||||||
y = last.y - previous.y;
|
y = last.y - previous.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.verticalMode ? (this.height += y) : (this.width -= x);
|
||||||
this.verticalMode ? this.height += y : this.width -= x;
|
|
||||||
this.fire();
|
this.fire();
|
||||||
}
|
};
|
||||||
|
|
||||||
this.cowebsiteAsideDom.addEventListener( touchMode ? 'touchstart' : 'mousedown', (event) => {
|
this.cowebsiteAsideDom.addEventListener(touchMode ? "touchstart" : "mousedown", (event) => {
|
||||||
this.resizing = true;
|
this.resizing = true;
|
||||||
this.getIframeDom().style.display = 'none';
|
this.getIframeDom().style.display = "none";
|
||||||
if (touchMode) {
|
if (touchMode) {
|
||||||
const touchEvent = (event as TouchEvent).touches[0];
|
const touchEvent = (event as TouchEvent).touches[0];
|
||||||
this.previousTouchMoveCoordinates = {x: touchEvent.pageX, y: touchEvent.pageY};
|
this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY };
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener(touchMode ? 'touchmove' : 'mousemove', movecallback);
|
document.addEventListener(touchMode ? "touchmove" : "mousemove", movecallback);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener(touchMode ? 'touchend' : 'mouseup', (event) => {
|
document.addEventListener(touchMode ? "touchend" : "mouseup", (event) => {
|
||||||
if (!this.resizing) return;
|
if (!this.resizing) return;
|
||||||
if (touchMode) {
|
if (touchMode) {
|
||||||
this.previousTouchMoveCoordinates = null;
|
this.previousTouchMoveCoordinates = null;
|
||||||
}
|
}
|
||||||
document.removeEventListener(touchMode ? 'touchmove' : 'mousemove', movecallback);
|
document.removeEventListener(touchMode ? "touchmove" : "mousemove", movecallback);
|
||||||
this.getIframeDom().style.display = 'block';
|
this.getIframeDom().style.display = "block";
|
||||||
this.resizing = false;
|
this.resizing = false;
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'inline';
|
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'inline';
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'none';
|
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'none';
|
||||||
@ -134,36 +133,34 @@ class CoWebsiteManager {
|
|||||||
private getDevicePixelRatio(): number {
|
private getDevicePixelRatio(): number {
|
||||||
//on chrome engines, movementX and movementY return global screens coordinates while other browser return pixels
|
//on chrome engines, movementX and movementY return global screens coordinates while other browser return pixels
|
||||||
//so on chrome-based browser we need to adjust using 'devicePixelRatio'
|
//so on chrome-based browser we need to adjust using 'devicePixelRatio'
|
||||||
return window.navigator.userAgent.includes('Firefox') ? 1 : window.devicePixelRatio;
|
return window.navigator.userAgent.includes("Firefox") ? 1 : window.devicePixelRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
private close(): void {
|
private close(): void {
|
||||||
this.cowebsiteDiv.classList.remove('loaded'); //edit the css class to trigger the transition
|
this.cowebsiteDiv.classList.remove("loaded"); //edit the css class to trigger the transition
|
||||||
this.cowebsiteDiv.classList.add('hidden');
|
this.cowebsiteDiv.classList.add("hidden");
|
||||||
this.opened = iframeStates.closed;
|
this.opened = iframeStates.closed;
|
||||||
this.resetStyle();
|
this.resetStyle();
|
||||||
}
|
}
|
||||||
private load(): void {
|
private load(): void {
|
||||||
this.cowebsiteDiv.classList.remove('hidden'); //edit the css class to trigger the transition
|
this.cowebsiteDiv.classList.remove("hidden"); //edit the css class to trigger the transition
|
||||||
this.cowebsiteDiv.classList.add('loading');
|
this.cowebsiteDiv.classList.add("loading");
|
||||||
this.opened = iframeStates.loading;
|
this.opened = iframeStates.loading;
|
||||||
}
|
}
|
||||||
private open(): void {
|
private open(): void {
|
||||||
this.cowebsiteDiv.classList.remove('loading', 'hidden'); //edit the css class to trigger the transition
|
this.cowebsiteDiv.classList.remove("loading", "hidden"); //edit the css class to trigger the transition
|
||||||
this.opened = iframeStates.opened;
|
this.opened = iframeStates.opened;
|
||||||
this.resetStyle();
|
this.resetStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetStyle() {
|
public resetStyle() {
|
||||||
this.cowebsiteDiv.style.width = '';
|
this.cowebsiteDiv.style.width = "";
|
||||||
this.cowebsiteDiv.style.height = '';
|
this.cowebsiteDiv.style.height = "";
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'inline';
|
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'none';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getIframeDom(): HTMLIFrameElement {
|
private getIframeDom(): HTMLIFrameElement {
|
||||||
const iframe = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId).querySelector('iframe');
|
const iframe = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId).querySelector("iframe");
|
||||||
if (!iframe) throw new Error('Could not find iframe!');
|
if (!iframe) throw new Error("Could not find iframe!");
|
||||||
return iframe;
|
return iframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,9 +168,9 @@ class CoWebsiteManager {
|
|||||||
this.load();
|
this.load();
|
||||||
this.cowebsiteMainDom.innerHTML = ``;
|
this.cowebsiteMainDom.innerHTML = ``;
|
||||||
|
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement("iframe");
|
||||||
iframe.id = 'cowebsite-iframe';
|
iframe.id = "cowebsite-iframe";
|
||||||
iframe.src = (new URL(url, base)).toString();
|
iframe.src = new URL(url, base).toString();
|
||||||
if (allowPolicy) {
|
if (allowPolicy) {
|
||||||
iframe.allow = allowPolicy;
|
iframe.allow = allowPolicy;
|
||||||
}
|
}
|
||||||
@ -187,15 +184,17 @@ class CoWebsiteManager {
|
|||||||
const onTimeoutPromise = new Promise<void>((resolve) => {
|
const onTimeoutPromise = new Promise<void>((resolve) => {
|
||||||
setTimeout(() => resolve(), 2000);
|
setTimeout(() => resolve(), 2000);
|
||||||
});
|
});
|
||||||
this.currentOperationPromise = this.currentOperationPromise.then(() =>Promise.race([onloadPromise, onTimeoutPromise])).then(() => {
|
this.currentOperationPromise = this.currentOperationPromise
|
||||||
this.cowebsiteMainDom.appendChild(iframe);
|
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
|
||||||
|
.then(() => {
|
||||||
this.open();
|
this.open();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.fire();
|
this.fire();
|
||||||
}, animationTime)
|
}, animationTime);
|
||||||
}).catch((err) => {
|
})
|
||||||
console.error('Error loadCoWebsite => ', err);
|
.catch((err) => {
|
||||||
this.closeCoWebsite()
|
console.error("Error loadCoWebsite => ", err);
|
||||||
|
this.closeCoWebsite();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,57 +204,63 @@ class CoWebsiteManager {
|
|||||||
public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise<void>): void {
|
public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise<void>): void {
|
||||||
this.load();
|
this.load();
|
||||||
this.cowebsiteMainDom.innerHTML = ``;
|
this.cowebsiteMainDom.innerHTML = ``;
|
||||||
this.currentOperationPromise = this.currentOperationPromise.then(() => callback(this.cowebsiteMainDom)).then(() => {
|
this.currentOperationPromise = this.currentOperationPromise
|
||||||
|
.then(() => callback(this.cowebsiteMainDom))
|
||||||
|
.then(() => {
|
||||||
this.open();
|
this.open();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.fire();
|
this.fire();
|
||||||
}, animationTime);
|
}, animationTime);
|
||||||
}).catch((err) => {
|
})
|
||||||
console.error('Error insertCoWebsite => ', err);
|
.catch((err) => {
|
||||||
|
console.error("Error insertCoWebsite => ", err);
|
||||||
this.closeCoWebsite();
|
this.closeCoWebsite();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeCoWebsite(): Promise<void> {
|
public closeCoWebsite(): Promise<void> {
|
||||||
this.currentOperationPromise = this.currentOperationPromise.then(() => new Promise((resolve, reject) => {
|
this.currentOperationPromise = this.currentOperationPromise.then(
|
||||||
if(this.opened === iframeStates.closed) resolve(); //this method may be called twice, in case of iframe error for example
|
() =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
if (this.opened === iframeStates.closed) resolve(); //this method may be called twice, in case of iframe error for example
|
||||||
this.close();
|
this.close();
|
||||||
this.fire();
|
this.fire();
|
||||||
const iframe = this.cowebsiteDiv.querySelector('iframe');
|
const iframe = this.cowebsiteDiv.querySelector("iframe");
|
||||||
if (iframe) {
|
if (iframe) {
|
||||||
iframeListener.unregisterIframe(iframe);
|
iframeListener.unregisterIframe(iframe);
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.cowebsiteMainDom.innerHTML = ``;
|
this.cowebsiteMainDom.innerHTML = ``;
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId).blur();
|
|
||||||
resolve();
|
resolve();
|
||||||
}, animationTime)
|
}, animationTime);
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
return this.currentOperationPromise;
|
return this.currentOperationPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getGameSize(): {width: number, height: number} {
|
public getGameSize(): { width: number; height: number } {
|
||||||
if (this.opened !== iframeStates.opened) {
|
if (this.opened !== iframeStates.opened) {
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight
|
height: window.innerHeight,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
if (!this.verticalMode) {
|
if (!this.verticalMode) {
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth - this.width,
|
width: window.innerWidth - this.width,
|
||||||
height: window.innerHeight
|
height: window.innerHeight,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight - this.height,
|
height: window.innerHeight - this.height,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fire(): void {
|
private fire(): void {
|
||||||
this._onResize.next();
|
this._onResize.next();
|
||||||
|
waScaleManager.applyNewSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private fullscreen(): void {
|
private fullscreen(): void {
|
||||||
@ -263,13 +268,13 @@ class CoWebsiteManager {
|
|||||||
this.resetStyle();
|
this.resetStyle();
|
||||||
this.fire();
|
this.fire();
|
||||||
//we don't trigger a resize of the phaser game since it won't be visible anyway.
|
//we don't trigger a resize of the phaser game since it won't be visible anyway.
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'inline';
|
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = "inline";
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'none';
|
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = "none";
|
||||||
} else {
|
} else {
|
||||||
this.verticalMode ? this.height = window.innerHeight : this.width = window.innerWidth;
|
this.verticalMode ? (this.height = window.innerHeight) : (this.width = window.innerWidth);
|
||||||
//we don't trigger a resize of the phaser game since it won't be visible anyway.
|
//we don't trigger a resize of the phaser game since it won't be visible anyway.
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'none';
|
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = "none";
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'inline';
|
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = "inline";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,92 +386,6 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.audioplayer:first-child {
|
|
||||||
display: grid;
|
|
||||||
grid: 2rem / 4rem 13rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.audioplayer>button,
|
|
||||||
.audioplayer>div,
|
|
||||||
.audioplayer>label {
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 5px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.audioplayer>div {
|
|
||||||
padding: 0;
|
|
||||||
padding-right: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayerctrl {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
right: calc(50% - 120px);
|
|
||||||
padding: 0.3rem 0.5rem;
|
|
||||||
color: white;
|
|
||||||
transition: transform 0.5s;
|
|
||||||
z-index: 99;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayer_mute {
|
|
||||||
max-width: 5rem;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayer_mute:focus,
|
|
||||||
#audioplayer_mute:active {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayer_mute>svg {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayer_volume_icon_playing.muted {
|
|
||||||
visibility: hidden;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayer_volume_icon_playing.low #audioplayer_volume_icon_playing_high {
|
|
||||||
visibility: hidden;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayer_volume_icon_playing.low #audioplayer_volume_icon_playing_mid {
|
|
||||||
visibility: hidden;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayer_volume_icon_playing.mid #audioplayer_volume_icon_playing_high {
|
|
||||||
visibility: hidden;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayerctrl>#audioplayer_volume {
|
|
||||||
width: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* sollte eigentlich in den aspect-ratio teil ..
|
|
||||||
*/
|
|
||||||
|
|
||||||
#audioplayerctrl.loading {
|
|
||||||
transform: translateY(-90%);
|
|
||||||
}
|
|
||||||
|
|
||||||
#audioplayerctrl.hidden {
|
|
||||||
transform: translateY(-100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Style Input Range
|
* Style Input Range
|
||||||
* https://www.cssportal.com/style-input-range/
|
* https://www.cssportal.com/style-input-range/
|
||||||
|
Before Width: | Height: | Size: 20 KiB |
@ -51,11 +51,11 @@ export class AuthenticateController extends BaseController {
|
|||||||
const { code, nonce } = parse(req.getQuery());
|
const { code, nonce } = parse(req.getQuery());
|
||||||
try {
|
try {
|
||||||
const userInfo = await openIDClient.getUserInfo(code as string, nonce as string);
|
const userInfo = await openIDClient.getUserInfo(code as string, nonce as string);
|
||||||
const email = userInfo.email || userInfo.sub;
|
const sub = userInfo.sub;
|
||||||
if (!email) {
|
if (!sub) {
|
||||||
throw new Error("No email in the response");
|
throw new Error("No sub in the response");
|
||||||
}
|
}
|
||||||
const authToken = jwtTokenManager.createAuthToken(email);
|
const authToken = jwtTokenManager.createAuthToken(sub);
|
||||||
res.writeStatus("200");
|
res.writeStatus("200");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
return res.end(JSON.stringify({ authToken }));
|
return res.end(JSON.stringify({ authToken }));
|
||||||
|
@ -307,7 +307,7 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
reportPlayerMessage.getReporteduseruuid(),
|
reportPlayerMessage.getReporteduseruuid(),
|
||||||
reportPlayerMessage.getReportcomment(),
|
reportPlayerMessage.getReportcomment(),
|
||||||
client.userUuid,
|
client.userUuid,
|
||||||
client.roomId.split("/")[2]
|
client.roomId
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('An error occurred on "handleReportMessage"');
|
console.error('An error occurred on "handleReportMessage"');
|
||||||
|