2024-05-11 21:15:22 +07:00

129 lines
3.7 KiB
TypeScript

import { CE, createSvgIcon } from "@utils/html";
import { ScreenshotAction } from "./action-screenshot";
import { TouchControlAction } from "./action-touch-control";
import { BxEvent } from "@utils/bx-event";
import { BxIcon } from "@utils/bx-icon";
import type { BaseGameBarAction } from "./action-base";
import { STATES } from "@utils/global";
import { PrefKey, getPref } from "@utils/preferences";
import { MicrophoneAction } from "./action-microphone";
export class GameBar {
private static instance: GameBar;
public static getInstance(): GameBar {
if (!GameBar.instance) {
GameBar.instance = new GameBar();
}
return GameBar.instance;
}
private static readonly VISIBLE_DURATION = 2000;
private $gameBar: HTMLElement;
private $container: HTMLElement;
private timeout: number | null = null;
private actions: BaseGameBarAction[] = [];
private constructor() {
let $container;
const $gameBar = CE('div', {id: 'bx-game-bar', class: 'bx-gone'},
$container = CE('div', {class: 'bx-game-bar-container bx-offscreen'}),
createSvgIcon(BxIcon.CARET_RIGHT),
);
this.actions = [
new ScreenshotAction(),
...(STATES.hasTouchSupport && (getPref(PrefKey.STREAM_TOUCH_CONTROLLER) !== 'off') ? [new TouchControlAction()] : []),
new MicrophoneAction(),
];
// Render actions
for (const action of this.actions) {
$container.appendChild(action.render());
}
// Toggle game bar when clicking on the game bar box
$gameBar.addEventListener('click', e => {
if (e.target !== $gameBar) {
return;
}
$container.classList.contains('bx-show') ? this.hideBar() : this.showBar();
});
// Hide game bar after clicking on an action
window.addEventListener(BxEvent.GAME_BAR_ACTION_ACTIVATED, this.hideBar.bind(this));
$container.addEventListener('pointerover', this.clearHideTimeout.bind(this));
$container.addEventListener('pointerout', this.beginHideTimeout.bind(this));
// Add animation when hiding game bar
$container.addEventListener('transitionend', e => {
const classList = $container.classList;
if (classList.contains('bx-hide')) {
classList.remove('bx-offscreen', 'bx-hide');
classList.add('bx-offscreen');
}
});
document.documentElement.appendChild($gameBar);
this.$gameBar = $gameBar;
this.$container = $container;
}
private beginHideTimeout() {
this.clearHideTimeout();
this.timeout = window.setTimeout(() => {
this.timeout = null;
this.hideBar();
}, GameBar.VISIBLE_DURATION);
}
private clearHideTimeout() {
this.timeout && clearTimeout(this.timeout);
this.timeout = null;
}
enable() {
this.$gameBar && this.$gameBar.classList.remove('bx-gone');
}
disable() {
this.hideBar();
this.$gameBar && this.$gameBar.classList.add('bx-gone');
}
showBar() {
if (!this.$container) {
return;
}
this.$container.classList.remove('bx-offscreen', 'bx-hide');
this.$container.classList.add('bx-show');
this.beginHideTimeout();
}
hideBar() {
if (!this.$container) {
return;
}
this.$container.classList.remove('bx-show');
this.$container.classList.add('bx-hide');
}
// Reset all states
reset() {
for (const action of this.actions) {
action.reset();
}
}
}