mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-08-12 16:09:16 +02:00
Game-specific settings (#623)
This commit is contained in:
@@ -47,7 +47,7 @@ export class DeviceVibrationManager {
|
||||
}
|
||||
});
|
||||
|
||||
BxEventBus.Script.on('deviceVibration.updated', () => this.setupDataChannel());
|
||||
BxEventBus.Stream.on('deviceVibration.updated', () => this.setupDataChannel());
|
||||
}
|
||||
|
||||
private setupDataChannel() {
|
||||
|
@@ -6,21 +6,21 @@ import { BxIcon } from "@utils/bx-icon";
|
||||
import type { BaseGameBarAction } from "./base-action";
|
||||
import { STATES } from "@utils/global";
|
||||
import { MicrophoneAction } from "./microphone-action";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { TrueAchievementsAction } from "./true-achievements-action";
|
||||
import { SpeakerAction } from "./speaker-action";
|
||||
import { RendererAction } from "./renderer-action";
|
||||
import { BxLogger } from "@/utils/bx-logger";
|
||||
import { GameBarPosition, TouchControllerMode } from "@/enums/pref-values";
|
||||
import { BxEventBus } from "@/utils/bx-event-bus";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
|
||||
|
||||
export class GameBar {
|
||||
private static instance: GameBar | null | undefined;
|
||||
public static getInstance(): typeof GameBar['instance'] {
|
||||
if (typeof GameBar.instance === 'undefined') {
|
||||
if (getPref(PrefKey.GAME_BAR_POSITION) !== GameBarPosition.OFF) {
|
||||
if (getGlobalPref(GlobalPref.GAME_BAR_POSITION) !== GameBarPosition.OFF) {
|
||||
GameBar.instance = new GameBar();
|
||||
} else {
|
||||
GameBar.instance = null;
|
||||
@@ -46,7 +46,7 @@ export class GameBar {
|
||||
|
||||
let $container;
|
||||
|
||||
const position = getPref(PrefKey.GAME_BAR_POSITION);
|
||||
const position = getGlobalPref(GlobalPref.GAME_BAR_POSITION);
|
||||
|
||||
const $gameBar = CE('div', { id: 'bx-game-bar', class: 'bx-gone', 'data-position': position },
|
||||
$container = CE('div', { class: 'bx-game-bar-container bx-offscreen' }),
|
||||
@@ -55,7 +55,7 @@ export class GameBar {
|
||||
|
||||
this.actions = [
|
||||
new ScreenshotAction(),
|
||||
...(STATES.userAgent.capabilities.touch && (getPref(PrefKey.TOUCH_CONTROLLER_MODE) !== TouchControllerMode.OFF) ? [new TouchControlAction()] : []),
|
||||
...(STATES.userAgent.capabilities.touch && (getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) !== TouchControllerMode.OFF) ? [new TouchControlAction()] : []),
|
||||
new SpeakerAction(),
|
||||
new RendererAction(),
|
||||
new MicrophoneAction(),
|
||||
|
@@ -2,8 +2,8 @@ import { CE } from "@utils/html";
|
||||
import { getPreferredServerRegion } from "@utils/region";
|
||||
import { t } from "@utils/translation";
|
||||
import { STATES } from "@utils/global";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
import { compressCss } from "@macros/build" with { type: "macro" };
|
||||
import { LoadingScreenRocket } from "@/enums/pref-values";
|
||||
|
||||
@@ -37,7 +37,7 @@ export class LoadingScreen {
|
||||
|
||||
LoadingScreen.setBackground(titleInfo.product.heroImageUrl || titleInfo.product.titledHeroImageUrl || titleInfo.product.tileImageUrl);
|
||||
|
||||
if (getPref(PrefKey.LOADING_SCREEN_ROCKET) === LoadingScreenRocket.HIDE) {
|
||||
if (getGlobalPref(GlobalPref.LOADING_SCREEN_ROCKET) === LoadingScreenRocket.HIDE) {
|
||||
LoadingScreen.hideRocket();
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ export class LoadingScreen {
|
||||
// Limit max width to reduce image size
|
||||
imageUrl = imageUrl + '?w=1920';
|
||||
|
||||
const imageQuality = getPref(PrefKey.UI_IMAGE_QUALITY);
|
||||
const imageQuality = getGlobalPref(GlobalPref.UI_IMAGE_QUALITY);
|
||||
if (imageQuality !== 90) {
|
||||
imageUrl += '&q=' + imageQuality;
|
||||
}
|
||||
@@ -94,7 +94,7 @@ export class LoadingScreen {
|
||||
|
||||
static setupWaitTime(waitTime: number) {
|
||||
// Hide rocket when queing
|
||||
if (getPref(PrefKey.LOADING_SCREEN_ROCKET) === LoadingScreenRocket.HIDE_QUEUE) {
|
||||
if (getGlobalPref(GlobalPref.LOADING_SCREEN_ROCKET) === LoadingScreenRocket.HIDE_QUEUE) {
|
||||
LoadingScreen.hideRocket();
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ export class LoadingScreen {
|
||||
LoadingScreen.orgWebTitle && (document.title = LoadingScreen.orgWebTitle);
|
||||
LoadingScreen.$waitTimeBox && LoadingScreen.$waitTimeBox.classList.add('bx-gone');
|
||||
|
||||
if (getPref(PrefKey.LOADING_SCREEN_GAME_ART) && LoadingScreen.$bgStyle) {
|
||||
if (getGlobalPref(GlobalPref.LOADING_SCREEN_GAME_ART) && LoadingScreen.$bgStyle) {
|
||||
const $rocketBg = document.querySelector('#game-stream rect[width="800"]');
|
||||
$rocketBg && $rocketBg.addEventListener('transitionend', e => {
|
||||
LoadingScreen.$bgStyle.textContent += compressCss(`
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { MouseButtonCode, WheelCode, type KeyCode } from "@/enums/mkb";
|
||||
import { MouseButtonCode, WheelCode } from "@/enums/mkb";
|
||||
|
||||
export const enum KeyModifier {
|
||||
CTRL = 1,
|
||||
|
@@ -11,8 +11,8 @@ import { BxLogger } from "@utils/bx-logger";
|
||||
import { PointerClient } from "./pointer-client";
|
||||
import { NativeMkbHandler } from "./native-mkb-handler";
|
||||
import { MkbHandler, MouseDataProvider } from "./base-mkb-handler";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref, StreamPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref, getStreamPref } from "@/utils/pref-utils";
|
||||
import { GamepadKey, GamepadStick } from "@/enums/gamepad";
|
||||
import { MkbPopup } from "./mkb-popup";
|
||||
import type { MkbConvertedPresetData } from "@/types/presets";
|
||||
@@ -134,7 +134,7 @@ export class EmulatedMkbHandler extends MkbHandler {
|
||||
private static readonly LOG_TAG = 'EmulatedMkbHandler';
|
||||
|
||||
static isAllowed() {
|
||||
return getPref(PrefKey.MKB_ENABLED) && (AppInterface || !UserAgent.isMobile());
|
||||
return getGlobalPref(GlobalPref.MKB_ENABLED) && (AppInterface || !UserAgent.isMobile());
|
||||
}
|
||||
|
||||
private PRESET!: MkbConvertedPresetData | null;
|
||||
@@ -233,10 +233,10 @@ export class EmulatedMkbHandler extends MkbHandler {
|
||||
private vectorLength = (x: number, y: number): number => Math.sqrt(x ** 2 + y ** 2);
|
||||
|
||||
resetXcloudGamepads() {
|
||||
const index = getPref(PrefKey.MKB_P1_SLOT) - 1;
|
||||
const index = getStreamPref(StreamPref.MKB_P1_SLOT) - 1;
|
||||
|
||||
this.xCloudGamepad = generateVirtualControllerMapping(0, {
|
||||
GamepadIndex: getPref(PrefKey.LOCAL_CO_OP_ENABLED) ? index : 0,
|
||||
GamepadIndex: getStreamPref(StreamPref.LOCAL_CO_OP_ENABLED) ? index : 0,
|
||||
Dirty: true,
|
||||
});
|
||||
this.VIRTUAL_GAMEPAD.index = index;
|
||||
@@ -590,7 +590,7 @@ export class EmulatedMkbHandler extends MkbHandler {
|
||||
this.isPolling = true;
|
||||
this.escKeyDownTime = -1;
|
||||
|
||||
window.BX_EXPOSED.toggleLocalCoOp(getPref(PrefKey.LOCAL_CO_OP_ENABLED));
|
||||
window.BX_EXPOSED.toggleLocalCoOp(getStreamPref(StreamPref.LOCAL_CO_OP_ENABLED));
|
||||
this.resetXcloudGamepads();
|
||||
window.navigator.getGamepads = this.patchedGetGamepads;
|
||||
|
||||
@@ -650,7 +650,7 @@ export class EmulatedMkbHandler extends MkbHandler {
|
||||
});
|
||||
|
||||
if (EmulatedMkbHandler.isAllowed()) {
|
||||
BxEventBus.Script.on('mkb.setting.updated', () => {
|
||||
BxEventBus.Stream.on('mkb.setting.updated', () => {
|
||||
EmulatedMkbHandler.getInstance()?.refreshPresetData();
|
||||
});
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ export class MkbPopup {
|
||||
constructor() {
|
||||
this.render();
|
||||
|
||||
BxEventBus.Script.on('keyboardShortcuts.updated', () => {
|
||||
BxEventBus.Stream.on('keyboardShortcuts.updated', () => {
|
||||
const $newButton = this.createActivateButton();
|
||||
this.$btnActivate.replaceWith($newButton);
|
||||
this.$btnActivate = $newButton;
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
|
||||
export class MouseCursorHider {
|
||||
private static instance: MouseCursorHider | null | undefined;
|
||||
public static getInstance(): typeof MouseCursorHider['instance'] {
|
||||
if (typeof MouseCursorHider.instance === 'undefined') {
|
||||
if (!getPref(PrefKey.MKB_ENABLED) && getPref(PrefKey.MKB_HIDE_IDLE_CURSOR)) {
|
||||
if (!getGlobalPref(GlobalPref.MKB_ENABLED) && getGlobalPref(GlobalPref.MKB_HIDE_IDLE_CURSOR)) {
|
||||
MouseCursorHider.instance = new MouseCursorHider();
|
||||
} else {
|
||||
MouseCursorHider.instance = null;
|
||||
|
@@ -4,8 +4,7 @@ import { AppInterface, STATES } from "@/utils/global";
|
||||
import { MkbHandler } from "./base-mkb-handler";
|
||||
import { t } from "@/utils/translation";
|
||||
import { BxEvent } from "@/utils/bx-event";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref, StreamPref } from "@/enums/pref-keys";
|
||||
import { BxLogger } from "@/utils/bx-logger";
|
||||
import { MkbPopup } from "./mkb-popup";
|
||||
import { KeyHelper } from "./key-helper";
|
||||
@@ -13,7 +12,7 @@ import { StreamSettings } from "@/utils/stream-settings";
|
||||
import { ShortcutAction } from "@/enums/shortcut-actions";
|
||||
import { NativeMkbMode } from "@/enums/pref-values";
|
||||
import { BxEventBus } from "@/utils/bx-event-bus";
|
||||
import type { NativeMouseData, XcloudInputChannel } from "@/utils/gamepad";
|
||||
import { getStreamPref, getGlobalPref } from "@/utils/pref-utils";
|
||||
|
||||
export class NativeMkbHandler extends MkbHandler {
|
||||
private static instance: NativeMkbHandler | null | undefined;
|
||||
@@ -31,7 +30,7 @@ export class NativeMkbHandler extends MkbHandler {
|
||||
private readonly LOG_TAG = 'NativeMkbHandler';
|
||||
|
||||
static isAllowed = () => {
|
||||
return STATES.browser.capabilities.emulatedNativeMkb && getPref(PrefKey.NATIVE_MKB_MODE) === NativeMkbMode.ON;
|
||||
return STATES.browser.capabilities.emulatedNativeMkb && getGlobalPref(GlobalPref.NATIVE_MKB_MODE) === NativeMkbMode.ON;
|
||||
}
|
||||
|
||||
private pointerClient: PointerClient | undefined;
|
||||
@@ -113,8 +112,8 @@ export class NativeMkbHandler extends MkbHandler {
|
||||
Toast.show('Cannot enable Mouse & Keyboard feature');
|
||||
}
|
||||
|
||||
this.mouseVerticalMultiply = getPref(PrefKey.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY);
|
||||
this.mouseHorizontalMultiply = getPref(PrefKey.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY);
|
||||
this.mouseVerticalMultiply = getStreamPref(StreamPref.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY);
|
||||
this.mouseHorizontalMultiply = getStreamPref(StreamPref.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY);
|
||||
|
||||
window.addEventListener('keyup', this);
|
||||
|
||||
|
@@ -11,8 +11,8 @@ import codeGameCardIcons from "./patches/game-card-icons.js" with { type: "text"
|
||||
import codeLocalCoOpEnable from "./patches/local-co-op-enable.js" with { type: "text" };
|
||||
import codeRemotePlayKeepAlive from "./patches/remote-play-keep-alive.js" with { type: "text" };
|
||||
import codeVibrationAdjust from "./patches/vibration-adjust.js" with { type: "text" };
|
||||
import { PrefKey, StorageKey } from "@/enums/pref-keys.js";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref, StorageKey } from "@/enums/pref-keys.js";
|
||||
import { getGlobalPref } from "@/utils/pref-utils.js";
|
||||
import { GamePassCloudGallery } from "@/enums/game-pass-gallery";
|
||||
import { t } from "@/utils/translation";
|
||||
import { BlockFeature, NativeMkbMode, TouchControllerMode, UiLayout, UiSection } from "@/enums/pref-values";
|
||||
@@ -89,7 +89,7 @@ const PATCHES = {
|
||||
return false;
|
||||
}
|
||||
|
||||
const layout = getPref(PrefKey.UI_LAYOUT) === UiLayout.TV ? UiLayout.TV : UiLayout.DEFAULT;
|
||||
const layout = getGlobalPref(GlobalPref.UI_LAYOUT) === UiLayout.TV ? UiLayout.TV : UiLayout.DEFAULT;
|
||||
return str.replace(text, `?"${layout}":"${layout}"`);
|
||||
},
|
||||
|
||||
@@ -189,7 +189,7 @@ remotePlayServerId: (window.BX_REMOTE_PLAY_CONFIG && window.BX_REMOTE_PLAY_CONFI
|
||||
str = PatcherUtils.replaceWith(str, setTimeoutIndex, tmp, tmpPatched);
|
||||
|
||||
// Block gamepad stats collecting
|
||||
if (getPref(PrefKey.BLOCK_TRACKING)) {
|
||||
if (getGlobalPref(GlobalPref.BLOCK_TRACKING)) {
|
||||
codeBlock = codeBlock.replace('this.inputPollingIntervalStats.addValue', '');
|
||||
codeBlock = codeBlock.replace('this.inputPollingDurationStats.addValue', '');
|
||||
}
|
||||
@@ -377,9 +377,9 @@ if (window.BX_EXPOSED.stopTakRendering) {
|
||||
}
|
||||
|
||||
let autoOffCode = '';
|
||||
if (getPref(PrefKey.TOUCH_CONTROLLER_MODE) === TouchControllerMode.OFF) {
|
||||
if (getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) === TouchControllerMode.OFF) {
|
||||
autoOffCode = 'return;';
|
||||
} else if (getPref(PrefKey.TOUCH_CONTROLLER_AUTO_OFF)) {
|
||||
} else if (getGlobalPref(GlobalPref.TOUCH_CONTROLLER_AUTO_OFF)) {
|
||||
autoOffCode = `
|
||||
const gamepads = window.navigator.getGamepads();
|
||||
let gamepadFound = false;
|
||||
@@ -434,7 +434,7 @@ e.guideUI = null;
|
||||
`;
|
||||
|
||||
// Remove the TAK Edit button when the touch controller is disabled
|
||||
if (getPref(PrefKey.TOUCH_CONTROLLER_MODE) === TouchControllerMode.OFF) {
|
||||
if (getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) === TouchControllerMode.OFF) {
|
||||
newCode += 'e.canShowTakHUD = false;';
|
||||
}
|
||||
|
||||
@@ -554,7 +554,7 @@ BxLogger.info('patchRemotePlayMkb', ${configsVar});
|
||||
return false;
|
||||
}
|
||||
|
||||
const opacity = (getPref(PrefKey.TOUCH_CONTROLLER_DEFAULT_OPACITY) / 100).toFixed(1);
|
||||
const opacity = (getGlobalPref(GlobalPref.TOUCH_CONTROLLER_DEFAULT_OPACITY) / 100).toFixed(1);
|
||||
const newCode = `opacityMultiplier: ${opacity}`;
|
||||
str = str.replace(text, newCode);
|
||||
return str;
|
||||
@@ -790,7 +790,7 @@ true` + text;
|
||||
return false;
|
||||
}
|
||||
|
||||
const PREF_HIDE_SECTIONS = getPref(PrefKey.UI_HIDE_SECTIONS);
|
||||
const PREF_HIDE_SECTIONS = getGlobalPref(GlobalPref.UI_HIDE_SECTIONS);
|
||||
const siglIds: GamePassCloudGallery[] = [];
|
||||
|
||||
const sections: PartialRecord<UiSection, GamePassCloudGallery> = {
|
||||
@@ -981,7 +981,7 @@ if (this.baseStorageKey in window.BX_EXPOSED.overrideSettings) {
|
||||
|
||||
// Find index after {
|
||||
index = str.indexOf('{', index) + 1;
|
||||
const blockFeatures = getPref(PrefKey.BLOCK_FEATURES);
|
||||
const blockFeatures = getGlobalPref(GlobalPref.BLOCK_FEATURES);
|
||||
const filters = [];
|
||||
if (blockFeatures.includes(BlockFeature.NOTIFICATIONS_INVITES)) {
|
||||
filters.push('GameInvite', 'PartyInvite');
|
||||
@@ -1097,7 +1097,7 @@ ${subsVar} = subs;
|
||||
// Find "return" keyword
|
||||
index = PatcherUtils.indexOf(str, 'return', index, 200);
|
||||
|
||||
const newCode = `${paramVar}.set('q', ${getPref(PrefKey.UI_IMAGE_QUALITY)});`;
|
||||
const newCode = `${paramVar}.set('q', ${getGlobalPref(GlobalPref.UI_IMAGE_QUALITY)});`;
|
||||
str = PatcherUtils.insertAt(str, index, newCode);
|
||||
|
||||
return str;
|
||||
@@ -1111,13 +1111,13 @@ ${subsVar} = subs;
|
||||
return false;
|
||||
}
|
||||
|
||||
str = PatcherUtils.insertAt(str, index, `&q=${getPref(PrefKey.UI_IMAGE_QUALITY)}`);
|
||||
str = PatcherUtils.insertAt(str, index, `&q=${getGlobalPref(GlobalPref.UI_IMAGE_QUALITY)}`);
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
let PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
...(AppInterface && getPref(PrefKey.NATIVE_MKB_MODE) === NativeMkbMode.ON ? [
|
||||
...(AppInterface && getGlobalPref(GlobalPref.NATIVE_MKB_MODE) === NativeMkbMode.ON ? [
|
||||
'enableNativeMkb',
|
||||
'disableAbsoluteMouse',
|
||||
] : []),
|
||||
@@ -1126,7 +1126,7 @@ let PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
'gameCardCustomIcons',
|
||||
// 'gameCardPassTitle',
|
||||
|
||||
...(getPref(PrefKey.UI_IMAGE_QUALITY) < 90 ? [
|
||||
...(getGlobalPref(GlobalPref.UI_IMAGE_QUALITY) < 90 ? [
|
||||
'setImageQuality',
|
||||
] : []),
|
||||
|
||||
@@ -1154,16 +1154,16 @@ let PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
|
||||
'supportLocalCoOp',
|
||||
'overrideStorageGetSettings',
|
||||
getPref(PrefKey.UI_GAME_CARD_SHOW_WAIT_TIME) && 'patchSetCurrentFocus',
|
||||
getGlobalPref(GlobalPref.UI_GAME_CARD_SHOW_WAIT_TIME) && 'patchSetCurrentFocus',
|
||||
|
||||
getPref(PrefKey.UI_LAYOUT) !== UiLayout.DEFAULT && 'websiteLayout',
|
||||
getPref(PrefKey.GAME_FORTNITE_FORCE_CONSOLE) && 'forceFortniteConsole',
|
||||
getGlobalPref(GlobalPref.UI_LAYOUT) !== UiLayout.DEFAULT && 'websiteLayout',
|
||||
getGlobalPref(GlobalPref.GAME_FORTNITE_FORCE_CONSOLE) && 'forceFortniteConsole',
|
||||
|
||||
...(STATES.userAgent.capabilities.touch ? [
|
||||
'disableTouchContextMenu',
|
||||
] : []),
|
||||
|
||||
...(getPref(PrefKey.BLOCK_TRACKING) ? [
|
||||
...(getGlobalPref(GlobalPref.BLOCK_TRACKING) ? [
|
||||
'disableAiTrack',
|
||||
'disableTelemetry',
|
||||
|
||||
@@ -1173,7 +1173,7 @@ let PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
'disableTelemetryProvider',
|
||||
] : []),
|
||||
|
||||
...(getPref(PrefKey.REMOTE_PLAY_ENABLED) ? [
|
||||
...(getGlobalPref(GlobalPref.REMOTE_PLAY_ENABLED) ? [
|
||||
'remotePlayKeepAlive',
|
||||
'remotePlayDirectConnectUrl',
|
||||
'remotePlayDisableAchievementToast',
|
||||
@@ -1188,7 +1188,7 @@ let PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
] : []),
|
||||
]);
|
||||
|
||||
const hideSections = getPref(PrefKey.UI_HIDE_SECTIONS);
|
||||
const hideSections = getGlobalPref(GlobalPref.UI_HIDE_SECTIONS);
|
||||
let HOME_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
hideSections.includes(UiSection.NEWS) && 'ignoreNewsSection',
|
||||
hideSections.includes(UiSection.FRIENDS) && 'ignorePlayWithFriendsSection',
|
||||
@@ -1196,7 +1196,7 @@ let HOME_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
STATES.browser.capabilities.touch && hideSections.includes(UiSection.TOUCH) && 'ignorePlayWithTouchSection',
|
||||
hideSections.some(value => [UiSection.NATIVE_MKB, UiSection.MOST_POPULAR].includes(value)) && 'ignoreSiglSections',
|
||||
|
||||
...(getPref(PrefKey.UI_IMAGE_QUALITY) < 90 ? [
|
||||
...(getGlobalPref(GlobalPref.UI_IMAGE_QUALITY) < 90 ? [
|
||||
'setBackgroundImageQuality',
|
||||
] : []),
|
||||
|
||||
@@ -1206,8 +1206,6 @@ let HOME_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
]);
|
||||
|
||||
// Only when playing
|
||||
// TODO: check this
|
||||
// @ts-ignore
|
||||
let STREAM_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
'exposeInputChannel',
|
||||
|
||||
@@ -1221,34 +1219,34 @@ let STREAM_PAGE_PATCH_ORDERS = PatcherUtils.filterPatches([
|
||||
// 'exposeEventTarget',
|
||||
|
||||
// Patch volume control for normal stream
|
||||
getPref(PrefKey.AUDIO_VOLUME_CONTROL_ENABLED) && !getPref(PrefKey.STREAM_COMBINE_SOURCES) && 'patchAudioMediaStream',
|
||||
getGlobalPref(GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED) && !getGlobalPref(GlobalPref.STREAM_COMBINE_SOURCES) && 'patchAudioMediaStream',
|
||||
// Patch volume control for combined audio+video stream
|
||||
getPref(PrefKey.AUDIO_VOLUME_CONTROL_ENABLED) && getPref(PrefKey.STREAM_COMBINE_SOURCES) && 'patchCombinedAudioVideoMediaStream',
|
||||
getGlobalPref(GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED) && getGlobalPref(GlobalPref.STREAM_COMBINE_SOURCES) && 'patchCombinedAudioVideoMediaStream',
|
||||
|
||||
// Skip feedback dialog
|
||||
getPref(PrefKey.UI_DISABLE_FEEDBACK_DIALOG) && 'skipFeedbackDialog',
|
||||
getGlobalPref(GlobalPref.UI_DISABLE_FEEDBACK_DIALOG) && 'skipFeedbackDialog',
|
||||
|
||||
...(STATES.userAgent.capabilities.touch ? [
|
||||
getPref(PrefKey.TOUCH_CONTROLLER_MODE) === TouchControllerMode.ALL && 'patchShowSensorControls',
|
||||
getPref(PrefKey.TOUCH_CONTROLLER_MODE) === TouchControllerMode.ALL && 'exposeTouchLayoutManager',
|
||||
(getPref(PrefKey.TOUCH_CONTROLLER_MODE) === TouchControllerMode.OFF || getPref(PrefKey.TOUCH_CONTROLLER_AUTO_OFF)) && 'disableTakRenderer',
|
||||
getPref(PrefKey.TOUCH_CONTROLLER_DEFAULT_OPACITY) !== 100 && 'patchTouchControlDefaultOpacity',
|
||||
(getPref(PrefKey.TOUCH_CONTROLLER_MODE) !== TouchControllerMode.OFF && (getPref(PrefKey.MKB_ENABLED) || getPref(PrefKey.NATIVE_MKB_MODE) === NativeMkbMode.ON)) && 'patchBabylonRendererClass',
|
||||
getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) === TouchControllerMode.ALL && 'patchShowSensorControls',
|
||||
getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) === TouchControllerMode.ALL && 'exposeTouchLayoutManager',
|
||||
(getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) === TouchControllerMode.OFF || getGlobalPref(GlobalPref.TOUCH_CONTROLLER_AUTO_OFF)) && 'disableTakRenderer',
|
||||
getGlobalPref(GlobalPref.TOUCH_CONTROLLER_DEFAULT_OPACITY) !== 100 && 'patchTouchControlDefaultOpacity',
|
||||
(getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) !== TouchControllerMode.OFF && (getGlobalPref(GlobalPref.MKB_ENABLED) || getGlobalPref(GlobalPref.NATIVE_MKB_MODE) === NativeMkbMode.ON)) && 'patchBabylonRendererClass',
|
||||
] : []),
|
||||
|
||||
BX_FLAGS.EnableXcloudLogging && 'enableConsoleLogging',
|
||||
|
||||
'patchPollGamepads',
|
||||
|
||||
getPref(PrefKey.STREAM_COMBINE_SOURCES) && 'streamCombineSources',
|
||||
getGlobalPref(GlobalPref.STREAM_COMBINE_SOURCES) && 'streamCombineSources',
|
||||
|
||||
...(getPref(PrefKey.REMOTE_PLAY_ENABLED) ? [
|
||||
...(getGlobalPref(GlobalPref.REMOTE_PLAY_ENABLED) ? [
|
||||
'patchRemotePlayMkb',
|
||||
'remotePlayConnectMode',
|
||||
] : []),
|
||||
|
||||
// Native MKB
|
||||
...(AppInterface && getPref(PrefKey.NATIVE_MKB_MODE) === NativeMkbMode.ON ? [
|
||||
...(AppInterface && getGlobalPref(GlobalPref.NATIVE_MKB_MODE) === NativeMkbMode.ON ? [
|
||||
'patchMouseAndKeyboardEnabled',
|
||||
'disableNativeRequestPointerLock',
|
||||
] : []),
|
||||
|
@@ -53,6 +53,9 @@ $this$.toggleLocalCoOp = (enable: boolean) => {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't show toast
|
||||
(gamepad as any)._noToast = true;
|
||||
|
||||
window.dispatchEvent(new GamepadEvent('gamepaddisconnected', { gamepad }));
|
||||
window.dispatchEvent(new GamepadEvent('gamepadconnected', { gamepad }));
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import vertClarityBoost from "./shaders/clarity_boost.vert" with { type: "text" };
|
||||
import fsClarityBoost from "./shaders/clarity_boost.fs" with { type: "text" };
|
||||
import { BxLogger } from "@/utils/bx-logger";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { StreamPref } from "@/enums/pref-keys";
|
||||
import { getStreamPref } from "@/utils/pref-utils";
|
||||
|
||||
|
||||
export class WebGL2Player {
|
||||
@@ -143,13 +143,13 @@ export class WebGL2Player {
|
||||
}
|
||||
|
||||
private setupShaders() {
|
||||
BxLogger.info(this.LOG_TAG, 'Setting up', getPref(PrefKey.VIDEO_POWER_PREFERENCE));
|
||||
BxLogger.info(this.LOG_TAG, 'Setting up', getStreamPref(StreamPref.VIDEO_POWER_PREFERENCE));
|
||||
|
||||
const gl = this.$canvas.getContext('webgl2', {
|
||||
isBx: true,
|
||||
antialias: true,
|
||||
alpha: false,
|
||||
powerPreference: getPref(PrefKey.VIDEO_POWER_PREFERENCE),
|
||||
powerPreference: getStreamPref(StreamPref.VIDEO_POWER_PREFERENCE),
|
||||
}) as WebGL2RenderingContext;
|
||||
this.gl = gl;
|
||||
|
||||
|
@@ -5,8 +5,8 @@ import { t } from "@utils/translation";
|
||||
import { localRedirect } from "@modules/ui/ui";
|
||||
import { BxLogger } from "@utils/bx-logger";
|
||||
import { HeaderSection } from "./ui/header";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref, setPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref, setGlobalPref } from "@/utils/pref-utils";
|
||||
import { RemotePlayDialog } from "./ui/dialog/remote-play-dialog";
|
||||
|
||||
export const enum RemotePlayConsoleState {
|
||||
@@ -37,7 +37,7 @@ export class RemotePlayManager {
|
||||
private static instance: RemotePlayManager | null | undefined;
|
||||
public static getInstance(): typeof RemotePlayManager['instance'] {
|
||||
if (typeof RemotePlayManager.instance === 'undefined') {
|
||||
if (getPref(PrefKey.REMOTE_PLAY_ENABLED)) {
|
||||
if (getGlobalPref(GlobalPref.REMOTE_PLAY_ENABLED)) {
|
||||
RemotePlayManager.instance = new RemotePlayManager();
|
||||
} else {
|
||||
RemotePlayManager.instance = null;
|
||||
@@ -186,7 +186,7 @@ export class RemotePlayManager {
|
||||
|
||||
play(serverId: string, resolution?: string) {
|
||||
if (resolution) {
|
||||
setPref(PrefKey.REMOTE_PLAY_STREAM_RESOLUTION, resolution);
|
||||
setGlobalPref(GlobalPref.REMOTE_PLAY_STREAM_RESOLUTION, resolution, 'ui');
|
||||
}
|
||||
|
||||
STATES.remotePlay.config = {
|
||||
@@ -221,7 +221,7 @@ export class RemotePlayManager {
|
||||
}
|
||||
|
||||
static detect() {
|
||||
if (!getPref(PrefKey.REMOTE_PLAY_ENABLED)) {
|
||||
if (!getGlobalPref(GlobalPref.REMOTE_PLAY_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
345
src/modules/settings-manager.ts
Normal file
345
src/modules/settings-manager.ts
Normal file
@@ -0,0 +1,345 @@
|
||||
import { GlobalPref, StreamPref, type AnyPref } from "@/enums/pref-keys";
|
||||
import { limitVideoPlayerFps, onChangeVideoPlayerType, updateVideoPlayer } from "./stream/stream-settings-utils";
|
||||
import { StreamStats } from "./stream/stream-stats";
|
||||
import { SoundShortcut } from "./shortcuts/sound-shortcut";
|
||||
import { STATES } from "@/utils/global";
|
||||
import { getGamePref, getStreamPref, hasGamePref, isStreamPref, setGameIdPref } from "@/utils/pref-utils";
|
||||
import { BxExposed } from "@/utils/bx-exposed";
|
||||
import { StreamSettings } from "@/utils/stream-settings";
|
||||
import { NativeMkbHandler } from "./mkb/native-mkb-handler";
|
||||
import { BxEventBus } from "@/utils/bx-event-bus";
|
||||
import { SettingElement } from "@/utils/setting-element";
|
||||
import { CE } from "@/utils/html";
|
||||
import { t } from "@/utils/translation";
|
||||
import { BxSelectElement } from "@/web-components/bx-select";
|
||||
import { XboxApi } from "@/utils/xbox-api";
|
||||
import { EmulatedMkbHandler } from "./mkb/mkb-handler";
|
||||
|
||||
type SettingType = Partial<{
|
||||
hidden: true;
|
||||
onChange: () => void;
|
||||
alwaysTriggerOnChange: boolean; // Always trigger onChange(), not just when playing
|
||||
$element: HTMLElement;
|
||||
}>;
|
||||
|
||||
export class SettingsManager {
|
||||
private static instance: SettingsManager;
|
||||
public static getInstance = () => SettingsManager.instance ?? (SettingsManager.instance = new SettingsManager());
|
||||
|
||||
private $streamSettingsSelection!: HTMLElement;
|
||||
private $tips!: HTMLElement;
|
||||
private playingGameId: number = -1;
|
||||
private targetGameId: number = -1;
|
||||
|
||||
// @ts-ignore
|
||||
private SETTINGS: Record<GlobalPref | StreamPref, SettingType> = {
|
||||
// [GlobalPref.VERSION_LATEST]: { hidden: true },
|
||||
// [GlobalPref.VERSION_LAST_CHECK]: { hidden: true },
|
||||
// [GlobalPref.VERSION_CURRENT]: { hidden: true },
|
||||
|
||||
[StreamPref.LOCAL_CO_OP_ENABLED]: {
|
||||
onChange: () => {
|
||||
BxExposed.toggleLocalCoOp(getStreamPref(StreamPref.LOCAL_CO_OP_ENABLED));
|
||||
},
|
||||
},
|
||||
[StreamPref.DEVICE_VIBRATION_MODE]: {
|
||||
onChange: StreamSettings.refreshControllerSettings,
|
||||
},
|
||||
[StreamPref.DEVICE_VIBRATION_INTENSITY]: {
|
||||
onChange: StreamSettings.refreshControllerSettings,
|
||||
},
|
||||
[StreamPref.CONTROLLER_POLLING_RATE]: {
|
||||
onChange: StreamSettings.refreshControllerSettings,
|
||||
},
|
||||
[StreamPref.CONTROLLER_SETTINGS]: {
|
||||
onChange: StreamSettings.refreshControllerSettings,
|
||||
},
|
||||
[StreamPref.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY]: {
|
||||
onChange: () => {
|
||||
const value = getStreamPref(StreamPref.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY);
|
||||
NativeMkbHandler.getInstance()?.setHorizontalScrollMultiplier(value / 100);
|
||||
},
|
||||
},
|
||||
[StreamPref.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY]: {
|
||||
onChange: () => {
|
||||
const value = getStreamPref(StreamPref.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY);
|
||||
NativeMkbHandler.getInstance()?.setVerticalScrollMultiplier(value / 100);
|
||||
},
|
||||
},
|
||||
[StreamPref.VIDEO_PLAYER_TYPE]: {
|
||||
onChange: () => {
|
||||
onChangeVideoPlayerType();
|
||||
|
||||
if (STATES.isPlaying) {
|
||||
updateVideoPlayer();
|
||||
}
|
||||
},
|
||||
alwaysTriggerOnChange: true,
|
||||
},
|
||||
[StreamPref.VIDEO_POWER_PREFERENCE]: {
|
||||
onChange: () => {
|
||||
const streamPlayer = STATES.currentStream.streamPlayer;
|
||||
if (!streamPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
streamPlayer.reloadPlayer();
|
||||
updateVideoPlayer();
|
||||
},
|
||||
},
|
||||
[StreamPref.VIDEO_PROCESSING]: {
|
||||
onChange: updateVideoPlayer,
|
||||
},
|
||||
[StreamPref.VIDEO_SHARPNESS]: {
|
||||
onChange: updateVideoPlayer,
|
||||
},
|
||||
[StreamPref.VIDEO_MAX_FPS]: {
|
||||
onChange: () => {
|
||||
const value = getStreamPref(StreamPref.VIDEO_MAX_FPS);
|
||||
limitVideoPlayerFps(value);
|
||||
},
|
||||
},
|
||||
[StreamPref.VIDEO_RATIO]: {
|
||||
onChange: updateVideoPlayer,
|
||||
},
|
||||
[StreamPref.VIDEO_BRIGHTNESS]: {
|
||||
onChange: updateVideoPlayer,
|
||||
},
|
||||
[StreamPref.VIDEO_CONTRAST]: {
|
||||
onChange: updateVideoPlayer,
|
||||
},
|
||||
[StreamPref.VIDEO_SATURATION]: {
|
||||
onChange: updateVideoPlayer,
|
||||
},
|
||||
[StreamPref.VIDEO_POSITION]: {
|
||||
onChange: updateVideoPlayer,
|
||||
},
|
||||
[StreamPref.AUDIO_VOLUME]: {
|
||||
onChange: () => {
|
||||
const value = getStreamPref(StreamPref.AUDIO_VOLUME);
|
||||
SoundShortcut.setGainNodeVolume(value);
|
||||
},
|
||||
},
|
||||
|
||||
[StreamPref.STATS_ITEMS]: {
|
||||
onChange: StreamStats.refreshStyles,
|
||||
},
|
||||
[StreamPref.STATS_QUICK_GLANCE_ENABLED]: {
|
||||
onChange: () => {
|
||||
const value = getStreamPref(StreamPref.STATS_QUICK_GLANCE_ENABLED);
|
||||
const streamStats = StreamStats.getInstance();
|
||||
value ? streamStats.quickGlanceSetup() : streamStats.quickGlanceStop();
|
||||
},
|
||||
},
|
||||
[StreamPref.STATS_POSITION]: {
|
||||
onChange: StreamStats.refreshStyles,
|
||||
},
|
||||
[StreamPref.STATS_TEXT_SIZE]: {
|
||||
onChange: StreamStats.refreshStyles,
|
||||
},
|
||||
[StreamPref.STATS_OPACITY_ALL]: {
|
||||
onChange: StreamStats.refreshStyles,
|
||||
},
|
||||
[StreamPref.STATS_OPACITY_BACKGROUND]: {
|
||||
onChange: StreamStats.refreshStyles,
|
||||
},
|
||||
[StreamPref.STATS_CONDITIONAL_FORMATTING]: {
|
||||
onChange: StreamStats.refreshStyles,
|
||||
},
|
||||
|
||||
[StreamPref.MKB_P1_MAPPING_PRESET_ID]: {
|
||||
onChange: StreamSettings.refreshMkbSettings,
|
||||
},
|
||||
|
||||
[StreamPref.MKB_P1_SLOT]: {
|
||||
onChange: () => {
|
||||
EmulatedMkbHandler.getInstance()?.resetXcloudGamepads();
|
||||
},
|
||||
},
|
||||
|
||||
[StreamPref.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID]: {
|
||||
onChange: StreamSettings.refreshKeyboardShortcuts,
|
||||
},
|
||||
};
|
||||
|
||||
constructor() {
|
||||
// Trigger onChange event when a setting value is modified
|
||||
BxEventBus.Stream.on('setting.changed', data => {
|
||||
if (isStreamPref(data.settingKey)) {
|
||||
this.updateStreamElement(data.settingKey);
|
||||
}
|
||||
});
|
||||
|
||||
BxEventBus.Stream.on('gameSettings.switched', ({ id }) => {
|
||||
this.switchGameSettings(id);
|
||||
});
|
||||
|
||||
this.renderStreamSettingsSelection();
|
||||
}
|
||||
|
||||
private updateStreamElement(key: StreamPref, onChanges?: Set<SettingType['onChange']>) {
|
||||
const info = this.SETTINGS[key];
|
||||
|
||||
// Add event
|
||||
if (info.onChange && (STATES.isPlaying || info.alwaysTriggerOnChange)) {
|
||||
if (onChanges) {
|
||||
// Save to a Set()
|
||||
onChanges.add(info.onChange);
|
||||
} else {
|
||||
// Trigger onChange()
|
||||
info.onChange();
|
||||
}
|
||||
}
|
||||
|
||||
// Update element
|
||||
const $elm = info.$element;
|
||||
if (!$elm) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = getGamePref(this.targetGameId, key, true)!;
|
||||
|
||||
if ('setValue' in $elm) {
|
||||
($elm as any).setValue(value);
|
||||
} else {
|
||||
($elm as HTMLInputElement).value = value.toString();
|
||||
}
|
||||
|
||||
this.updateDataset($elm, key as StreamPref);
|
||||
}
|
||||
|
||||
private switchGameSettings(id: number) {
|
||||
setGameIdPref(id);
|
||||
|
||||
// Don't re-apply settings if the game is the same
|
||||
if (this.targetGameId === id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-apply all stream settings
|
||||
const onChanges: Set<SettingType['onChange']> = new Set();
|
||||
const oldGameId = this.targetGameId;
|
||||
this.targetGameId = id;
|
||||
|
||||
let key: AnyPref;
|
||||
for (key in this.SETTINGS) {
|
||||
if (!isStreamPref(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const oldValue = getGamePref(oldGameId, key, true, true);
|
||||
const newValue = getGamePref(this.targetGameId, key, true, true);
|
||||
|
||||
if (oldValue === newValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only apply Stream settings
|
||||
this.updateStreamElement(key, onChanges);
|
||||
}
|
||||
|
||||
// BxLogger.warning('Settings Manager', onChanges);
|
||||
onChanges.forEach(onChange => {
|
||||
onChange && onChange();
|
||||
});
|
||||
|
||||
// Toggle tips if not playing anything
|
||||
this.$tips.classList.toggle('bx-gone', id < 0);
|
||||
}
|
||||
|
||||
setElement(pref: AnyPref, $elm: HTMLElement) {
|
||||
// Set empty object
|
||||
if (!this.SETTINGS[pref]) {
|
||||
this.SETTINGS[pref] = {};
|
||||
}
|
||||
|
||||
this.updateDataset($elm, pref as StreamPref);
|
||||
this.SETTINGS[pref].$element = $elm;
|
||||
}
|
||||
|
||||
getElement(pref: AnyPref, params?: any) {
|
||||
// Set empty object
|
||||
if (!this.SETTINGS[pref]) {
|
||||
this.SETTINGS[pref] = {};
|
||||
}
|
||||
|
||||
let $elm = this.SETTINGS[pref].$element;
|
||||
|
||||
if (!$elm) {
|
||||
// Render element
|
||||
$elm = SettingElement.fromPref(pref, null, params)!;
|
||||
this.SETTINGS[pref].$element = $elm;
|
||||
}
|
||||
|
||||
this.updateDataset($elm, pref as StreamPref);
|
||||
return $elm;
|
||||
}
|
||||
|
||||
hasElement(pref: AnyPref) {
|
||||
return !!this.SETTINGS[pref]?.$element;
|
||||
}
|
||||
|
||||
private updateDataset($elm: HTMLElement, pref: StreamPref) {
|
||||
if (this.targetGameId === this.playingGameId && hasGamePref(this.playingGameId, pref)) {
|
||||
$elm.dataset.override = 'true';
|
||||
} else {
|
||||
delete $elm.dataset['override'];
|
||||
}
|
||||
}
|
||||
|
||||
private renderStreamSettingsSelection() {
|
||||
this.$tips = CE('p', { class: 'bx-gone' }, `⇐ Q ⟶: ${t('reset-highlighted-setting')}`);
|
||||
|
||||
const $select = BxSelectElement.create(CE('select', false,
|
||||
CE('optgroup', { label: t('settings-for') },
|
||||
CE('option', { value: -1 }, t('all-games')),
|
||||
),
|
||||
), true);
|
||||
$select.addEventListener('input', e => {
|
||||
const id = parseInt($select.value);
|
||||
// $btn.disabled = id < 0;
|
||||
BxEventBus.Stream.emit('gameSettings.switched', { id });
|
||||
});
|
||||
|
||||
this.$streamSettingsSelection = CE('div', {
|
||||
class: 'bx-stream-settings-selection bx-gone',
|
||||
_nearby: { orientation: 'vertical' },
|
||||
},
|
||||
CE('div', false, $select ),
|
||||
this.$tips,
|
||||
);
|
||||
|
||||
BxEventBus.Stream.on('xboxTitleId.changed', async ({ id }) => {
|
||||
this.playingGameId = id;
|
||||
setGameIdPref(id);
|
||||
const $optGroup = $select.querySelector('optgroup')!;
|
||||
|
||||
// Remove every options except the first one (All games)
|
||||
while ($optGroup.childElementCount > 1) {
|
||||
$optGroup.lastElementChild?.remove();
|
||||
}
|
||||
|
||||
// Add current game to the selection
|
||||
if (id >= 0) {
|
||||
const title = id === 0 ? 'Xbox' : await XboxApi.getProductTitle(id);
|
||||
$optGroup.appendChild(CE('option', {
|
||||
value: id,
|
||||
}, title));
|
||||
|
||||
$select.value = id.toString();
|
||||
} else {
|
||||
$select.value = '-1';
|
||||
}
|
||||
|
||||
BxEventBus.Stream.emit('gameSettings.switched', { id });
|
||||
});
|
||||
}
|
||||
|
||||
getStreamSettingsSelection() {
|
||||
return this.$streamSettingsSelection;
|
||||
}
|
||||
|
||||
getTargetGameId() {
|
||||
return this.targetGameId;
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { StreamPref } from "@/enums/pref-keys";
|
||||
import { limitVideoPlayerFps } from "../stream/stream-settings-utils";
|
||||
import { BxEventBus } from "@/utils/bx-event-bus";
|
||||
import { getStreamPref } from "@/utils/pref-utils";
|
||||
|
||||
export class RendererShortcut {
|
||||
static toggleVisibility() {
|
||||
@@ -15,7 +15,7 @@ export class RendererShortcut {
|
||||
const isVisible = !$mediaContainer.classList.contains('bx-gone');
|
||||
|
||||
// Switch FPS
|
||||
limitVideoPlayerFps(isVisible ? getPref(PrefKey.VIDEO_MAX_FPS) : 0);
|
||||
limitVideoPlayerFps(isVisible ? getStreamPref(StreamPref.VIDEO_MAX_FPS) : 0);
|
||||
BxEventBus.Stream.emit('video.visibility.changed', { isVisible });
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { ShortcutAction } from "@/enums/shortcut-actions";
|
||||
import { AppInterface, STATES } from "@/utils/global";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
import { t } from "@/utils/translation";
|
||||
|
||||
type ShortcutActions = {
|
||||
@@ -46,7 +46,7 @@ export const SHORTCUT_ACTIONS: ShortcutActions = {
|
||||
|
||||
[ShortcutAction.STREAM_SOUND_TOGGLE]: [t('sound'), t('toggle')],
|
||||
|
||||
...(getPref(PrefKey.AUDIO_VOLUME_CONTROL_ENABLED) ? {
|
||||
...(getGlobalPref(GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED) ? {
|
||||
[ShortcutAction.STREAM_VOLUME_INC]: [t('volume'), t('increase')],
|
||||
[ShortcutAction.STREAM_VOLUME_DEC]: [t('volume'), t('decrease')],
|
||||
} : {}),
|
||||
|
@@ -2,9 +2,10 @@ import { t } from "@utils/translation";
|
||||
import { STATES } from "@utils/global";
|
||||
import { Toast } from "@utils/toast";
|
||||
import { ceilToNearest, floorToNearest } from "@/utils/utils";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref, setPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref, StreamPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
import { BxEventBus } from "@/utils/bx-event-bus";
|
||||
import { getStreamPref, setStreamPref } from "@/utils/pref-utils";
|
||||
|
||||
export enum SpeakerState {
|
||||
ENABLED,
|
||||
@@ -13,11 +14,11 @@ export enum SpeakerState {
|
||||
|
||||
export class SoundShortcut {
|
||||
static adjustGainNodeVolume(amount: number): number {
|
||||
if (!getPref(PrefKey.AUDIO_VOLUME_CONTROL_ENABLED)) {
|
||||
if (!getGlobalPref(GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const currentValue = getPref(PrefKey.AUDIO_VOLUME);
|
||||
const currentValue = getStreamPref(StreamPref.AUDIO_VOLUME);
|
||||
let nearestValue: number;
|
||||
|
||||
if (amount > 0) { // Increase
|
||||
@@ -33,7 +34,7 @@ export class SoundShortcut {
|
||||
newValue = currentValue + amount;
|
||||
}
|
||||
|
||||
newValue = setPref(PrefKey.AUDIO_VOLUME, newValue, true);
|
||||
newValue = setStreamPref(StreamPref.AUDIO_VOLUME, newValue, 'direct');
|
||||
SoundShortcut.setGainNodeVolume(newValue);
|
||||
|
||||
// Show toast
|
||||
@@ -47,14 +48,14 @@ export class SoundShortcut {
|
||||
}
|
||||
|
||||
static muteUnmute() {
|
||||
if (getPref(PrefKey.AUDIO_VOLUME_CONTROL_ENABLED) && STATES.currentStream.audioGainNode) {
|
||||
if (getGlobalPref(GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED) && STATES.currentStream.audioGainNode) {
|
||||
const gainValue = STATES.currentStream.audioGainNode.gain.value;
|
||||
const settingValue = getPref(PrefKey.AUDIO_VOLUME);
|
||||
const settingValue = getStreamPref(StreamPref.AUDIO_VOLUME);
|
||||
|
||||
let targetValue: number;
|
||||
if (settingValue === 0) { // settingValue is 0 => set to 100
|
||||
targetValue = 100;
|
||||
setPref(PrefKey.AUDIO_VOLUME, targetValue, true);
|
||||
setStreamPref(StreamPref.AUDIO_VOLUME, targetValue, 'direct');
|
||||
} else if (gainValue === 0) { // is being muted => set to settingValue
|
||||
targetValue = settingValue;
|
||||
} else { // not being muted => mute
|
||||
|
@@ -4,18 +4,12 @@ import { CE } from "@/utils/html";
|
||||
import { WebGL2Player } from "./player/webgl2-player";
|
||||
import { ScreenshotManager } from "@/utils/screenshot-manager";
|
||||
import { STATES } from "@/utils/global";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref, StreamPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
import { BX_FLAGS } from "@/utils/bx-flags";
|
||||
import { StreamPlayerType, StreamVideoProcessing, VideoPosition } from "@/enums/pref-values";
|
||||
import { getStreamPref } from "@/utils/pref-utils";
|
||||
|
||||
export type StreamPlayerOptions = Partial<{
|
||||
processing: string,
|
||||
sharpness: number,
|
||||
saturation: number,
|
||||
contrast: number,
|
||||
brightness: number,
|
||||
}>;
|
||||
|
||||
export class StreamPlayer {
|
||||
private $video: HTMLVideoElement;
|
||||
@@ -98,7 +92,7 @@ export class StreamPlayer {
|
||||
}
|
||||
|
||||
private resizePlayer() {
|
||||
const PREF_RATIO = getPref(PrefKey.VIDEO_RATIO);
|
||||
const PREF_RATIO = getStreamPref(StreamPref.VIDEO_RATIO);
|
||||
const $video = this.$video;
|
||||
const isNativeTouchGame = STATES.currentStream.titleInfo?.details.hasNativeTouchSupport;
|
||||
|
||||
@@ -142,7 +136,7 @@ export class StreamPlayer {
|
||||
|
||||
// Set position
|
||||
const $parent = $video.parentElement!;
|
||||
const position = getPref(PrefKey.VIDEO_POSITION);
|
||||
const position = getStreamPref(StreamPref.VIDEO_POSITION);
|
||||
$parent.style.removeProperty('padding-top');
|
||||
|
||||
$parent.dataset.position = position;
|
||||
@@ -269,7 +263,7 @@ export class StreamPlayer {
|
||||
}
|
||||
|
||||
// Apply video filters to screenshots
|
||||
if (isFullVersion() && getPref(PrefKey.SCREENSHOT_APPLY_FILTERS)) {
|
||||
if (isFullVersion() && getGlobalPref(GlobalPref.SCREENSHOT_APPLY_FILTERS)) {
|
||||
ScreenshotManager.getInstance().updateCanvasFilters(filters);
|
||||
}
|
||||
|
||||
|
@@ -1,24 +1,24 @@
|
||||
import { STATES } from "@utils/global";
|
||||
import { UserAgent } from "@utils/user-agent";
|
||||
import type { StreamPlayerOptions } from "../stream-player";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref, setPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { StreamPref } from "@/enums/pref-keys";
|
||||
import { StreamVideoProcessing, StreamPlayerType } from "@/enums/pref-values";
|
||||
import { escapeCssSelector } from "@/utils/html";
|
||||
import { getStreamPref, setStreamPref } from "@/utils/pref-utils";
|
||||
import { SettingsManager } from "../settings-manager";
|
||||
|
||||
export function onChangeVideoPlayerType() {
|
||||
const playerType = getPref(PrefKey.VIDEO_PLAYER_TYPE);
|
||||
const $videoProcessing = document.getElementById(`bx_setting_${escapeCssSelector(PrefKey.VIDEO_PROCESSING)}`) as HTMLSelectElement;
|
||||
const $videoSharpness = document.getElementById(`bx_setting_${escapeCssSelector(PrefKey.VIDEO_SHARPNESS)}`) as HTMLElement;
|
||||
const $videoPowerPreference = document.getElementById(`bx_setting_${escapeCssSelector(PrefKey.VIDEO_POWER_PREFERENCE)}`) as HTMLElement;
|
||||
const $videoMaxFps = document.getElementById(`bx_setting_${escapeCssSelector(PrefKey.VIDEO_MAX_FPS)}`) as HTMLElement;
|
||||
|
||||
if (!$videoProcessing) {
|
||||
const playerType = getStreamPref(StreamPref.VIDEO_PLAYER_TYPE);
|
||||
const settingsManager = SettingsManager.getInstance();
|
||||
if (!settingsManager.hasElement(StreamPref.VIDEO_PROCESSING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isDisabled = false;
|
||||
|
||||
const $videoProcessing = settingsManager.getElement(StreamPref.VIDEO_PROCESSING) as HTMLSelectElement;
|
||||
const $videoSharpness = settingsManager.getElement(StreamPref.VIDEO_SHARPNESS);
|
||||
const $videoPowerPreference = settingsManager.getElement(StreamPref.VIDEO_POWER_PREFERENCE);
|
||||
const $videoMaxFps = settingsManager.getElement(StreamPref.VIDEO_MAX_FPS);
|
||||
|
||||
const $optCas = $videoProcessing.querySelector<HTMLOptionElement>(`option[value=${StreamVideoProcessing.CAS}]`);
|
||||
|
||||
if (playerType === StreamPlayerType.WEBGL2) {
|
||||
@@ -26,7 +26,7 @@ export function onChangeVideoPlayerType() {
|
||||
} else {
|
||||
// Only allow USM when player type is Video
|
||||
$videoProcessing.value = StreamVideoProcessing.USM;
|
||||
setPref(PrefKey.VIDEO_PROCESSING, StreamVideoProcessing.USM);
|
||||
setStreamPref(StreamPref.VIDEO_PROCESSING, StreamVideoProcessing.USM, 'direct');
|
||||
|
||||
$optCas && ($optCas.disabled = true);
|
||||
|
||||
@@ -41,8 +41,6 @@ export function onChangeVideoPlayerType() {
|
||||
// Hide Power Preference setting if renderer isn't WebGL2
|
||||
$videoPowerPreference.closest('.bx-settings-row')!.classList.toggle('bx-gone', playerType !== StreamPlayerType.WEBGL2);
|
||||
$videoMaxFps.closest('.bx-settings-row')!.classList.toggle('bx-gone', playerType !== StreamPlayerType.WEBGL2);
|
||||
|
||||
updateVideoPlayer();
|
||||
}
|
||||
|
||||
|
||||
@@ -58,17 +56,17 @@ export function updateVideoPlayer() {
|
||||
return;
|
||||
}
|
||||
|
||||
limitVideoPlayerFps(getPref(PrefKey.VIDEO_MAX_FPS));
|
||||
limitVideoPlayerFps(getStreamPref(StreamPref.VIDEO_MAX_FPS));
|
||||
|
||||
const options = {
|
||||
processing: getPref(PrefKey.VIDEO_PROCESSING),
|
||||
sharpness: getPref(PrefKey.VIDEO_SHARPNESS),
|
||||
saturation: getPref(PrefKey.VIDEO_SATURATION),
|
||||
contrast: getPref(PrefKey.VIDEO_CONTRAST),
|
||||
brightness: getPref(PrefKey.VIDEO_BRIGHTNESS),
|
||||
processing: getStreamPref(StreamPref.VIDEO_PROCESSING),
|
||||
sharpness: getStreamPref(StreamPref.VIDEO_SHARPNESS),
|
||||
saturation: getStreamPref(StreamPref.VIDEO_SATURATION),
|
||||
contrast: getStreamPref(StreamPref.VIDEO_CONTRAST),
|
||||
brightness: getStreamPref(StreamPref.VIDEO_BRIGHTNESS),
|
||||
} satisfies StreamPlayerOptions;
|
||||
|
||||
streamPlayer.setPlayerType(getPref(PrefKey.VIDEO_PLAYER_TYPE));
|
||||
streamPlayer.setPlayerType(getStreamPref(StreamPref.VIDEO_PLAYER_TYPE));
|
||||
streamPlayer.updateOptions(options);
|
||||
streamPlayer.refreshPlayer();
|
||||
}
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import { CE } from "@utils/html"
|
||||
import { t } from "@utils/translation"
|
||||
import { STATES } from "@utils/global"
|
||||
import { PrefKey } from "@/enums/pref-keys"
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage"
|
||||
import { StreamStatsCollector, type StreamStatGrade } from "@/utils/stream-stats-collector"
|
||||
import { StreamPref } from "@/enums/pref-keys"
|
||||
import { StreamStatsCollector } from "@/utils/stream-stats-collector"
|
||||
import { BxLogger } from "@/utils/bx-logger"
|
||||
import { StreamStat } from "@/enums/pref-values"
|
||||
import { BxEventBus } from "@/utils/bx-event-bus"
|
||||
import { getStreamPref } from "@/utils/pref-utils";
|
||||
|
||||
|
||||
export class StreamStats {
|
||||
@@ -164,7 +164,7 @@ export class StreamStats {
|
||||
return;
|
||||
}
|
||||
|
||||
const PREF_STATS_CONDITIONAL_FORMATTING = getPref(PrefKey.STATS_CONDITIONAL_FORMATTING);
|
||||
const PREF_STATS_CONDITIONAL_FORMATTING = getStreamPref(StreamPref.STATS_CONDITIONAL_FORMATTING);
|
||||
let grade: StreamStatGrade = '';
|
||||
|
||||
// Collect stats
|
||||
@@ -192,12 +192,12 @@ export class StreamStats {
|
||||
}
|
||||
|
||||
refreshStyles() {
|
||||
const PREF_ITEMS = getPref(PrefKey.STATS_ITEMS);
|
||||
const PREF_OPACITY_BG = getPref(PrefKey.STATS_OPACITY_BACKGROUND);
|
||||
const PREF_ITEMS = getStreamPref(StreamPref.STATS_ITEMS);
|
||||
const PREF_OPACITY_BG = getStreamPref(StreamPref.STATS_OPACITY_BACKGROUND);
|
||||
|
||||
const $container = this.$container;
|
||||
$container.dataset.stats = '[' + PREF_ITEMS.join('][') + ']';
|
||||
$container.dataset.position = getPref(PrefKey.STATS_POSITION);
|
||||
$container.dataset.position = getStreamPref(StreamPref.STATS_POSITION);
|
||||
|
||||
if (PREF_OPACITY_BG === 0) {
|
||||
$container.style.removeProperty('background-color');
|
||||
@@ -207,12 +207,12 @@ export class StreamStats {
|
||||
$container.style.backgroundColor = `rgba(0, 0, 0, ${PREF_OPACITY_BG}%)`;
|
||||
}
|
||||
|
||||
$container.style.opacity = getPref(PrefKey.STATS_OPACITY_ALL) + '%';
|
||||
$container.style.fontSize = getPref(PrefKey.STATS_TEXT_SIZE);
|
||||
$container.style.opacity = getStreamPref(StreamPref.STATS_OPACITY_ALL) + '%';
|
||||
$container.style.fontSize = getStreamPref(StreamPref.STATS_TEXT_SIZE);
|
||||
}
|
||||
|
||||
hideSettingsUi() {
|
||||
if (this.isGlancing() && !getPref(PrefKey.STATS_QUICK_GLANCE_ENABLED)) {
|
||||
if (this.isGlancing() && !getStreamPref(StreamPref.STATS_QUICK_GLANCE_ENABLED)) {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
@@ -240,8 +240,8 @@ export class StreamStats {
|
||||
|
||||
static setupEvents() {
|
||||
BxEventBus.Stream.on('state.playing', () => {
|
||||
const PREF_STATS_QUICK_GLANCE = getPref(PrefKey.STATS_QUICK_GLANCE_ENABLED);
|
||||
const PREF_STATS_SHOW_WHEN_PLAYING = getPref(PrefKey.STATS_SHOW_WHEN_PLAYING);
|
||||
const PREF_STATS_QUICK_GLANCE = getStreamPref(StreamPref.STATS_QUICK_GLANCE_ENABLED);
|
||||
const PREF_STATS_SHOW_WHEN_PLAYING = getStreamPref(StreamPref.STATS_SHOW_WHEN_PLAYING);
|
||||
|
||||
const streamStats = StreamStats.getInstance();
|
||||
|
||||
|
@@ -4,8 +4,8 @@ import { BxEvent } from "@utils/bx-event";
|
||||
import { NATIVE_FETCH } from "@utils/bx-flags";
|
||||
import { t } from "@utils/translation";
|
||||
import { BxLogger } from "@utils/bx-logger";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
import { TouchControllerStyleCustom, TouchControllerStyleStandard } from "@/enums/pref-values";
|
||||
import { GhPagesUtils } from "@/utils/gh-pages";
|
||||
import { BxEventBus } from "@/utils/bx-event-bus";
|
||||
@@ -289,8 +289,8 @@ export class TouchController {
|
||||
|
||||
TouchController.#$style = $style;
|
||||
|
||||
const PREF_STYLE_STANDARD = getPref(PrefKey.TOUCH_CONTROLLER_STYLE_STANDARD);
|
||||
const PREF_STYLE_CUSTOM = getPref(PrefKey.TOUCH_CONTROLLER_STYLE_CUSTOM);
|
||||
const PREF_STYLE_STANDARD = getGlobalPref(GlobalPref.TOUCH_CONTROLLER_STYLE_STANDARD);
|
||||
const PREF_STYLE_CUSTOM = getGlobalPref(GlobalPref.TOUCH_CONTROLLER_STYLE_CUSTOM);
|
||||
|
||||
BxEventBus.Stream.on('dataChannelCreated', payload => {
|
||||
const { dataChannel } = payload;
|
||||
|
@@ -5,8 +5,8 @@ import { t } from "@/utils/translation";
|
||||
import { GamepadKey, GamepadKeyName } from "@/enums/gamepad";
|
||||
import { ButtonStyle, CE, createButton, createSettingRow } from "@/utils/html";
|
||||
import { BxSelectElement } from "@/web-components/bx-select";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
import { BxEvent } from "@/utils/bx-event";
|
||||
import { deepClone } from "@/utils/global";
|
||||
import { StreamSettings } from "@/utils/stream-settings";
|
||||
@@ -58,7 +58,7 @@ export class ControllerCustomizationsManagerDialog extends BaseProfileManagerDia
|
||||
}
|
||||
|
||||
private render() {
|
||||
const isControllerFriendly = getPref(PrefKey.UI_CONTROLLER_FRIENDLY);
|
||||
const isControllerFriendly = getGlobalPref(GlobalPref.UI_CONTROLLER_FRIENDLY);
|
||||
const $rows = CE('div', { class: 'bx-buttons-grid' });
|
||||
|
||||
const $baseSelect = CE('select', { class: 'bx-full-width' },
|
||||
@@ -117,7 +117,7 @@ export class ControllerCustomizationsManagerDialog extends BaseProfileManagerDia
|
||||
}
|
||||
|
||||
// Map nearby elenemts for controller-friendly UI
|
||||
if (getPref(PrefKey.UI_CONTROLLER_FRIENDLY)) {
|
||||
if (getGlobalPref(GlobalPref.UI_CONTROLLER_FRIENDLY)) {
|
||||
for (let i = 0; i < this.selectsOrder.length; i++) {
|
||||
const $select = this.selectsMap[this.selectsOrder[i] as unknown as GamepadKey] as NavigationElement;
|
||||
const directions = {
|
||||
@@ -257,7 +257,7 @@ export class ControllerCustomizationsManagerDialog extends BaseProfileManagerDia
|
||||
$label.classList.add('bx-horizontal-shaking');
|
||||
|
||||
// Focus select
|
||||
if (getPref(PrefKey.UI_CONTROLLER_FRIENDLY)) {
|
||||
if (getGlobalPref(GlobalPref.UI_CONTROLLER_FRIENDLY)) {
|
||||
this.dialogManager.focus($select);
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import { t } from "@/utils/translation";
|
||||
import { MkbMappingPresetsTable } from "@/utils/local-db/mkb-mapping-presets-table";
|
||||
import { GamepadKey, GamepadKeyName } from "@/enums/gamepad";
|
||||
import { CE, createSettingRow } from "@/utils/html";
|
||||
import { MouseMapTo, type KeyCode } from "@/enums/mkb";
|
||||
import { MouseMapTo } from "@/enums/mkb";
|
||||
import { BxKeyBindingButton, BxKeyBindingButtonFlag } from "@/web-components/bx-key-binding-button";
|
||||
import { StreamSettings } from "@/utils/stream-settings";
|
||||
import { BxNumberStepper } from "@/web-components/bx-number-stepper";
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { ButtonStyle, CE, createButton } from "@/utils/html";
|
||||
import { NavigationDialog, type NavigationElement } from "./navigation-dialog";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { BxIcon } from "@/utils/bx-icon";
|
||||
import { getPref, setPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { getGlobalPref, setGlobalPref } from "@/utils/pref-utils";
|
||||
import { t } from "@/utils/translation";
|
||||
import { RemotePlayConsoleState, RemotePlayManager } from "@/modules/remote-play-manager";
|
||||
import { BxSelectElement } from "@/web-components/bx-select";
|
||||
@@ -40,7 +40,7 @@ export class RemotePlayDialog extends NavigationDialog {
|
||||
|
||||
const $settingNote = CE('p', {});
|
||||
|
||||
const currentResolution = getPref(PrefKey.REMOTE_PLAY_STREAM_RESOLUTION);
|
||||
const currentResolution = getGlobalPref(GlobalPref.REMOTE_PLAY_STREAM_RESOLUTION);
|
||||
let $resolutions : HTMLSelectElement | NavigationElement = CE('select', false,
|
||||
CE('option', { value: StreamResolution.DIM_720P }, '720p'),
|
||||
CE('option', { value: StreamResolution.DIM_1080P }, '1080p'),
|
||||
@@ -52,7 +52,7 @@ export class RemotePlayDialog extends NavigationDialog {
|
||||
const value = (e.target as HTMLSelectElement).value;
|
||||
|
||||
$settingNote.textContent = value === '1080p' ? '✅ ' + t('can-stream-xbox-360-games') : '❌ ' + t('cant-stream-xbox-360-games');
|
||||
setPref(PrefKey.REMOTE_PLAY_STREAM_RESOLUTION, value);
|
||||
setGlobalPref(GlobalPref.REMOTE_PLAY_STREAM_RESOLUTION, value, 'ui');
|
||||
});
|
||||
|
||||
($resolutions as any).value = currentResolution;
|
||||
|
@@ -1,14 +1,12 @@
|
||||
import { isFullVersion } from "@macros/build" with { type: "macro" };
|
||||
|
||||
import { limitVideoPlayerFps, onChangeVideoPlayerType, updateVideoPlayer } from "@/modules/stream/stream-settings-utils";
|
||||
import { onChangeVideoPlayerType } from "@/modules/stream/stream-settings-utils";
|
||||
import { ButtonStyle, calculateSelectBoxes, CE, createButton, createSettingRow, createSvgIcon, escapeCssSelector, type BxButtonOptions } from "@/utils/html";
|
||||
import { NavigationDialog, NavigationDirection } from "./navigation-dialog";
|
||||
import { SoundShortcut } from "@/modules/shortcuts/sound-shortcut";
|
||||
import { StreamStats } from "@/modules/stream/stream-stats";
|
||||
import { TouchController } from "@/modules/touch-controller";
|
||||
import { BxEvent } from "@/utils/bx-event";
|
||||
import { BxIcon, type BxIconRaw } from "@/utils/bx-icon";
|
||||
import { STATES, AppInterface, deepClone, SCRIPT_VERSION, STORAGE, SCRIPT_VARIANT } from "@/utils/global";
|
||||
import { STATES, AppInterface, deepClone, SCRIPT_VERSION, SCRIPT_VARIANT } from "@/utils/global";
|
||||
import { t, Translations } from "@/utils/translation";
|
||||
import { BxSelectElement } from "@/web-components/bx-select";
|
||||
import { setNearby } from "@/utils/navigation-utils";
|
||||
@@ -17,8 +15,7 @@ import { UserAgentProfile } from "@/enums/user-agent";
|
||||
import { UserAgent } from "@/utils/user-agent";
|
||||
import { BX_FLAGS } from "@/utils/bx-flags";
|
||||
import { clearAllData, copyToClipboard } from "@/utils/utils";
|
||||
import { PrefKey, StorageKey } from "@/enums/pref-keys";
|
||||
import { getPref, getPrefDefinition, setPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref, StorageKey, StreamPref, type AnyPref } from "@/enums/pref-keys";
|
||||
import { SettingElement } from "@/utils/setting-element";
|
||||
import type { SettingDefinition, SuggestedSettingProfile } from "@/types/setting-definition";
|
||||
import { FullscreenText } from "../fullscreen-text";
|
||||
@@ -27,14 +24,14 @@ import { GamepadKey } from "@/enums/gamepad";
|
||||
import { NativeMkbHandler } from "@/modules/mkb/native-mkb-handler";
|
||||
import { ControllerExtraSettings } from "./settings/controller-extra";
|
||||
import { SuggestionsSetting } from "./settings/suggestions";
|
||||
import { StreamSettings } from "@/utils/stream-settings";
|
||||
import { MkbExtraSettings } from "./settings/mkb-extra";
|
||||
import { BxExposed } from "@/utils/bx-exposed";
|
||||
import { BxEventBus } from "@/utils/bx-event-bus";
|
||||
import { getGlobalPref, getPrefInfo, getStreamPref, isStreamPref, setGlobalPref, STORAGE } from "@/utils/pref-utils";
|
||||
import { SettingsManager } from "@/modules/settings-manager";
|
||||
|
||||
|
||||
type SettingTabSectionItem = Partial<{
|
||||
pref: PrefKey;
|
||||
pref: AnyPref;
|
||||
multiLines: boolean;
|
||||
label: string;
|
||||
note: string | (() => HTMLElement) | HTMLElement;
|
||||
@@ -43,7 +40,7 @@ type SettingTabSectionItem = Partial<{
|
||||
options: { [key: string]: string };
|
||||
unsupported: boolean;
|
||||
unsupportedNote: string;
|
||||
onChange: (e: any, value: number) => void;
|
||||
// onChange: (e: any, value: number) => void;
|
||||
onCreated: (setting: SettingTabSectionItem, $control: any) => void;
|
||||
params: any;
|
||||
requiredVariants?: BuildVariant | Array<BuildVariant>;
|
||||
@@ -59,17 +56,15 @@ type SettingTabSection = {
|
||||
unsupportedNote?: HTMLElement | string | Text | null;
|
||||
helpUrl?: string;
|
||||
content?: HTMLElement;
|
||||
lazyContent?: boolean | (() => HTMLElement);
|
||||
items?: Array<SettingTabSectionItem | PrefKey | (($parent: HTMLElement) => void) | false>;
|
||||
items?: Array<SettingTabSectionItem | AnyPref | (($parent: HTMLElement) => void) | false>;
|
||||
requiredVariants?: BuildVariant | Array<BuildVariant>;
|
||||
};
|
||||
|
||||
type SettingTab = {
|
||||
icon: BxIconRaw;
|
||||
group: SettingTabGroup,
|
||||
items: Array<SettingTabSection | HTMLElement | false> | (() => Array<SettingTabSection | false>);
|
||||
items: Array<SettingTabSection | HTMLElement | false>;
|
||||
requiredVariants?: BuildVariant | Array<BuildVariant>;
|
||||
lazyContent?: boolean;
|
||||
};
|
||||
|
||||
type SettingTabGroup = 'global' | 'stream' | 'controller' | 'mkb' | 'stats';
|
||||
@@ -87,17 +82,20 @@ export class SettingsDialog extends NavigationDialog {
|
||||
private $btnGlobalReload!: HTMLButtonElement;
|
||||
private $noteGlobalReload!: HTMLElement;
|
||||
private $btnSuggestion!: HTMLDivElement;
|
||||
private $streamSettingsSelection!: HTMLElement;
|
||||
|
||||
private renderFullSettings: boolean;
|
||||
protected boundOnContextMenu: any;
|
||||
|
||||
protected suggestedSettings: Record<SuggestedSettingProfile, PartialRecord<PrefKey, any>> = {
|
||||
protected suggestedSettings: Record<SuggestedSettingProfile, PartialRecord<AnyPref, any>> = {
|
||||
recommended: {},
|
||||
default: {},
|
||||
lowest: {},
|
||||
highest: {},
|
||||
};
|
||||
protected suggestedSettingLabels: PartialRecord<PrefKey, string> = {};
|
||||
protected settingElements: PartialRecord<PrefKey, HTMLElement> = {};
|
||||
protected settingLabels: PartialRecord<AnyPref, string> = {};
|
||||
|
||||
protected settingsManager: SettingsManager;
|
||||
|
||||
private readonly TAB_GLOBAL_ITEMS: Array<SettingTabSection | false> = [{
|
||||
group: 'general',
|
||||
@@ -106,7 +104,7 @@ export class SettingsDialog extends NavigationDialog {
|
||||
items: [
|
||||
// Top buttons
|
||||
($parent) => {
|
||||
const PREF_LATEST_VERSION = getPref(PrefKey.VERSION_LATEST);
|
||||
const PREF_LATEST_VERSION = getGlobalPref(GlobalPref.VERSION_LATEST);
|
||||
const topButtons = [];
|
||||
|
||||
// "New version available" button
|
||||
@@ -188,57 +186,57 @@ export class SettingsDialog extends NavigationDialog {
|
||||
},
|
||||
|
||||
{
|
||||
pref: PrefKey.SCRIPT_LOCALE,
|
||||
pref: GlobalPref.SCRIPT_LOCALE,
|
||||
multiLines: true,
|
||||
},
|
||||
PrefKey.SERVER_BYPASS_RESTRICTION,
|
||||
PrefKey.UI_CONTROLLER_FRIENDLY,
|
||||
PrefKey.REMOTE_PLAY_ENABLED,
|
||||
GlobalPref.SERVER_BYPASS_RESTRICTION,
|
||||
GlobalPref.UI_CONTROLLER_FRIENDLY,
|
||||
GlobalPref.REMOTE_PLAY_ENABLED,
|
||||
],
|
||||
}, {
|
||||
group: 'server',
|
||||
label: t('server'),
|
||||
items: [
|
||||
{
|
||||
pref: PrefKey.SERVER_REGION,
|
||||
pref: GlobalPref.SERVER_REGION,
|
||||
multiLines: true,
|
||||
},
|
||||
{
|
||||
pref: PrefKey.STREAM_PREFERRED_LOCALE,
|
||||
pref: GlobalPref.STREAM_PREFERRED_LOCALE,
|
||||
multiLines: true,
|
||||
},
|
||||
PrefKey.SERVER_PREFER_IPV6,
|
||||
GlobalPref.SERVER_PREFER_IPV6,
|
||||
],
|
||||
}, {
|
||||
group: 'stream',
|
||||
label: t('stream'),
|
||||
items: [
|
||||
PrefKey.STREAM_RESOLUTION,
|
||||
PrefKey.STREAM_CODEC_PROFILE,
|
||||
PrefKey.STREAM_MAX_VIDEO_BITRATE,
|
||||
GlobalPref.STREAM_RESOLUTION,
|
||||
GlobalPref.STREAM_CODEC_PROFILE,
|
||||
GlobalPref.STREAM_MAX_VIDEO_BITRATE,
|
||||
|
||||
PrefKey.AUDIO_VOLUME_CONTROL_ENABLED,
|
||||
GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED,
|
||||
|
||||
PrefKey.SCREENSHOT_APPLY_FILTERS,
|
||||
GlobalPref.SCREENSHOT_APPLY_FILTERS,
|
||||
|
||||
PrefKey.AUDIO_MIC_ON_PLAYING,
|
||||
PrefKey.GAME_FORTNITE_FORCE_CONSOLE,
|
||||
PrefKey.STREAM_COMBINE_SOURCES,
|
||||
GlobalPref.AUDIO_MIC_ON_PLAYING,
|
||||
GlobalPref.GAME_FORTNITE_FORCE_CONSOLE,
|
||||
GlobalPref.STREAM_COMBINE_SOURCES,
|
||||
],
|
||||
}, {
|
||||
requiredVariants: 'full',
|
||||
group: 'mkb',
|
||||
label: t('mouse-and-keyboard'),
|
||||
items: [
|
||||
PrefKey.NATIVE_MKB_MODE,
|
||||
GlobalPref.NATIVE_MKB_MODE,
|
||||
{
|
||||
pref: PrefKey.NATIVE_MKB_FORCED_GAMES,
|
||||
pref: GlobalPref.NATIVE_MKB_FORCED_GAMES,
|
||||
multiLines: true,
|
||||
note: CE('a', { href: 'https://github.com/redphx/better-xcloud/discussions/574', target: '_blank' }, t('unofficial-game-list')),
|
||||
},
|
||||
|
||||
PrefKey.MKB_ENABLED,
|
||||
PrefKey.MKB_HIDE_IDLE_CURSOR,
|
||||
GlobalPref.MKB_ENABLED,
|
||||
GlobalPref.MKB_HIDE_IDLE_CURSOR,
|
||||
],
|
||||
|
||||
// Unsupported
|
||||
@@ -255,13 +253,13 @@ export class SettingsDialog extends NavigationDialog {
|
||||
label: t('touch-controller'),
|
||||
items: [
|
||||
{
|
||||
pref: PrefKey.TOUCH_CONTROLLER_MODE,
|
||||
pref: GlobalPref.TOUCH_CONTROLLER_MODE,
|
||||
note: CE('a', { href: 'https://github.com/redphx/better-xcloud/discussions/241', target: '_blank' }, t('unofficial-game-list')),
|
||||
},
|
||||
PrefKey.TOUCH_CONTROLLER_AUTO_OFF,
|
||||
PrefKey.TOUCH_CONTROLLER_DEFAULT_OPACITY,
|
||||
PrefKey.TOUCH_CONTROLLER_STYLE_STANDARD,
|
||||
PrefKey.TOUCH_CONTROLLER_STYLE_CUSTOM,
|
||||
GlobalPref.TOUCH_CONTROLLER_AUTO_OFF,
|
||||
GlobalPref.TOUCH_CONTROLLER_DEFAULT_OPACITY,
|
||||
GlobalPref.TOUCH_CONTROLLER_STYLE_STANDARD,
|
||||
GlobalPref.TOUCH_CONTROLLER_STYLE_CUSTOM,
|
||||
],
|
||||
|
||||
// Unsupported
|
||||
@@ -273,22 +271,22 @@ export class SettingsDialog extends NavigationDialog {
|
||||
group: 'ui',
|
||||
label: t('ui'),
|
||||
items: [
|
||||
PrefKey.UI_LAYOUT,
|
||||
PrefKey.UI_IMAGE_QUALITY,
|
||||
PrefKey.UI_GAME_CARD_SHOW_WAIT_TIME,
|
||||
PrefKey.UI_CONTROLLER_SHOW_STATUS,
|
||||
PrefKey.UI_SIMPLIFY_STREAM_MENU,
|
||||
PrefKey.UI_SKIP_SPLASH_VIDEO,
|
||||
!AppInterface && PrefKey.UI_SCROLLBAR_HIDE,
|
||||
PrefKey.UI_HIDE_SYSTEM_MENU_ICON,
|
||||
PrefKey.UI_DISABLE_FEEDBACK_DIALOG,
|
||||
PrefKey.UI_REDUCE_ANIMATIONS,
|
||||
GlobalPref.UI_LAYOUT,
|
||||
GlobalPref.UI_IMAGE_QUALITY,
|
||||
GlobalPref.UI_GAME_CARD_SHOW_WAIT_TIME,
|
||||
GlobalPref.UI_CONTROLLER_SHOW_STATUS,
|
||||
GlobalPref.UI_SIMPLIFY_STREAM_MENU,
|
||||
GlobalPref.UI_SKIP_SPLASH_VIDEO,
|
||||
!AppInterface && GlobalPref.UI_SCROLLBAR_HIDE,
|
||||
GlobalPref.UI_HIDE_SYSTEM_MENU_ICON,
|
||||
GlobalPref.UI_DISABLE_FEEDBACK_DIALOG,
|
||||
GlobalPref.UI_REDUCE_ANIMATIONS,
|
||||
{
|
||||
pref: PrefKey.UI_HIDE_SECTIONS,
|
||||
pref: GlobalPref.UI_HIDE_SECTIONS,
|
||||
multiLines: true,
|
||||
},
|
||||
{
|
||||
pref: PrefKey.BLOCK_FEATURES,
|
||||
pref: GlobalPref.BLOCK_FEATURES,
|
||||
multiLines: true,
|
||||
},
|
||||
],
|
||||
@@ -297,28 +295,28 @@ export class SettingsDialog extends NavigationDialog {
|
||||
group: 'game-bar',
|
||||
label: t('game-bar'),
|
||||
items: [
|
||||
PrefKey.GAME_BAR_POSITION,
|
||||
GlobalPref.GAME_BAR_POSITION,
|
||||
],
|
||||
}, {
|
||||
group: 'loading-screen',
|
||||
label: t('loading-screen'),
|
||||
items: [
|
||||
PrefKey.LOADING_SCREEN_GAME_ART,
|
||||
PrefKey.LOADING_SCREEN_SHOW_WAIT_TIME,
|
||||
PrefKey.LOADING_SCREEN_ROCKET,
|
||||
GlobalPref.LOADING_SCREEN_GAME_ART,
|
||||
GlobalPref.LOADING_SCREEN_SHOW_WAIT_TIME,
|
||||
GlobalPref.LOADING_SCREEN_ROCKET,
|
||||
],
|
||||
}, {
|
||||
group: 'other',
|
||||
label: t('other'),
|
||||
items: [
|
||||
PrefKey.BLOCK_TRACKING,
|
||||
GlobalPref.BLOCK_TRACKING,
|
||||
],
|
||||
}, isFullVersion() && {
|
||||
group: 'advanced',
|
||||
label: t('advanced'),
|
||||
items: [
|
||||
{
|
||||
pref: PrefKey.USER_AGENT_PROFILE,
|
||||
pref: GlobalPref.USER_AGENT_PROFILE,
|
||||
multiLines: true,
|
||||
onCreated: (setting, $control) => {
|
||||
const defaultUserAgent = window.navigator.orgUserAgent || window.navigator.userAgent;
|
||||
@@ -429,20 +427,17 @@ export class SettingsDialog extends NavigationDialog {
|
||||
label: t('audio'),
|
||||
helpUrl: 'https://better-xcloud.github.io/ingame-features/#audio',
|
||||
items: [{
|
||||
pref: PrefKey.AUDIO_VOLUME,
|
||||
onChange: (e: any, value: number) => {
|
||||
SoundShortcut.setGainNodeVolume(value);
|
||||
},
|
||||
pref: StreamPref.AUDIO_VOLUME,
|
||||
params: {
|
||||
disabled: !getPref(PrefKey.AUDIO_VOLUME_CONTROL_ENABLED),
|
||||
disabled: !getGlobalPref(GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED),
|
||||
},
|
||||
onCreated: (setting: SettingTabSectionItem, $elm: HTMLElement) => {
|
||||
const $range = $elm.querySelector<HTMLInputElement>('input[type=range')!;
|
||||
|
||||
BxEventBus.Script.on('setting.changed', payload => {
|
||||
const { storageKey, settingKey, settingValue } = payload;
|
||||
if (storageKey === StorageKey.GLOBAL && settingKey === PrefKey.AUDIO_VOLUME) {
|
||||
$range.value = settingValue;
|
||||
BxEventBus.Stream.on('setting.changed', payload => {
|
||||
const { settingKey } = payload;
|
||||
if (settingKey === StreamPref.AUDIO_VOLUME) {
|
||||
$range.value = getStreamPref(settingKey).toString();
|
||||
BxEvent.dispatch($range, 'input', { ignoreOnChange: true });
|
||||
}
|
||||
});
|
||||
@@ -452,47 +447,18 @@ export class SettingsDialog extends NavigationDialog {
|
||||
group: 'video',
|
||||
label: t('video'),
|
||||
helpUrl: 'https://better-xcloud.github.io/ingame-features/#video',
|
||||
items: [{
|
||||
pref: PrefKey.VIDEO_PLAYER_TYPE,
|
||||
onChange: onChangeVideoPlayerType,
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_MAX_FPS,
|
||||
onChange: e => {
|
||||
limitVideoPlayerFps(parseInt(e.target.value));
|
||||
},
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_POWER_PREFERENCE,
|
||||
onChange: () => {
|
||||
const streamPlayer = STATES.currentStream.streamPlayer;
|
||||
if (!streamPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
streamPlayer.reloadPlayer();
|
||||
updateVideoPlayer();
|
||||
},
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_PROCESSING,
|
||||
onChange: updateVideoPlayer,
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_RATIO,
|
||||
onChange: updateVideoPlayer,
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_POSITION,
|
||||
onChange: updateVideoPlayer,
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_SHARPNESS,
|
||||
onChange: updateVideoPlayer,
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_SATURATION,
|
||||
onChange: updateVideoPlayer,
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_CONTRAST,
|
||||
onChange: updateVideoPlayer,
|
||||
}, {
|
||||
pref: PrefKey.VIDEO_BRIGHTNESS,
|
||||
onChange: updateVideoPlayer,
|
||||
}],
|
||||
items: [
|
||||
StreamPref.VIDEO_PLAYER_TYPE,
|
||||
StreamPref.VIDEO_MAX_FPS,
|
||||
StreamPref.VIDEO_POWER_PREFERENCE,
|
||||
StreamPref.VIDEO_PROCESSING,
|
||||
StreamPref.VIDEO_RATIO,
|
||||
StreamPref.VIDEO_POSITION,
|
||||
StreamPref.VIDEO_SHARPNESS,
|
||||
StreamPref.VIDEO_SATURATION,
|
||||
StreamPref.VIDEO_CONTRAST,
|
||||
StreamPref.VIDEO_BRIGHTNESS,
|
||||
],
|
||||
}];
|
||||
|
||||
private readonly TAB_CONTROLLER_ITEMS: Array<SettingTabSection | HTMLElement | false> = isFullVersion() ? [{
|
||||
@@ -500,15 +466,12 @@ export class SettingsDialog extends NavigationDialog {
|
||||
label: t('controller'),
|
||||
helpUrl: 'https://better-xcloud.github.io/ingame-features/#controller',
|
||||
items: [
|
||||
{
|
||||
pref: PrefKey.LOCAL_CO_OP_ENABLED,
|
||||
onChange: () => { BxExposed.toggleLocalCoOp(getPref(PrefKey.LOCAL_CO_OP_ENABLED)); },
|
||||
}, {
|
||||
pref: PrefKey.CONTROLLER_POLLING_RATE,
|
||||
onChange: () => StreamSettings.refreshControllerSettings(),
|
||||
}, ($parent => {
|
||||
$parent.appendChild(ControllerExtraSettings.renderSettings.apply(this));
|
||||
})],
|
||||
StreamPref.LOCAL_CO_OP_ENABLED,
|
||||
StreamPref.CONTROLLER_POLLING_RATE,
|
||||
($parent => {
|
||||
$parent.appendChild(ControllerExtraSettings.renderSettings.apply(this));
|
||||
}),
|
||||
],
|
||||
},
|
||||
|
||||
STATES.userAgent.capabilities.touch && {
|
||||
@@ -569,18 +532,16 @@ export class SettingsDialog extends NavigationDialog {
|
||||
group: 'device',
|
||||
label: t('device'),
|
||||
items: [{
|
||||
pref: PrefKey.DEVICE_VIBRATION_MODE,
|
||||
pref: StreamPref.DEVICE_VIBRATION_MODE,
|
||||
multiLines: true,
|
||||
unsupported: !STATES.browser.capabilities.deviceVibration,
|
||||
onChange: () => StreamSettings.refreshControllerSettings(),
|
||||
}, {
|
||||
pref: PrefKey.DEVICE_VIBRATION_INTENSITY,
|
||||
pref: StreamPref.DEVICE_VIBRATION_INTENSITY,
|
||||
unsupported: !STATES.browser.capabilities.deviceVibration,
|
||||
onChange: () => StreamSettings.refreshControllerSettings(),
|
||||
}],
|
||||
}] : [];
|
||||
|
||||
private readonly TAB_MKB_ITEMS: (() => Array<SettingTabSection | false>) = isFullVersion() ? () => [
|
||||
private readonly TAB_MKB_ITEMS: Array<SettingTabSection | false> = isFullVersion() ? [
|
||||
{
|
||||
requiredVariants: 'full',
|
||||
group: 'mkb',
|
||||
@@ -597,50 +558,25 @@ export class SettingsDialog extends NavigationDialog {
|
||||
requiredVariants: 'full',
|
||||
group: 'native-mkb',
|
||||
label: t('native-mkb'),
|
||||
items: isFullVersion() ? [{
|
||||
pref: PrefKey.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY,
|
||||
onChange: (e: any, value: number) => {
|
||||
NativeMkbHandler.getInstance()?.setVerticalScrollMultiplier(value / 100);
|
||||
},
|
||||
}, {
|
||||
pref: PrefKey.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY,
|
||||
onChange: (e: any, value: number) => {
|
||||
NativeMkbHandler.getInstance()?.setHorizontalScrollMultiplier(value / 100);
|
||||
},
|
||||
}] : [],
|
||||
}] : () => [];
|
||||
items: [
|
||||
StreamPref.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY,
|
||||
StreamPref.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY,
|
||||
],
|
||||
}] : [];
|
||||
|
||||
private readonly TAB_STATS_ITEMS: Array<SettingTabSection | false> = [{
|
||||
group: 'stats',
|
||||
label: t('stream-stats'),
|
||||
helpUrl: 'https://better-xcloud.github.io/stream-stats/',
|
||||
items: [{
|
||||
pref: PrefKey.STATS_SHOW_WHEN_PLAYING,
|
||||
}, {
|
||||
pref: PrefKey.STATS_QUICK_GLANCE_ENABLED,
|
||||
onChange: (e: InputEvent) => {
|
||||
const streamStats = StreamStats.getInstance();
|
||||
(e.target! as HTMLInputElement).checked ? streamStats.quickGlanceSetup() : streamStats.quickGlanceStop();
|
||||
},
|
||||
}, {
|
||||
pref: PrefKey.STATS_ITEMS,
|
||||
onChange: StreamStats.refreshStyles,
|
||||
}, {
|
||||
pref: PrefKey.STATS_POSITION,
|
||||
onChange: StreamStats.refreshStyles,
|
||||
}, {
|
||||
pref: PrefKey.STATS_TEXT_SIZE,
|
||||
onChange: StreamStats.refreshStyles,
|
||||
}, {
|
||||
pref: PrefKey.STATS_OPACITY_ALL,
|
||||
onChange: StreamStats.refreshStyles,
|
||||
}, {
|
||||
pref: PrefKey.STATS_OPACITY_BACKGROUND,
|
||||
onChange: StreamStats.refreshStyles,
|
||||
}, {
|
||||
pref: PrefKey.STATS_CONDITIONAL_FORMATTING,
|
||||
onChange: StreamStats.refreshStyles,
|
||||
},
|
||||
items: [
|
||||
StreamPref.STATS_SHOW_WHEN_PLAYING,
|
||||
StreamPref.STATS_QUICK_GLANCE_ENABLED,
|
||||
StreamPref.STATS_ITEMS,
|
||||
StreamPref.STATS_POSITION,
|
||||
StreamPref.STATS_TEXT_SIZE,
|
||||
StreamPref.STATS_OPACITY_ALL,
|
||||
StreamPref.STATS_OPACITY_BACKGROUND,
|
||||
StreamPref.STATS_CONDITIONAL_FORMATTING,
|
||||
],
|
||||
}];
|
||||
|
||||
@@ -668,7 +604,6 @@ export class SettingsDialog extends NavigationDialog {
|
||||
group: 'mkb',
|
||||
icon: BxIcon.NATIVE_MKB,
|
||||
items: this.TAB_MKB_ITEMS,
|
||||
lazyContent: true,
|
||||
requiredVariants: 'full',
|
||||
},
|
||||
|
||||
@@ -683,6 +618,8 @@ export class SettingsDialog extends NavigationDialog {
|
||||
super();
|
||||
BxLogger.info(this.LOG_TAG, 'constructor()');
|
||||
|
||||
this.boundOnContextMenu = this.onContextMenu.bind(this);
|
||||
this.settingsManager = SettingsManager.getInstance();
|
||||
this.renderFullSettings = STATES.supportedRegion && STATES.isSignedIn;
|
||||
this.setupDialog();
|
||||
|
||||
@@ -696,13 +633,17 @@ export class SettingsDialog extends NavigationDialog {
|
||||
}
|
||||
|
||||
// Trigger event
|
||||
const $selectUserAgent = document.querySelector<HTMLSelectElement>(`#bx_setting_${escapeCssSelector(PrefKey.USER_AGENT_PROFILE)}`);
|
||||
const $selectUserAgent = document.querySelector<HTMLSelectElement>(`#bx_setting_${escapeCssSelector(GlobalPref.USER_AGENT_PROFILE)}`);
|
||||
if ($selectUserAgent) {
|
||||
$selectUserAgent.disabled = true;
|
||||
BxEvent.dispatch($selectUserAgent, 'input', {});
|
||||
$selectUserAgent.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
BxEventBus.Stream.on('gameSettings.switched', ({ id }) => {
|
||||
this.$tabContents.dataset.gameId = id.toString();
|
||||
});
|
||||
}
|
||||
|
||||
getDialog(): NavigationDialog {
|
||||
@@ -742,21 +683,6 @@ export class SettingsDialog extends NavigationDialog {
|
||||
private onTabClicked = (e: Event) => {
|
||||
const $svg = (e.target as SVGElement).closest('svg')!;
|
||||
|
||||
// Render tab content lazily
|
||||
if (!!$svg.dataset.lazy) {
|
||||
// Remove attribute
|
||||
delete $svg.dataset.lazy;
|
||||
// Render data
|
||||
const settingTab = this.SETTINGS_UI[$svg.dataset.group as SettingTabGroup];
|
||||
if (!settingTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
const items = (settingTab.items as Function)();
|
||||
const $tabContent = this.renderSettingsSection.call(this, settingTab, items);
|
||||
this.$tabContents.appendChild($tabContent);
|
||||
}
|
||||
|
||||
// Switch tab
|
||||
let $child: HTMLElement;
|
||||
const children = Array.from(this.$tabContents.children) as HTMLElement[];
|
||||
@@ -767,12 +693,15 @@ export class SettingsDialog extends NavigationDialog {
|
||||
|
||||
// Calculate size of controller-friendly select boxes
|
||||
calculateSelectBoxes($child as HTMLElement);
|
||||
} else {
|
||||
} else if ($child.dataset.tabGroup) {
|
||||
// Hide tab content
|
||||
$child.classList.add('bx-gone');
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle stream settings selection
|
||||
this.$streamSettingsSelection.classList.toggle('bx-gone', $svg.dataset.group === 'global');
|
||||
|
||||
// Highlight current tab button
|
||||
for (const $child of Array.from(this.$tabs.children)) {
|
||||
$child.classList.remove('bx-active');
|
||||
@@ -785,10 +714,8 @@ export class SettingsDialog extends NavigationDialog {
|
||||
const $svg = createSvgIcon(settingTab.icon as any);
|
||||
$svg.dataset.group = settingTab.group;
|
||||
$svg.tabIndex = 0;
|
||||
settingTab.lazyContent && ($svg.dataset.lazy = settingTab.lazyContent.toString());
|
||||
|
||||
$svg.addEventListener('click', this.onTabClicked);
|
||||
|
||||
return $svg;
|
||||
}
|
||||
|
||||
@@ -803,8 +730,14 @@ export class SettingsDialog extends NavigationDialog {
|
||||
this.$btnGlobalReload.classList.add('bx-danger');
|
||||
}
|
||||
|
||||
private onContextMenu(e: Event) {
|
||||
e.preventDefault();
|
||||
const $elm = e.target;
|
||||
$elm instanceof HTMLElement && this.resetHighlightedSetting($elm);
|
||||
}
|
||||
|
||||
private renderServerSetting(setting: SettingTabSectionItem): HTMLElement {
|
||||
let selectedValue = getPref(PrefKey.SERVER_REGION);
|
||||
let selectedValue = getGlobalPref(GlobalPref.SERVER_REGION);
|
||||
|
||||
const continents: Record<ServerContinent, {
|
||||
label: string,
|
||||
@@ -837,7 +770,7 @@ export class SettingsDialog extends NavigationDialog {
|
||||
$control.name = $control.id;
|
||||
|
||||
$control.addEventListener('input', (e: Event) => {
|
||||
setPref(setting.pref!, (e.target as HTMLSelectElement).value);
|
||||
setGlobalPref(setting.pref! as GlobalPref, (e.target as HTMLSelectElement).value, 'ui');
|
||||
this.onGlobalSettingChanged(e);
|
||||
});
|
||||
|
||||
@@ -889,13 +822,14 @@ export class SettingsDialog extends NavigationDialog {
|
||||
}
|
||||
|
||||
private renderSettingRow(settingTab: SettingTab, $tabContent: HTMLElement, settingTabContent: SettingTabSection, setting: SettingTabSectionItem | string) {
|
||||
// Convert pref key to object
|
||||
if (typeof setting === 'string') {
|
||||
setting = {
|
||||
pref: setting as PrefKey,
|
||||
pref: setting as AnyPref,
|
||||
} satisfies SettingTabSectionItem;
|
||||
}
|
||||
|
||||
const pref = setting.pref;
|
||||
const pref = setting.pref!;
|
||||
|
||||
let $control;
|
||||
if (setting.content) {
|
||||
@@ -905,13 +839,13 @@ export class SettingsDialog extends NavigationDialog {
|
||||
$control = setting.content;
|
||||
}
|
||||
} else if (!setting.unsupported) {
|
||||
if (pref === PrefKey.SERVER_REGION) {
|
||||
if (pref === GlobalPref.SERVER_REGION) {
|
||||
$control = this.renderServerSetting(setting);
|
||||
} else if (pref === PrefKey.SCRIPT_LOCALE) {
|
||||
$control = SettingElement.fromPref(pref, STORAGE.Global, async (e: Event) => {
|
||||
} else if (pref === GlobalPref.SCRIPT_LOCALE) {
|
||||
$control = SettingElement.fromPref(pref, async (e: Event) => {
|
||||
const newLocale = (e.target as HTMLSelectElement).value;
|
||||
|
||||
if (getPref(PrefKey.UI_CONTROLLER_FRIENDLY)) {
|
||||
if (getGlobalPref(GlobalPref.UI_CONTROLLER_FRIENDLY)) {
|
||||
let timeoutId = (e.target as any).timeoutId;
|
||||
timeoutId && window.clearTimeout(timeoutId);
|
||||
(e.target as any).timeoutId = window.setTimeout(() => {
|
||||
@@ -926,8 +860,8 @@ export class SettingsDialog extends NavigationDialog {
|
||||
|
||||
this.onGlobalSettingChanged(e);
|
||||
});
|
||||
} else if (pref === PrefKey.USER_AGENT_PROFILE) {
|
||||
$control = SettingElement.fromPref(PrefKey.USER_AGENT_PROFILE, STORAGE.Global, (e: Event) => {
|
||||
} else if (pref === GlobalPref.USER_AGENT_PROFILE) {
|
||||
$control = SettingElement.fromPref(GlobalPref.USER_AGENT_PROFILE, (e: Event) => {
|
||||
const $target = e.target as HTMLSelectElement;
|
||||
const value = $target.value as UserAgentProfile;
|
||||
let isCustom = value === UserAgentProfile.CUSTOM;
|
||||
@@ -943,25 +877,21 @@ export class SettingsDialog extends NavigationDialog {
|
||||
!(e.target as HTMLInputElement).disabled && this.onGlobalSettingChanged(e);
|
||||
});
|
||||
} else {
|
||||
let onChange = setting.onChange;
|
||||
if (!onChange && settingTab.group === 'global') {
|
||||
onChange = this.onGlobalSettingChanged;
|
||||
$control = this.settingsManager.getElement(pref, setting.params);
|
||||
if (settingTab.group === 'global') {
|
||||
$control.addEventListener('input', this.onGlobalSettingChanged);
|
||||
}
|
||||
|
||||
$control = SettingElement.fromPref(pref as PrefKey, STORAGE.Global, onChange, setting.params);
|
||||
}
|
||||
|
||||
// Replace <select> with controller-friendly one
|
||||
if ($control instanceof HTMLSelectElement) {
|
||||
$control = BxSelectElement.create($control);
|
||||
}
|
||||
|
||||
pref && (this.settingElements[pref] = $control);
|
||||
}
|
||||
|
||||
let prefDefinition: SettingDefinition | null = null;
|
||||
if (pref) {
|
||||
prefDefinition = getPrefDefinition(pref);
|
||||
prefDefinition = getPrefInfo(pref).definition;
|
||||
}
|
||||
|
||||
if (prefDefinition && !this.isSupportedVariant(prefDefinition.requiredVariants)) {
|
||||
@@ -1010,6 +940,8 @@ export class SettingsDialog extends NavigationDialog {
|
||||
$note,
|
||||
multiLines: setting.multiLines,
|
||||
icon: prefDefinition?.labelIcon,
|
||||
onContextMenu: this.boundOnContextMenu,
|
||||
pref: pref,
|
||||
});
|
||||
if (pref) {
|
||||
$row.htmlFor = `bx_setting_${escapeCssSelector(pref)}`;
|
||||
@@ -1023,7 +955,9 @@ export class SettingsDialog extends NavigationDialog {
|
||||
private renderSettingsSection(settingTab: SettingTab, sections: Array<SettingTabSection | HTMLElement | false>): HTMLElement {
|
||||
const $tabContent = CE('div', {
|
||||
class: 'bx-gone',
|
||||
'data-tab-group': settingTab.group,
|
||||
_dataset: {
|
||||
tabGroup: settingTab.group,
|
||||
},
|
||||
});
|
||||
|
||||
for (const section of sections) {
|
||||
@@ -1168,21 +1102,31 @@ export class SettingsDialog extends NavigationDialog {
|
||||
),
|
||||
),
|
||||
|
||||
$tabContents = CE('div', {
|
||||
class: 'bx-settings-tab-contents',
|
||||
_nearby: {
|
||||
orientation: 'vertical',
|
||||
focus: () => this.jumpToSettingGroup('next'),
|
||||
loop: direction => {
|
||||
if (direction === NavigationDirection.UP || direction === NavigationDirection.DOWN) {
|
||||
this.focusVisibleSetting(direction === NavigationDirection.UP ? 'last' : 'first');
|
||||
return true;
|
||||
}
|
||||
CE('div', {
|
||||
class: 'bx-settings-tab-contents',
|
||||
_nearby: {
|
||||
orientation: 'vertical',
|
||||
loop: direction => {
|
||||
if (direction === NavigationDirection.UP || direction === NavigationDirection.DOWN) {
|
||||
this.focusVisibleSetting(direction === NavigationDirection.UP ? 'last' : 'first');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
return false;
|
||||
},
|
||||
}
|
||||
},
|
||||
}),
|
||||
// Render global/per-game settings selection
|
||||
this.$streamSettingsSelection = SettingsManager.getInstance().getStreamSettingsSelection(),
|
||||
|
||||
$tabContents = CE('div', {
|
||||
class: 'bx-settings-tab-content',
|
||||
_nearby: {
|
||||
orientation: 'vertical',
|
||||
focus: () => this.jumpToSettingGroup('next'),
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
this.$container = $container;
|
||||
@@ -1198,6 +1142,7 @@ export class SettingsDialog extends NavigationDialog {
|
||||
}
|
||||
});
|
||||
|
||||
// Render tab contents
|
||||
let settingTabGroup: keyof typeof this.SETTINGS_UI
|
||||
for (settingTabGroup in this.SETTINGS_UI) {
|
||||
const settingTab = this.SETTINGS_UI[settingTabGroup];
|
||||
@@ -1219,11 +1164,6 @@ export class SettingsDialog extends NavigationDialog {
|
||||
const $svg = this.renderTab(settingTab);
|
||||
$tabs.appendChild($svg);
|
||||
|
||||
// Don't render lazy tab content
|
||||
if (typeof settingTab.items === 'function') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const $tabContent = this.renderSettingsSection.call(this, settingTab, settingTab.items);
|
||||
$tabContents.appendChild($tabContent);
|
||||
}
|
||||
@@ -1344,6 +1284,44 @@ export class SettingsDialog extends NavigationDialog {
|
||||
return false;
|
||||
}
|
||||
|
||||
private resetHighlightedSetting($elm?: HTMLElement) {
|
||||
const targetGameId = SettingsManager.getInstance().getTargetGameId();
|
||||
if (targetGameId < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$elm) {
|
||||
// Get focusing element
|
||||
$elm = document.activeElement instanceof HTMLElement ? document.activeElement : undefined;
|
||||
}
|
||||
|
||||
const $row = $elm?.closest('div[data-tab-group] > .bx-settings-row');
|
||||
if (!$row) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pref = ($row as any).prefKey;
|
||||
if (!pref) {
|
||||
alert('Pref not found: ' + $row.id);
|
||||
}
|
||||
|
||||
if (!isStreamPref(pref)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete settings
|
||||
const gameSettings = STORAGE.Stream.getGameSettings(targetGameId);
|
||||
const deleted = gameSettings?.deleteSetting(pref);
|
||||
if (deleted) {
|
||||
BxEventBus.Stream.emit('setting.changed', {
|
||||
storageKey: `${StorageKey.STREAM}.${targetGameId}`,
|
||||
settingKey: pref,
|
||||
});
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
handleKeyPress(key: string): boolean {
|
||||
let handled = true;
|
||||
switch (key) {
|
||||
@@ -1362,6 +1340,9 @@ export class SettingsDialog extends NavigationDialog {
|
||||
case 'PageDown':
|
||||
this.jumpToSettingGroup('next');
|
||||
break;
|
||||
case 'KeyQ':
|
||||
this.resetHighlightedSetting();
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
@@ -1394,6 +1375,9 @@ export class SettingsDialog extends NavigationDialog {
|
||||
case GamepadKey.RT:
|
||||
this.jumpToSettingGroup('next');
|
||||
break;
|
||||
case GamepadKey.X:
|
||||
this.resetHighlightedSetting();
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
|
@@ -1,16 +1,17 @@
|
||||
import { BxEvent } from "@/utils/bx-event";
|
||||
import { getUniqueGamepadNames } from "@/utils/gamepad";
|
||||
import { getUniqueGamepadNames, simplifyGamepadName } from "@/utils/gamepad";
|
||||
import { CE, removeChildElements, createButton, ButtonStyle, createSettingRow, renderPresetsList, calculateSelectBoxes } from "@/utils/html";
|
||||
import { t } from "@/utils/translation";
|
||||
import { BxSelectElement } from "@/web-components/bx-select";
|
||||
import { ControllerShortcutsManagerDialog } from "../profile-manger/controller-shortcuts-manager-dialog";
|
||||
import type { SettingsDialog } from "../settings-dialog";
|
||||
import { ControllerShortcutsTable } from "@/utils/local-db/controller-shortcuts-table";
|
||||
import { ControllerSettingsTable } from "@/utils/local-db/controller-settings-table";
|
||||
import { StreamSettings } from "@/utils/stream-settings";
|
||||
import { ControllerCustomizationsTable } from "@/utils/local-db/controller-customizations-table";
|
||||
import { ControllerCustomizationsManagerDialog } from "../profile-manger/controller-customizations-manager-dialog";
|
||||
import { BxIcon } from "@/utils/bx-icon";
|
||||
import { getStreamPref, setStreamPref, STORAGE } from "@/utils/pref-utils";
|
||||
import { StreamPref } from "@/enums/pref-keys";
|
||||
|
||||
export class ControllerExtraSettings extends HTMLElement {
|
||||
currentControllerId!: string;
|
||||
@@ -26,16 +27,23 @@ export class ControllerExtraSettings extends HTMLElement {
|
||||
getCurrentControllerId!: typeof ControllerExtraSettings['getCurrentControllerId'];
|
||||
saveSettings!: typeof ControllerExtraSettings['saveSettings'];
|
||||
updateCustomizationSummary!: typeof ControllerExtraSettings['updateCustomizationSummary'];
|
||||
setValue!: typeof ControllerExtraSettings['setValue'];
|
||||
|
||||
static renderSettings(this: SettingsDialog): HTMLElement {
|
||||
const $container = CE('label', {
|
||||
class: 'bx-settings-row bx-controller-extra-settings',
|
||||
}) as unknown as ControllerExtraSettings;
|
||||
|
||||
// Setting up for Settings Manager
|
||||
($container as any).prefKey = StreamPref.CONTROLLER_SETTINGS;
|
||||
$container.addEventListener('contextmenu', this.boundOnContextMenu);
|
||||
this.settingsManager.setElement(StreamPref.CONTROLLER_SETTINGS, $container);
|
||||
|
||||
$container.updateLayout = ControllerExtraSettings.updateLayout.bind($container);
|
||||
$container.switchController = ControllerExtraSettings.switchController.bind($container);
|
||||
$container.getCurrentControllerId = ControllerExtraSettings.getCurrentControllerId.bind($container);
|
||||
$container.saveSettings = ControllerExtraSettings.saveSettings.bind($container);
|
||||
$container.setValue = ControllerExtraSettings.setValue.bind($container);
|
||||
|
||||
const $selectControllers = BxSelectElement.create(CE('select', {
|
||||
class: 'bx-full-width',
|
||||
@@ -80,9 +88,7 @@ export class ControllerExtraSettings extends HTMLElement {
|
||||
}),
|
||||
}),
|
||||
),
|
||||
{
|
||||
multiLines: true,
|
||||
},
|
||||
{ multiLines: true },
|
||||
);
|
||||
$rowCustomization.appendChild(
|
||||
$container.$summaryCustomization = CE('div'),
|
||||
@@ -162,7 +168,7 @@ export class ControllerExtraSettings extends HTMLElement {
|
||||
|
||||
// Render controller list
|
||||
for (const name of this.controllerIds) {
|
||||
const $option = CE('option', { value: name }, name);
|
||||
const $option = CE('option', { value: name }, simplifyGamepadName(name));
|
||||
$fragment.appendChild($option);
|
||||
}
|
||||
|
||||
@@ -191,14 +197,8 @@ export class ControllerExtraSettings extends HTMLElement {
|
||||
return;
|
||||
}
|
||||
|
||||
const controllerSettings = await ControllerSettingsTable.getInstance().getControllerData(this.currentControllerId);
|
||||
|
||||
// Update UI
|
||||
this.$selectShortcuts.value = controllerSettings.shortcutPresetId.toString();
|
||||
this.$selectCustomization.value = controllerSettings.customizationPresetId.toString();
|
||||
|
||||
// Update summary
|
||||
ControllerExtraSettings.updateCustomizationSummary.call(this);
|
||||
const controllerSetting = STORAGE.Stream.getControllerSetting(this.currentControllerId);
|
||||
ControllerExtraSettings.updateElements.call(this, controllerSetting);
|
||||
}
|
||||
|
||||
private static getCurrentControllerId(this: ControllerExtraSettings) {
|
||||
@@ -228,16 +228,30 @@ export class ControllerExtraSettings extends HTMLElement {
|
||||
return;
|
||||
}
|
||||
|
||||
const data: ControllerSettingsRecord = {
|
||||
id: this.currentControllerId,
|
||||
data: {
|
||||
shortcutPresetId: parseInt(this.$selectShortcuts.value),
|
||||
customizationPresetId: parseInt(this.$selectCustomization.value),
|
||||
},
|
||||
const controllerSettings = getStreamPref(StreamPref.CONTROLLER_SETTINGS);
|
||||
controllerSettings[this.currentControllerId] = {
|
||||
shortcutPresetId: parseInt(this.$selectShortcuts.value),
|
||||
customizationPresetId: parseInt(this.$selectCustomization.value),
|
||||
};
|
||||
|
||||
await ControllerSettingsTable.getInstance().put(data);
|
||||
|
||||
setStreamPref(StreamPref.CONTROLLER_SETTINGS, controllerSettings, 'ui');
|
||||
StreamSettings.refreshControllerSettings();
|
||||
}
|
||||
|
||||
private static setValue(this: ControllerExtraSettings, value: ControllerSettings) {
|
||||
ControllerExtraSettings.updateElements.call(this, value[this.currentControllerId]);
|
||||
}
|
||||
|
||||
private static updateElements(this: ControllerExtraSettings, controllerSetting: ControllerSetting) {
|
||||
if (!controllerSetting) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update UI
|
||||
this.$selectShortcuts.value = controllerSetting.shortcutPresetId.toString();
|
||||
this.$selectCustomization.value = controllerSetting.customizationPresetId.toString();
|
||||
|
||||
// Update summary
|
||||
ControllerExtraSettings.updateCustomizationSummary.call(this);
|
||||
}
|
||||
}
|
||||
|
@@ -3,15 +3,11 @@ import type { SettingsDialog } from "../settings-dialog";
|
||||
import { MkbMappingPresetsTable } from "@/utils/local-db/mkb-mapping-presets-table";
|
||||
import { BxSelectElement } from "@/web-components/bx-select";
|
||||
import { t } from "@/utils/translation";
|
||||
import { getPref, setPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { StreamSettings } from "@/utils/stream-settings";
|
||||
import { getGlobalPref, getStreamPref, setStreamPref } from "@/utils/pref-utils";
|
||||
import { GlobalPref, StreamPref } from "@/enums/pref-keys";
|
||||
import { MkbMappingManagerDialog } from "../profile-manger/mkb-mapping-manager-dialog";
|
||||
import { KeyboardShortcutsManagerDialog } from "../profile-manger/keyboard-shortcuts-manager-dialog";
|
||||
import { KeyboardShortcutsTable } from "@/utils/local-db/keyboard-shortcuts-table";
|
||||
import { SettingElement } from "@/utils/setting-element";
|
||||
import { STORAGE } from "@/utils/global";
|
||||
import { EmulatedMkbHandler } from "@/modules/mkb/mkb-handler";
|
||||
import { BxIcon } from "@/utils/bx-icon";
|
||||
|
||||
export class MkbExtraSettings extends HTMLElement {
|
||||
@@ -44,7 +40,7 @@ export class MkbExtraSettings extends HTMLElement {
|
||||
}));
|
||||
|
||||
$container.append(
|
||||
...(getPref(PrefKey.MKB_ENABLED) ? [
|
||||
...(getGlobalPref(GlobalPref.MKB_ENABLED) ? [
|
||||
createSettingRow(
|
||||
t('virtual-controller'),
|
||||
CE('div', {
|
||||
@@ -63,14 +59,20 @@ export class MkbExtraSettings extends HTMLElement {
|
||||
}),
|
||||
}),
|
||||
),
|
||||
{ multiLines: true },
|
||||
{
|
||||
multiLines: true,
|
||||
onContextMenu: this.boundOnContextMenu,
|
||||
pref: StreamPref.MKB_P1_MAPPING_PRESET_ID,
|
||||
},
|
||||
),
|
||||
|
||||
createSettingRow(
|
||||
t('virtual-controller-slot'),
|
||||
SettingElement.fromPref(PrefKey.MKB_P1_SLOT, STORAGE.Global, () => {
|
||||
EmulatedMkbHandler.getInstance()?.resetXcloudGamepads();
|
||||
}),
|
||||
this.settingsManager.getElement(StreamPref.MKB_P1_SLOT),
|
||||
{
|
||||
onContextMenu: this.boundOnContextMenu,
|
||||
pref: StreamPref.MKB_P1_SLOT,
|
||||
},
|
||||
),
|
||||
] : []),
|
||||
|
||||
@@ -92,13 +94,20 @@ export class MkbExtraSettings extends HTMLElement {
|
||||
}),
|
||||
}),
|
||||
),
|
||||
{ multiLines: true },
|
||||
{
|
||||
multiLines: true,
|
||||
onContextMenu: this.boundOnContextMenu,
|
||||
pref: StreamPref.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
$container.$mappingPresets = $mappingPresets;
|
||||
$container.$shortcutsPresets = $shortcutsPresets;
|
||||
|
||||
this.settingsManager.setElement(StreamPref.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID, $shortcutsPresets);
|
||||
this.settingsManager.setElement(StreamPref.MKB_P1_MAPPING_PRESET_ID, $mappingPresets);
|
||||
|
||||
$container.updateLayout();
|
||||
// Refresh layout when parent dialog is shown
|
||||
this.onMountedCallbacks.push(() => {
|
||||
@@ -111,24 +120,20 @@ export class MkbExtraSettings extends HTMLElement {
|
||||
private static async updateLayout(this: MkbExtraSettings) {
|
||||
// Render shortcut presets
|
||||
const mappingPresets = await MkbMappingPresetsTable.getInstance().getPresets();
|
||||
renderPresetsList(this.$mappingPresets, mappingPresets, getPref(PrefKey.MKB_P1_MAPPING_PRESET_ID));
|
||||
renderPresetsList(this.$mappingPresets, mappingPresets, getStreamPref(StreamPref.MKB_P1_MAPPING_PRESET_ID));
|
||||
|
||||
// Render shortcut presets
|
||||
const shortcutsPresets = await KeyboardShortcutsTable.getInstance().getPresets();
|
||||
renderPresetsList(this.$shortcutsPresets, shortcutsPresets, getPref(PrefKey.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID), { addOffValue: true });
|
||||
renderPresetsList(this.$shortcutsPresets, shortcutsPresets, getStreamPref(StreamPref.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID), { addOffValue: true });
|
||||
}
|
||||
|
||||
private static async saveMkbSettings(this: MkbExtraSettings) {
|
||||
const presetId = parseInt(this.$mappingPresets.value);
|
||||
setPref(PrefKey.MKB_P1_MAPPING_PRESET_ID, presetId);
|
||||
|
||||
StreamSettings.refreshMkbSettings();
|
||||
setStreamPref(StreamPref.MKB_P1_MAPPING_PRESET_ID, presetId, 'ui');
|
||||
}
|
||||
|
||||
private static async saveShortcutsSettings(this: MkbExtraSettings) {
|
||||
const presetId = parseInt(this.$shortcutsPresets.value);
|
||||
setPref(PrefKey.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID, presetId);
|
||||
|
||||
StreamSettings.refreshKeyboardShortcuts();
|
||||
setStreamPref(StreamPref.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID, presetId, 'ui');
|
||||
}
|
||||
}
|
||||
|
@@ -1,16 +1,16 @@
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { GlobalPref, StreamPref, type AnyPref } from "@/enums/pref-keys";
|
||||
import { BxEvent } from "@/utils/bx-event";
|
||||
import { BX_FLAGS, NATIVE_FETCH, type BxFlags } from "@/utils/bx-flags";
|
||||
import { STORAGE } from "@/utils/global";
|
||||
import { BX_FLAGS, NATIVE_FETCH } from "@/utils/bx-flags";
|
||||
import { CE, removeChildElements, createButton, ButtonStyle, escapeCssSelector } from "@/utils/html";
|
||||
import type { BxHtmlSettingElement } from "@/utils/setting-element";
|
||||
import { getPref, setPref, getPrefDefinition } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { t } from "@/utils/translation";
|
||||
import { BxSelectElement } from "@/web-components/bx-select";
|
||||
import type { SettingsDialog } from "../settings-dialog";
|
||||
import type { RecommendedSettings, SuggestedSettingProfile } from "@/types/setting-definition";
|
||||
import { DeviceVibrationMode, TouchControllerMode } from "@/enums/pref-values";
|
||||
import { GhPagesUtils } from "@/utils/gh-pages";
|
||||
import { STORAGE, getPrefInfo, setPref } from "@/utils/pref-utils";
|
||||
import { SettingsManager } from "@/modules/settings-manager";
|
||||
|
||||
export class SuggestionsSetting {
|
||||
static async renderSuggestions(this: SettingsDialog, e: Event) {
|
||||
@@ -38,16 +38,16 @@ export class SuggestionsSetting {
|
||||
}
|
||||
|
||||
for (const setting of settingTabContent.items) {
|
||||
let prefKey: PrefKey | undefined;
|
||||
let prefKey: AnyPref | undefined;
|
||||
|
||||
if (typeof setting === 'string') {
|
||||
prefKey = setting;
|
||||
} else if (typeof setting === 'object') {
|
||||
prefKey = setting.pref as PrefKey;
|
||||
prefKey = setting.pref as GlobalPref;
|
||||
}
|
||||
|
||||
if (prefKey) {
|
||||
this.suggestedSettingLabels[prefKey] = settingTabContent.label;
|
||||
this.settingLabels[prefKey] = settingTabContent.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,15 +76,15 @@ export class SuggestionsSetting {
|
||||
const deviceType = BX_FLAGS.DeviceInfo.deviceType;
|
||||
if (deviceType === 'android-handheld') {
|
||||
// Disable touch
|
||||
SuggestionsSetting.addDefaultSuggestedSetting.call(this, PrefKey.TOUCH_CONTROLLER_MODE, TouchControllerMode.OFF);
|
||||
SuggestionsSetting.addDefaultSuggestedSetting.call(this, GlobalPref.TOUCH_CONTROLLER_MODE, TouchControllerMode.OFF);
|
||||
// Enable device vibration
|
||||
SuggestionsSetting.addDefaultSuggestedSetting.call(this, PrefKey.DEVICE_VIBRATION_MODE, DeviceVibrationMode.ON);
|
||||
SuggestionsSetting.addDefaultSuggestedSetting.call(this, StreamPref.DEVICE_VIBRATION_MODE, DeviceVibrationMode.ON);
|
||||
} else if (deviceType === 'android') {
|
||||
// Enable device vibration
|
||||
SuggestionsSetting.addDefaultSuggestedSetting.call(this, PrefKey.DEVICE_VIBRATION_MODE, DeviceVibrationMode.AUTO);
|
||||
SuggestionsSetting.addDefaultSuggestedSetting.call(this, StreamPref.DEVICE_VIBRATION_MODE, DeviceVibrationMode.AUTO);
|
||||
} else if (deviceType === 'android-tv') {
|
||||
// Disable touch
|
||||
SuggestionsSetting.addDefaultSuggestedSetting.call(this, PrefKey.TOUCH_CONTROLLER_MODE, TouchControllerMode.OFF);
|
||||
SuggestionsSetting.addDefaultSuggestedSetting.call(this, GlobalPref.TOUCH_CONTROLLER_MODE, TouchControllerMode.OFF);
|
||||
}
|
||||
|
||||
// Set value for Default profile
|
||||
@@ -116,10 +116,17 @@ export class SuggestionsSetting {
|
||||
note && fragment.appendChild(CE('div', { class: 'bx-suggest-note' }, note));
|
||||
|
||||
const settings = this.suggestedSettings[profile];
|
||||
let prefKey: PrefKey;
|
||||
for (prefKey in settings) {
|
||||
for (const key in settings) {
|
||||
const { storage, definition } = getPrefInfo(key as AnyPref);
|
||||
|
||||
let prefKey;
|
||||
if (storage === STORAGE.Stream) {
|
||||
prefKey = key as StreamPref;
|
||||
} else {
|
||||
prefKey = key as GlobalPref;
|
||||
}
|
||||
|
||||
let suggestedValue;
|
||||
const definition = getPrefDefinition(prefKey);
|
||||
if (definition && definition.transformValue) {
|
||||
suggestedValue = definition.transformValue.get.call(definition, settings[prefKey]);
|
||||
} else {
|
||||
@@ -127,8 +134,9 @@ export class SuggestionsSetting {
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const currentValue = getPref(prefKey, false);
|
||||
const currentValueText = STORAGE.Global.getValueText(prefKey, currentValue);
|
||||
const currentValue = storage.getSetting(prefKey, false);
|
||||
// @ts-ignore
|
||||
const currentValueText = storage.getValueText(prefKey, currentValue);
|
||||
const isSameValue = currentValue === suggestedValue;
|
||||
|
||||
let $child: HTMLElement;
|
||||
@@ -137,12 +145,14 @@ export class SuggestionsSetting {
|
||||
// No changes
|
||||
$value = currentValueText;
|
||||
} else {
|
||||
const suggestedValueText = STORAGE.Global.getValueText(prefKey, suggestedValue);
|
||||
// @ts-ignore
|
||||
const suggestedValueText = storage.getValueText(prefKey, suggestedValue);
|
||||
$value = currentValueText + ' ➔ ' + suggestedValueText;
|
||||
}
|
||||
|
||||
let $checkbox: HTMLInputElement;
|
||||
const breadcrumb = this.suggestedSettingLabels[prefKey] + ' ❯ ' + STORAGE.Global.getLabel(prefKey);
|
||||
// @ts-ignore
|
||||
const breadcrumb = this.settingLabels[prefKey] + ' ❯ ' + storage.getLabel(prefKey);
|
||||
const id = escapeCssSelector(`bx_suggest_${prefKey}`);
|
||||
|
||||
$child = CE('div', {
|
||||
@@ -183,7 +193,8 @@ export class SuggestionsSetting {
|
||||
const profile = $select.value as SuggestedSettingProfile;
|
||||
const settings = this.suggestedSettings[profile];
|
||||
|
||||
let prefKey: PrefKey;
|
||||
let prefKey: AnyPref;
|
||||
const settingsManager = SettingsManager.getInstance();
|
||||
for (prefKey in settings) {
|
||||
let suggestedValue = settings[prefKey];
|
||||
|
||||
@@ -192,17 +203,17 @@ export class SuggestionsSetting {
|
||||
continue;
|
||||
}
|
||||
|
||||
const $control = this.settingElements[prefKey] as HTMLElement;
|
||||
const $control = settingsManager.getElement(prefKey);
|
||||
|
||||
// Set value directly if the control element is not available
|
||||
if (!$control) {
|
||||
setPref(prefKey, suggestedValue);
|
||||
setPref(prefKey, suggestedValue, 'direct');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Transform value
|
||||
const settingDefinition = getPrefDefinition(prefKey);
|
||||
if (settingDefinition.transformValue) {
|
||||
const { definition: settingDefinition } = getPrefInfo(prefKey);
|
||||
if (settingDefinition?.transformValue) {
|
||||
suggestedValue = settingDefinition.transformValue.get.call(settingDefinition, suggestedValue);
|
||||
}
|
||||
|
||||
@@ -274,7 +285,7 @@ export class SuggestionsSetting {
|
||||
const url = GhPagesUtils.getUrl(`devices/${brand}/${board}-${model}.json`);
|
||||
const response = await NATIVE_FETCH(url);
|
||||
const json = (await response.json()) as RecommendedSettings;
|
||||
const recommended: PartialRecord<PrefKey, any> = {};
|
||||
const recommended: PartialRecord<GlobalPref, any> = {};
|
||||
|
||||
// Only supports schema version 2
|
||||
if (json.schema_version !== 2) {
|
||||
@@ -311,7 +322,7 @@ export class SuggestionsSetting {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static addDefaultSuggestedSetting(this: SettingsDialog, prefKey: PrefKey, value: any) {
|
||||
private static addDefaultSuggestedSetting(this: SettingsDialog, prefKey: AnyPref, value: any) {
|
||||
let key: keyof typeof this.suggestedSettings;
|
||||
for (key in this.suggestedSettings) {
|
||||
if (key !== 'default' && !(prefKey in this.suggestedSettings)) {
|
||||
@@ -327,10 +338,10 @@ export class SuggestionsSetting {
|
||||
continue;
|
||||
}
|
||||
|
||||
let prefKey: PrefKey;
|
||||
let prefKey: AnyPref;
|
||||
for (prefKey in this.suggestedSettings[key]) {
|
||||
if (!(prefKey in this.suggestedSettings.default)) {
|
||||
this.suggestedSettings.default[prefKey] = getPrefDefinition(prefKey).default;
|
||||
this.suggestedSettings.default[prefKey] = getPrefInfo(prefKey).definition.default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,9 +8,9 @@ import { SettingsDialog } from "./dialog/settings-dialog";
|
||||
import { TrueAchievements } from "@/utils/true-achievements";
|
||||
import { BxIcon } from "@/utils/bx-icon";
|
||||
import { BxEventBus } from "@/utils/bx-event-bus";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
import { UiLayout } from "@/enums/pref-values";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
|
||||
export enum GuideMenuTab {
|
||||
HOME = 'home',
|
||||
@@ -116,7 +116,7 @@ export class GuideMenu {
|
||||
});
|
||||
|
||||
// Set TV tag
|
||||
if (STATES.userAgent.isTv || getPref(PrefKey.UI_LAYOUT) === UiLayout.TV) {
|
||||
if (STATES.userAgent.isTv || getGlobalPref(GlobalPref.UI_LAYOUT) === UiLayout.TV) {
|
||||
document.body.dataset.bxMediaType = 'tv';
|
||||
}
|
||||
|
||||
|
@@ -7,8 +7,8 @@ import { getPreferredServerRegion } from "@utils/region";
|
||||
import { RemotePlayManager } from "@/modules/remote-play-manager";
|
||||
import { t } from "@utils/translation";
|
||||
import { SettingsDialog } from "./dialog/settings-dialog";
|
||||
import { PrefKey } from "@/enums/pref-keys";
|
||||
import { getPref } from "@/utils/settings-storages/global-settings-storage";
|
||||
import { GlobalPref } from "@/enums/pref-keys";
|
||||
import { getGlobalPref } from "@/utils/pref-utils";
|
||||
import { BxLogger } from "@/utils/bx-logger";
|
||||
|
||||
export class HeaderSection {
|
||||
@@ -46,7 +46,7 @@ export class HeaderSection {
|
||||
});
|
||||
|
||||
this.$buttonsWrapper = CE('div', false,
|
||||
getPref(PrefKey.REMOTE_PLAY_ENABLED) ? this.$btnRemotePlay : null,
|
||||
getGlobalPref(GlobalPref.REMOTE_PLAY_ENABLED) ? this.$btnRemotePlay : null,
|
||||
this.$btnSettings,
|
||||
);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ export class HeaderSection {
|
||||
return;
|
||||
}
|
||||
|
||||
const PREF_LATEST_VERSION = getPref(PrefKey.VERSION_LATEST);
|
||||
const PREF_LATEST_VERSION = getGlobalPref(GlobalPref.VERSION_LATEST);
|
||||
|
||||
// Setup Settings button
|
||||
const $btnSettings = this.$btnSettings;
|
||||
|
Reference in New Issue
Block a user