diff --git a/dist/better-xcloud.lite.user.js b/dist/better-xcloud.lite.user.js index 26245c8..53ddc86 100644 --- a/dist/better-xcloud.lite.user.js +++ b/dist/better-xcloud.lite.user.js @@ -3059,6 +3059,8 @@ var BxIcon = { CONTROLLER: "", CREATE_SHORTCUT: "", DISPLAY: "", + EYE: "", + EYE_SLASH: "", HOME: "", NATIVE_MKB: "", NEW: "", diff --git a/dist/better-xcloud.user.js b/dist/better-xcloud.user.js index fad28d7..c183cd6 100644 --- a/dist/better-xcloud.user.js +++ b/dist/better-xcloud.user.js @@ -3342,6 +3342,8 @@ var BxIcon = { CONTROLLER: "", CREATE_SHORTCUT: "", DISPLAY: "", + EYE: "", + EYE_SLASH: "", HOME: "", NATIVE_MKB: "", NEW: "", @@ -7465,6 +7467,38 @@ class SpeakerAction extends BaseGameBarAction { this.$content.dataset.enabled = "true"; } } +class RendererShortcut { + static toggleVisibility() { + const $mediaContainer = document.querySelector('#game-stream div[data-testid="media-container"]'); + if (!$mediaContainer) return !0; + return $mediaContainer.classList.toggle("bx-gone"), !$mediaContainer.classList.contains("bx-gone"); + } +} +class RendererAction extends BaseGameBarAction { + $content; + constructor() { + super(); + const onClick = (e) => { + BxEvent.dispatch(window, BxEvent.GAME_BAR_ACTION_ACTIVATED), this.$content.dataset.enabled = RendererShortcut.toggleVisibility().toString(); + }, $btnDefault = createButton({ + style: 4, + icon: BxIcon.EYE, + onClick + }), $btnActivated = createButton({ + style: 4, + icon: BxIcon.EYE_SLASH, + onClick, + classes: ["bx-activated"] + }); + this.$content = CE("div", {}, $btnDefault, $btnActivated), this.reset(); + } + render() { + return this.$content; + } + reset() { + this.$content.dataset.enabled = "true"; + } +} class GameBar { static instance; static getInstance() { @@ -7474,7 +7508,7 @@ class GameBar { static VISIBLE_DURATION = 2000; $gameBar; $container; - timeout = null; + timeoutId = null; actions = []; constructor() { let $container; @@ -7483,6 +7517,7 @@ class GameBar { new ScreenshotAction, ...STATES.userAgent.capabilities.touch && getPref("stream_touch_controller") !== "off" ? [new TouchControlAction] : [], new SpeakerAction, + new RendererAction, new MicrophoneAction, new TrueAchievementsAction ], position === "bottom-right") @@ -7504,12 +7539,12 @@ class GameBar { }).bind(this)); } beginHideTimeout() { - this.clearHideTimeout(), this.timeout = window.setTimeout(() => { - this.timeout = null, this.hideBar(); + this.clearHideTimeout(), this.timeoutId = window.setTimeout(() => { + this.timeoutId = null, this.hideBar(); }, GameBar.VISIBLE_DURATION); } clearHideTimeout() { - this.timeout && clearTimeout(this.timeout), this.timeout = null; + this.timeoutId && clearTimeout(this.timeoutId), this.timeoutId = null; } enable() { this.$gameBar && this.$gameBar.classList.remove("bx-gone"); diff --git a/src/assets/svg/eye-slash.svg b/src/assets/svg/eye-slash.svg new file mode 100644 index 0000000..68775d2 --- /dev/null +++ b/src/assets/svg/eye-slash.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/svg/eye.svg b/src/assets/svg/eye.svg new file mode 100644 index 0000000..7eae1e6 --- /dev/null +++ b/src/assets/svg/eye.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/modules/game-bar/action-renderer.ts b/src/modules/game-bar/action-renderer.ts new file mode 100644 index 0000000..f43b331 --- /dev/null +++ b/src/modules/game-bar/action-renderer.ts @@ -0,0 +1,47 @@ +import { BxEvent } from "@utils/bx-event"; +import { BxIcon } from "@utils/bx-icon"; +import { createButton, ButtonStyle, CE } from "@utils/html"; +import { BaseGameBarAction } from "./action-base"; +import { RendererShortcut } from "../shortcuts/shortcut-renderer"; + + +export class RendererAction extends BaseGameBarAction { + $content: HTMLElement; + + constructor() { + super(); + + const onClick = (e: Event) => { + BxEvent.dispatch(window, BxEvent.GAME_BAR_ACTION_ACTIVATED); + this.$content.dataset.enabled = RendererShortcut.toggleVisibility().toString(); + }; + + const $btnDefault = createButton({ + style: ButtonStyle.GHOST, + icon: BxIcon.EYE, + onClick: onClick, + }); + + const $btnActivated = createButton({ + style: ButtonStyle.GHOST, + icon: BxIcon.EYE_SLASH, + onClick: onClick, + classes: ['bx-activated'], + }); + + this.$content = CE('div', {}, + $btnDefault, + $btnActivated, + ); + + this.reset(); + } + + render(): HTMLElement { + return this.$content; + } + + reset(): void { + this.$content.dataset.enabled = 'true'; + } +} diff --git a/src/modules/game-bar/game-bar.ts b/src/modules/game-bar/game-bar.ts index 23d1dc9..10e1e13 100644 --- a/src/modules/game-bar/game-bar.ts +++ b/src/modules/game-bar/game-bar.ts @@ -10,6 +10,7 @@ import { PrefKey } from "@/enums/pref-keys"; import { getPref, StreamTouchController } from "@/utils/settings-storages/global-settings-storage"; import { TrueAchievementsAction } from "./action-true-achievements"; import { SpeakerAction } from "./action-speaker"; +import { RendererAction } from "./action-renderer"; export class GameBar { @@ -27,7 +28,7 @@ export class GameBar { private $gameBar: HTMLElement; private $container: HTMLElement; - private timeout: number | null = null; + private timeoutId: number | null = null; private actions: BaseGameBarAction[] = []; @@ -45,6 +46,7 @@ export class GameBar { new ScreenshotAction(), ...(STATES.userAgent.capabilities.touch && (getPref(PrefKey.STREAM_TOUCH_CONTROLLER) !== StreamTouchController.OFF) ? [new TouchControlAction()] : []), new SpeakerAction(), + new RendererAction(), new MicrophoneAction(), new TrueAchievementsAction(), ]; @@ -103,15 +105,15 @@ export class GameBar { private beginHideTimeout() { this.clearHideTimeout(); - this.timeout = window.setTimeout(() => { - this.timeout = null; + this.timeoutId = window.setTimeout(() => { + this.timeoutId = null; this.hideBar(); }, GameBar.VISIBLE_DURATION); } private clearHideTimeout() { - this.timeout && clearTimeout(this.timeout); - this.timeout = null; + this.timeoutId && clearTimeout(this.timeoutId); + this.timeoutId = null; } enable() { diff --git a/src/modules/shortcuts/shortcut-renderer.ts b/src/modules/shortcuts/shortcut-renderer.ts new file mode 100644 index 0000000..765fc12 --- /dev/null +++ b/src/modules/shortcuts/shortcut-renderer.ts @@ -0,0 +1,11 @@ +export class RendererShortcut { + static toggleVisibility(): boolean { + const $mediaContainer = document.querySelector('#game-stream div[data-testid="media-container"]'); + if (!$mediaContainer) { + return true; + } + + $mediaContainer.classList.toggle('bx-gone'); + return !$mediaContainer.classList.contains('bx-gone'); + } +} diff --git a/src/utils/bx-icon.ts b/src/utils/bx-icon.ts index 495d0ac..3c517be 100644 --- a/src/utils/bx-icon.ts +++ b/src/utils/bx-icon.ts @@ -7,6 +7,8 @@ import iconCopy from "@assets/svg/copy.svg" with { type: "text" }; import iconCreateShortcut from "@assets/svg/create-shortcut.svg" with { type: "text" }; import iconCursorText from "@assets/svg/cursor-text.svg" with { type: "text" }; import iconDisplay from "@assets/svg/display.svg" with { type: "text" }; +import iconEye from "@assets/svg/eye.svg" with { type: "text" }; +import iconEyeSlash from "@assets/svg/eye-slash.svg" with { type: "text" }; import iconHome from "@assets/svg/home.svg" with { type: "text" }; import iconNativeMkb from "@assets/svg/native-mkb.svg" with { type: "text" }; import iconNew from "@assets/svg/new.svg" with { type: "text" }; @@ -48,6 +50,8 @@ export const BxIcon = { CONTROLLER: iconController, CREATE_SHORTCUT: iconCreateShortcut, DISPLAY: iconDisplay, + EYE: iconEye, + EYE_SLASH: iconEyeSlash, HOME: iconHome, NATIVE_MKB: iconNativeMkb, NEW: iconNew,