diff --git a/build.ts b/build.ts
index 798ba51..c3e5070 100755
--- a/build.ts
+++ b/build.ts
@@ -21,6 +21,7 @@ enum BuildTarget {
type BuildVariant = 'full' | 'lite';
const MINIFY_SYNTAX = true;
+const INDENT_SPACES = false;
function minifySvgImports(str: string): string {
// Minify SVG imports
@@ -128,8 +129,12 @@ function postProcess(str: string): string {
str = minifyIfElse(str);
str = str.replaceAll(/\n(\s+)/g, (match, p1) => {
- const len = p1.length / 2;
- return '\n' + ' '.repeat(len);
+ if (INDENT_SPACES) {
+ const len = p1.length / 2;
+ return '\n' + ' '.repeat(len);
+ } else {
+ return '\n';
+ }
});
}
diff --git a/bun.lock b/bun.lock
old mode 100755
new mode 100644
index 40bef75..4bbb893
--- a/bun.lock
+++ b/bun.lock
@@ -1,5 +1,5 @@
{
- "lockfileVersion": 0,
+ "lockfileVersion": 1,
"workspaces": {
"": {
"devDependencies": {
@@ -24,15 +24,15 @@
"@eslint/config-array": ["@eslint/config-array@0.19.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ=="],
- "@eslint/core": ["@eslint/core@0.9.0", "", {}, "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg=="],
+ "@eslint/core": ["@eslint/core@0.10.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.2.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w=="],
- "@eslint/js": ["@eslint/js@9.17.0", "", {}, "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w=="],
+ "@eslint/js": ["@eslint/js@9.19.0", "", {}, "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.4", "", {}, "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ=="],
- "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.3", "", { "dependencies": { "levn": "^0.4.1" } }, "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA=="],
+ "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.5", "", { "dependencies": { "@eslint/core": "^0.10.0", "levn": "^0.4.1" } }, "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
@@ -48,13 +48,13 @@
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
- "@types/bun": ["@types/bun@1.1.14", "", { "dependencies": { "bun-types": "1.1.37" } }, "sha512-opVYiFGtO2af0dnWBdZWlioLBoxSdDO5qokaazLhq8XQtGZbY4pY3/JxY8Zdf/hEwGubbp7ErZXoN1+h2yesxA=="],
+ "@types/bun": ["@types/bun@1.2.0", "", { "dependencies": { "bun-types": "1.2.0" } }, "sha512-5N1JqdahfpBlAv4wy6svEYcd/YfO2GNrbL95JOmFx8nkE6dbK4R0oSE5SpBA4vBRqgrOUAXF8Dpiz+gi7r80SA=="],
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
- "@types/node": ["@types/node@22.10.2", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ=="],
+ "@types/node": ["@types/node@22.10.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww=="],
"@types/stylus": ["@types/stylus@0.48.43", "", { "dependencies": { "@types/node": "*" } }, "sha512-72dv/zdhuyXWVHUXG2VTPEQdOG+oen95/DNFx2aMFFaY6LoITI6PwEqf5x31JF49kp2w9hvUzkNfTGBIeg61LQ=="],
@@ -80,7 +80,7 @@
"browserslist": ["browserslist@4.24.3", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA=="],
- "bun-types": ["bun-types@1.1.37", "", { "dependencies": { "@types/node": "~20.12.8", "@types/ws": "~8.5.10" } }, "sha512-C65lv6eBr3LPJWFZ2gswyrGZ82ljnH8flVE03xeXxKhi2ZGtFiO4isRKTKnitbSqtRAcaqYSR6djt1whI66AbA=="],
+ "bun-types": ["bun-types@1.2.0", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-KEaJxyZfbV/c4eyG0vyehDpYmBGreNiQbZIqvVHJwZ4BmeuWlNZ7EAzMN2Zcd7ailmS/tGVW0BgYbGf+lGEpWw=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
@@ -110,7 +110,7 @@
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
- "eslint": ["eslint@9.17.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.9.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.17.0", "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA=="],
+ "eslint": ["eslint@9.19.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.10.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.19.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA=="],
"eslint-plugin-compat": ["eslint-plugin-compat@6.0.2", "", { "dependencies": { "@mdn/browser-compat-data": "^5.5.35", "ast-metadata-inferer": "^0.8.1", "browserslist": "^4.24.2", "caniuse-lite": "^1.0.30001687", "find-up": "^5.0.0", "globals": "^15.7.0", "lodash.memoize": "^4.1.2", "semver": "^7.6.2" }, "peerDependencies": { "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" } }, "sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA=="],
@@ -280,8 +280,6 @@
"ast-metadata-inferer/@mdn/browser-compat-data": ["@mdn/browser-compat-data@5.6.26", "", {}, "sha512-7NdgdOR7lkzrN70zGSULmrcvKyi/aJjpTJRCbuy8IZuHiLkPTvsr10jW0MJgWzK2l2wTmhdQvegTw6yNU5AVNQ=="],
- "bun-types/@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="],
-
"foreground-child/cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
"glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
@@ -302,8 +300,6 @@
"@types/ws/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
- "bun-types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
-
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
diff --git a/package.json b/package.json
index 14c4fcc..dd0800f 100755
--- a/package.json
+++ b/package.json
@@ -10,10 +10,10 @@
"build": "build.ts"
},
"devDependencies": {
- "@types/bun": "^1.1.14",
- "@types/node": "^22.10.2",
+ "@types/bun": "^1.2.0",
+ "@types/node": "^22.10.10",
"@types/stylus": "^0.48.43",
- "eslint": "^9.17.0",
+ "eslint": "^9.19.0",
"eslint-plugin-compat": "^6.0.2",
"stylus": "^0.64.0"
},
diff --git a/src/assets/css/button.styl b/src/assets/css/button.styl
index 0ea50a7..05b9d29 100755
--- a/src/assets/css/button.styl
+++ b/src/assets/css/button.styl
@@ -37,6 +37,7 @@
&:disabled {
cursor: default;
background-color: unquote('rgb(var(--button-disabled-rgb))');
+ opacity: 0.5;
}
&.bx-ghost {
diff --git a/src/assets/css/root.styl b/src/assets/css/root.styl
index 87d29b2..fe741e7 100755
--- a/src/assets/css/root.styl
+++ b/src/assets/css/root.styl
@@ -25,7 +25,7 @@ button_color(name, normal, hover, active, disabled)
button_color('default', #2d3036, #515863, #222428, #8e8e8e);
button_color('primary', #008746, #04b358, #044e2a, #448262);
button_color('warning', #c16e04, #fa9005, #965603, #a2816c);
- button_color('danger', #c10404, #e61d1d, #a26c6c, #df5656);
+ button_color('danger', #c10404, #e61d1d, #a26c6c, #bd8282);
--bx-fullscreen-text-z-index: 9999;
--bx-toast-z-index: 6000;
@@ -47,7 +47,7 @@ button_color(name, normal, hover, active, disabled)
@font-face {
font-family: 'promptfont';
src: url('https://redphx.github.io/better-xcloud/fonts/promptfont.otf');
- unicode-range: U+2196-E011;
+ unicode-range: U+2196-E011, U+27F6, U+FF31;
}
/* Fix Stream menu buttons not hiding */
diff --git a/src/assets/css/settings-dialog.styl b/src/assets/css/settings-dialog.styl
index ff59e1d..91a3cb2 100755
--- a/src/assets/css/settings-dialog.styl
+++ b/src/assets/css/settings-dialog.styl
@@ -98,10 +98,8 @@
tabsWidth = 48px;
flex-direction: column;
- padding: 10px;
margin-left: tabsWidth;
width: 450px;
- max-width: calc(100vw - tabsWidth);
background: #1a1b1e;
color: #fff;
font-weight: 400;
@@ -112,13 +110,6 @@
overflow: overlay;
z-index: 1;
- > div[data-tab-group=mkb] {
- display: flex;
- flex-direction: column;
- height: 100%;
- overflow: hidden;
- }
-
.bx-top-buttons {
display: flex;
flex-direction: column;
@@ -284,7 +275,8 @@
color: #828282;
}
-.bx-settings-tab-contents {
+.bx-settings-tab-content {
+ padding: 10px;
border-radius-size = 6px;
> div {
@@ -307,6 +299,14 @@
border-radius: border-radius-size;
}
}
+
+ &:not([data-game-id="-1"]) {
+ .bx-settings-row[data-override=true], .bx-settings-row:has(*[data-override=true]) {
+ border-left: 4px solid orange !important;
+ border-top-left-radius: 0 !important;
+ border-bottom-left-radius: 0 !important;
+ }
+ }
}
.bx-suggest-toggler {
@@ -533,3 +533,53 @@
flex: 1;
}
}
+
+.bx-stream-settings-selection {
+ margin-bottom: 8px;
+ position: sticky;
+ z-index: 1000;
+ top: 0;
+
+ > div {
+ display: flex;
+ gap: 8px;
+ background: #222222;
+ padding: 10px;
+ border-bottom: 4px solid #353638;
+ box-shadow: 0 0 6px #000;
+ position: relative;
+ z-index: 1;
+
+ .bx-select {
+ flex: 1;
+
+ label {
+ font-weight: bold;
+ font-size: 1.1rem;
+ line-height: initial;
+
+ span {
+ line-height: initial;
+ }
+ }
+
+ .bx-select-indicators {
+ display: none;
+ }
+ }
+ }
+
+ p {
+ font-family: var(--bx-promptfont-font), var(--bx-normal-font);
+ margin: 0;
+ font-size: 13px;
+ background: #505050f2;
+ height: 25px;
+ line-height: 23px;
+ position: absolute;
+ bottom: -25px;
+ left: 0;
+ right: 0;
+ text-shadow: 0 1px #000;
+ }
+}
diff --git a/src/assets/svg/global-restore.svg b/src/assets/svg/global-restore.svg
new file mode 100644
index 0000000..a12f7ba
--- /dev/null
+++ b/src/assets/svg/global-restore.svg
@@ -0,0 +1,6 @@
+
diff --git a/src/enums/mkb.ts b/src/enums/mkb.ts
index e48ec4f..dda3999 100755
--- a/src/enums/mkb.ts
+++ b/src/enums/mkb.ts
@@ -37,131 +37,6 @@ export const enum MkbPresetKey {
}
-export type KeyCode =
- | 'Backspace'
- | 'Tab'
- | 'Enter'
- | 'ShiftLeft'
- | 'ShiftRight'
- | 'ControlLeft'
- | 'ControlRight'
- | 'AltLeft'
- | 'AltRight'
- | 'Pause'
- | 'CapsLock'
- | 'Escape'
- | 'Space'
- | 'PageUp'
- | 'PageDown'
- | 'End'
- | 'Home'
- | 'ArrowLeft'
- | 'ArrowUp'
- | 'ArrowRight'
- | 'ArrowDown'
- | 'PrintScreen'
- | 'Insert'
- | 'Delete'
- | 'Digit0'
- | 'Digit1'
- | 'Digit2'
- | 'Digit3'
- | 'Digit4'
- | 'Digit5'
- | 'Digit6'
- | 'Digit7'
- | 'Digit8'
- | 'Digit9'
- | 'KeyA'
- | 'KeyB'
- | 'KeyC'
- | 'KeyD'
- | 'KeyE'
- | 'KeyF'
- | 'KeyG'
- | 'KeyH'
- | 'KeyI'
- | 'KeyJ'
- | 'KeyK'
- | 'KeyL'
- | 'KeyM'
- | 'KeyN'
- | 'KeyO'
- | 'KeyP'
- | 'KeyQ'
- | 'KeyR'
- | 'KeyS'
- | 'KeyT'
- | 'KeyU'
- | 'KeyV'
- | 'KeyW'
- | 'KeyX'
- | 'KeyY'
- | 'KeyZ'
- | 'MetaLeft'
- | 'MetaRight'
- | 'ContextMenu'
- | 'F1'
- | 'F2'
- | 'F3'
- | 'F4'
- | 'F5'
- | 'F6'
- | 'F7'
- | 'F8'
- | 'F9'
- | 'F10'
- | 'F11'
- | 'F12'
- | 'NumLock'
- | 'ScrollLock'
- | 'AudioVolumeMute'
- | 'AudioVolumeDown'
- | 'AudioVolumeUp'
- | 'MediaTrackNext'
- | 'MediaTrackPrevious'
- | 'MediaStop'
- | 'MediaPlayPause'
- | 'LaunchMail'
- | 'LaunchMediaPlayer'
- | 'LaunchApplication1'
- | 'LaunchApplication2'
- | 'Semicolon'
- | 'Equal'
- | 'Comma'
- | 'Minus'
- | 'Period'
- | 'Slash'
- | 'Backquote'
- | 'BracketLeft'
- | 'Backslash'
- | 'BracketRight'
- | 'Quote'
- | 'Numpad0'
- | 'Numpad1'
- | 'Numpad2'
- | 'Numpad3'
- | 'Numpad4'
- | 'Numpad5'
- | 'Numpad6'
- | 'Numpad7'
- | 'Numpad8'
- | 'Numpad9'
- | 'NumpadMultiply'
- | 'NumpadAdd'
- | 'NumpadSubtract'
- | 'NumpadDecimal'
- | 'NumpadDivide';
-
-export type KeyCodeExcludeModifiers = Exclude
-
export const enum KeyModifier {
CTRL = 1,
ALT = 2,
diff --git a/src/enums/pref-keys.ts b/src/enums/pref-keys.ts
index dc93a99..9f5018b 100755
--- a/src/enums/pref-keys.ts
+++ b/src/enums/pref-keys.ts
@@ -1,7 +1,9 @@
+import type { BaseSettingsStorage } from "@/utils/settings-storages/base-settings-storage";
import type { BlockFeature, CodecProfile, DeviceVibrationMode, GameBarPosition, LoadingScreenRocket, NativeMkbMode, StreamPlayerType, StreamResolution, StreamStat, StreamStatPosition, StreamVideoProcessing, TouchControllerMode, TouchControllerStyleCustom, TouchControllerStyleStandard, UiLayout, UiSection, VideoPosition, VideoPowerPreference, VideoRatio } from "./pref-values"
export const enum StorageKey {
GLOBAL = 'BetterXcloud',
+ STREAM = 'BetterXcloud.Stream',
LOCALE = 'BetterXcloud.Locale',
LOCALE_TRANSLATIONS = 'BetterXcloud.Locale.Translations',
@@ -16,7 +18,7 @@ export const enum StorageKey {
}
-export const enum PrefKey {
+export const enum GlobalPref {
VERSION_LAST_CHECK = 'version.lastCheck',
VERSION_LATEST = 'version.latest',
VERSION_CURRENT = 'version.current',
@@ -43,26 +45,11 @@ export const enum PrefKey {
GAME_BAR_POSITION = 'gameBar.position',
- LOCAL_CO_OP_ENABLED = 'localCoOp.enabled',
-
- DEVICE_VIBRATION_MODE = 'deviceVibration.mode',
- DEVICE_VIBRATION_INTENSITY = 'deviceVibration.intensity',
-
- CONTROLLER_POLLING_RATE = 'controller.pollingRate',
-
NATIVE_MKB_MODE = 'nativeMkb.mode',
NATIVE_MKB_FORCED_GAMES = 'nativeMkb.forcedGames',
- NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY = 'nativeMkb.scroll.sensitivityX',
- NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY = 'nativeMkb.scroll.sensitivityY',
MKB_ENABLED = 'mkb.enabled',
MKB_HIDE_IDLE_CURSOR = 'mkb.cursor.hideIdle',
- MKB_P1_MAPPING_PRESET_ID = 'mkb.p1.preset.mappingId',
- MKB_P1_SLOT = 'mkb.p1.slot',
- MKB_P2_MAPPING_PRESET_ID = 'mkb.p2.preset.mappingId',
- MKB_P2_SLOT = 'mkb.p2.slot',
-
- KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID = 'keyboardShortcuts.preset.inGameId',
SCREENSHOT_APPLY_FILTERS = 'screenshot.applyFilters',
@@ -88,6 +75,84 @@ export const enum PrefKey {
UI_REDUCE_ANIMATIONS = 'ui.reduceAnimations',
UI_IMAGE_QUALITY = 'ui.imageQuality',
+ AUDIO_MIC_ON_PLAYING = 'audio.mic.onPlaying',
+ AUDIO_VOLUME_CONTROL_ENABLED = 'audio.volume.booster.enabled',
+
+ REMOTE_PLAY_ENABLED = 'xhome.enabled',
+ REMOTE_PLAY_STREAM_RESOLUTION = 'xhome.video.resolution',
+
+ GAME_FORTNITE_FORCE_CONSOLE = 'game.fortnite.forceConsole',
+}
+
+export type GlobalPrefTypeMap = {
+ [GlobalPref.AUDIO_MIC_ON_PLAYING]: boolean;
+ [GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED]: boolean;
+ [GlobalPref.BLOCK_FEATURES]: BlockFeature[];
+ [GlobalPref.BLOCK_TRACKING]: boolean;
+ [GlobalPref.GAME_BAR_POSITION]: GameBarPosition;
+ [GlobalPref.GAME_FORTNITE_FORCE_CONSOLE]: boolean;
+ [GlobalPref.LOADING_SCREEN_GAME_ART]: boolean;
+ [GlobalPref.LOADING_SCREEN_ROCKET]: LoadingScreenRocket;
+ [GlobalPref.LOADING_SCREEN_SHOW_WAIT_TIME]: boolean;
+ [GlobalPref.MKB_ENABLED]: boolean;
+ [GlobalPref.MKB_HIDE_IDLE_CURSOR]: boolean;
+ [GlobalPref.NATIVE_MKB_FORCED_GAMES]: string[];
+ [GlobalPref.NATIVE_MKB_MODE]: NativeMkbMode;
+ [GlobalPref.REMOTE_PLAY_ENABLED]: boolean;
+ [GlobalPref.REMOTE_PLAY_STREAM_RESOLUTION]: StreamResolution;
+ [GlobalPref.SCREENSHOT_APPLY_FILTERS]: boolean;
+ [GlobalPref.SERVER_BYPASS_RESTRICTION]: string;
+ [GlobalPref.SERVER_PREFER_IPV6]: boolean;
+ [GlobalPref.SERVER_REGION]: string;
+ [GlobalPref.STREAM_CODEC_PROFILE]: CodecProfile;
+ [GlobalPref.STREAM_COMBINE_SOURCES]: boolean;
+ [GlobalPref.STREAM_MAX_VIDEO_BITRATE]: number;
+ [GlobalPref.STREAM_PREFERRED_LOCALE]: StreamPreferredLocale;
+ [GlobalPref.STREAM_RESOLUTION]: StreamResolution;
+ [GlobalPref.TOUCH_CONTROLLER_AUTO_OFF]: boolean;
+ [GlobalPref.TOUCH_CONTROLLER_DEFAULT_OPACITY]: number;
+ [GlobalPref.TOUCH_CONTROLLER_MODE]: TouchControllerMode;
+ [GlobalPref.TOUCH_CONTROLLER_STYLE_CUSTOM]: TouchControllerStyleCustom;
+ [GlobalPref.TOUCH_CONTROLLER_STYLE_STANDARD]: TouchControllerStyleStandard;
+ [GlobalPref.UI_CONTROLLER_FRIENDLY]: boolean;
+ [GlobalPref.UI_CONTROLLER_SHOW_STATUS]: boolean;
+ [GlobalPref.UI_DISABLE_FEEDBACK_DIALOG]: boolean;
+ [GlobalPref.UI_GAME_CARD_SHOW_WAIT_TIME]: boolean;
+ [GlobalPref.UI_HIDE_SECTIONS]: UiSection[];
+ [GlobalPref.UI_HIDE_SYSTEM_MENU_ICON]: boolean;
+ [GlobalPref.UI_IMAGE_QUALITY]: number;
+ [GlobalPref.UI_LAYOUT]: UiLayout;
+ [GlobalPref.UI_REDUCE_ANIMATIONS]: boolean;
+ [GlobalPref.UI_SCROLLBAR_HIDE]: boolean;
+ [GlobalPref.UI_SIMPLIFY_STREAM_MENU]: boolean;
+ [GlobalPref.UI_SKIP_SPLASH_VIDEO]: boolean;
+ [GlobalPref.VERSION_CURRENT]: string;
+ [GlobalPref.VERSION_LAST_CHECK]: number;
+ [GlobalPref.VERSION_LATEST]: string;
+
+ [GlobalPref.SCRIPT_LOCALE]: string;
+ [GlobalPref.USER_AGENT_PROFILE]: string;
+}
+
+export const enum StreamPref {
+ LOCAL_CO_OP_ENABLED = 'localCoOp.enabled',
+
+ DEVICE_VIBRATION_MODE = 'deviceVibration.mode',
+ DEVICE_VIBRATION_INTENSITY = 'deviceVibration.intensity',
+
+ CONTROLLER_POLLING_RATE = 'controller.pollingRate',
+ CONTROLLER_SETTINGS = 'controller.settings',
+
+ NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY = 'nativeMkb.scroll.sensitivityX',
+ NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY = 'nativeMkb.scroll.sensitivityY',
+
+ MKB_P1_MAPPING_PRESET_ID = 'mkb.p1.preset.mappingId',
+ MKB_P1_SLOT = 'mkb.p1.slot',
+ MKB_P2_MAPPING_PRESET_ID = 'mkb.p2.preset.mappingId',
+ MKB_P2_SLOT = 'mkb.p2.slot',
+
+ KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID = 'keyboardShortcuts.preset.inGameId',
+
VIDEO_PLAYER_TYPE = 'video.player.type',
VIDEO_POWER_PREFERENCE = 'video.player.powerPreference',
VIDEO_PROCESSING = 'video.processing',
@@ -99,8 +164,6 @@ export const enum PrefKey {
VIDEO_SATURATION = 'video.saturation',
VIDEO_POSITION = 'video.position',
- AUDIO_MIC_ON_PLAYING = 'audio.mic.onPlaying',
- AUDIO_VOLUME_CONTROL_ENABLED = 'audio.volume.booster.enabled',
AUDIO_VOLUME = 'audio.volume',
STATS_ITEMS = 'stats.items',
@@ -111,85 +174,137 @@ export const enum PrefKey {
STATS_OPACITY_ALL = 'stats.opacity.all',
STATS_OPACITY_BACKGROUND = 'stats.opacity.background',
STATS_CONDITIONAL_FORMATTING = 'stats.colors',
-
- REMOTE_PLAY_ENABLED = 'xhome.enabled',
- REMOTE_PLAY_STREAM_RESOLUTION = 'xhome.video.resolution',
-
- GAME_FORTNITE_FORCE_CONSOLE = 'game.fortnite.forceConsole',
}
-
-export type PrefTypeMap = {
- [PrefKey.AUDIO_MIC_ON_PLAYING]: boolean,
- [PrefKey.AUDIO_VOLUME_CONTROL_ENABLED]: boolean,
- [PrefKey.AUDIO_VOLUME]: number,
- [PrefKey.BLOCK_FEATURES]: BlockFeature[],
- [PrefKey.BLOCK_TRACKING]: boolean,
- [PrefKey.CONTROLLER_POLLING_RATE]: number,
- [PrefKey.DEVICE_VIBRATION_INTENSITY]: number,
- [PrefKey.DEVICE_VIBRATION_MODE]: DeviceVibrationMode,
- [PrefKey.GAME_BAR_POSITION]: GameBarPosition,
- [PrefKey.GAME_FORTNITE_FORCE_CONSOLE]: boolean,
- [PrefKey.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID]: number,
- [PrefKey.LOADING_SCREEN_GAME_ART]: boolean,
- [PrefKey.LOADING_SCREEN_ROCKET]: LoadingScreenRocket,
- [PrefKey.LOADING_SCREEN_SHOW_WAIT_TIME]: boolean,
- [PrefKey.LOCAL_CO_OP_ENABLED]: boolean,
- [PrefKey.MKB_ENABLED]: boolean,
- [PrefKey.MKB_HIDE_IDLE_CURSOR]: boolean,
- [PrefKey.MKB_P1_MAPPING_PRESET_ID]: number,
- [PrefKey.MKB_P1_SLOT]: number,
- [PrefKey.NATIVE_MKB_FORCED_GAMES]: string[],
- [PrefKey.NATIVE_MKB_MODE]: NativeMkbMode,
- [PrefKey.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY]: number,
- [PrefKey.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY]: number,
- [PrefKey.REMOTE_PLAY_ENABLED]: boolean,
- [PrefKey.REMOTE_PLAY_STREAM_RESOLUTION]: StreamResolution,
- [PrefKey.SCREENSHOT_APPLY_FILTERS]: boolean,
- [PrefKey.SERVER_BYPASS_RESTRICTION]: string,
- [PrefKey.SERVER_PREFER_IPV6]: boolean,
- [PrefKey.SERVER_REGION]: string,
- [PrefKey.STATS_CONDITIONAL_FORMATTING]: boolean,
- [PrefKey.STATS_ITEMS]: StreamStat[],
- [PrefKey.STATS_OPACITY_ALL]: number,
- [PrefKey.STATS_OPACITY_BACKGROUND]: number,
- [PrefKey.STATS_POSITION]: StreamStatPosition,
- [PrefKey.STATS_QUICK_GLANCE_ENABLED]: boolean,
- [PrefKey.STATS_SHOW_WHEN_PLAYING]: boolean,
- [PrefKey.STATS_TEXT_SIZE]: string,
- [PrefKey.STREAM_CODEC_PROFILE]: CodecProfile,
- [PrefKey.STREAM_COMBINE_SOURCES]: boolean,
- [PrefKey.STREAM_MAX_VIDEO_BITRATE]: number,
- [PrefKey.STREAM_PREFERRED_LOCALE]: StreamPreferredLocale,
- [PrefKey.STREAM_RESOLUTION]: StreamResolution,
- [PrefKey.TOUCH_CONTROLLER_AUTO_OFF]: boolean,
- [PrefKey.TOUCH_CONTROLLER_DEFAULT_OPACITY]: number,
- [PrefKey.TOUCH_CONTROLLER_MODE]: TouchControllerMode,
- [PrefKey.TOUCH_CONTROLLER_STYLE_CUSTOM]: TouchControllerStyleCustom,
- [PrefKey.TOUCH_CONTROLLER_STYLE_STANDARD]: TouchControllerStyleStandard,
- [PrefKey.UI_CONTROLLER_FRIENDLY]: boolean,
- [PrefKey.UI_CONTROLLER_SHOW_STATUS]: boolean,
- [PrefKey.UI_DISABLE_FEEDBACK_DIALOG]: boolean,
- [PrefKey.UI_GAME_CARD_SHOW_WAIT_TIME]: boolean,
- [PrefKey.UI_HIDE_SECTIONS]: UiSection[],
- [PrefKey.UI_HIDE_SYSTEM_MENU_ICON]: boolean,
- [PrefKey.UI_IMAGE_QUALITY]: number,
- [PrefKey.UI_LAYOUT]: UiLayout,
- [PrefKey.UI_REDUCE_ANIMATIONS]: boolean,
- [PrefKey.UI_SCROLLBAR_HIDE]: boolean,
- [PrefKey.UI_SIMPLIFY_STREAM_MENU]: boolean,
- [PrefKey.UI_SKIP_SPLASH_VIDEO]: boolean,
- [PrefKey.VERSION_CURRENT]: string,
- [PrefKey.VERSION_LAST_CHECK]: number,
- [PrefKey.VERSION_LATEST]: string,
- [PrefKey.VIDEO_BRIGHTNESS]: number,
- [PrefKey.VIDEO_CONTRAST]: number,
- [PrefKey.VIDEO_MAX_FPS]: number,
- [PrefKey.VIDEO_PLAYER_TYPE]: StreamPlayerType,
- [PrefKey.VIDEO_POSITION]: VideoPosition,
- [PrefKey.VIDEO_POWER_PREFERENCE]: VideoPowerPreference,
- [PrefKey.VIDEO_PROCESSING]: StreamVideoProcessing,
- [PrefKey.VIDEO_RATIO]: VideoRatio,
- [PrefKey.VIDEO_SATURATION]: number,
- [PrefKey.VIDEO_SHARPNESS]: number,
+export type StreamPrefTypeMap = {
+ [StreamPref.AUDIO_VOLUME]: number;
+ [StreamPref.CONTROLLER_POLLING_RATE]: number;
+ [StreamPref.CONTROLLER_SETTINGS]: ControllerSettings;
+ [StreamPref.DEVICE_VIBRATION_INTENSITY]: number;
+ [StreamPref.DEVICE_VIBRATION_MODE]: DeviceVibrationMode;
+ [StreamPref.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID]: number;
+ [StreamPref.LOCAL_CO_OP_ENABLED]: boolean;
+ [StreamPref.MKB_P1_MAPPING_PRESET_ID]: number;
+ [StreamPref.MKB_P1_SLOT]: number;
+ [StreamPref.MKB_P2_MAPPING_PRESET_ID]: number;
+ [StreamPref.MKB_P2_SLOT]: number;
+ [StreamPref.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY]: number;
+ [StreamPref.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY]: number;
+ [StreamPref.STATS_CONDITIONAL_FORMATTING]: boolean;
+ [StreamPref.STATS_ITEMS]: StreamStat[];
+ [StreamPref.STATS_OPACITY_ALL]: number;
+ [StreamPref.STATS_OPACITY_BACKGROUND]: number;
+ [StreamPref.STATS_POSITION]: StreamStatPosition;
+ [StreamPref.STATS_QUICK_GLANCE_ENABLED]: boolean;
+ [StreamPref.STATS_SHOW_WHEN_PLAYING]: boolean;
+ [StreamPref.STATS_TEXT_SIZE]: string;
+ [StreamPref.VIDEO_BRIGHTNESS]: number;
+ [StreamPref.VIDEO_CONTRAST]: number;
+ [StreamPref.VIDEO_MAX_FPS]: number;
+ [StreamPref.VIDEO_PLAYER_TYPE]: StreamPlayerType;
+ [StreamPref.VIDEO_POSITION]: VideoPosition;
+ [StreamPref.VIDEO_POWER_PREFERENCE]: VideoPowerPreference;
+ [StreamPref.VIDEO_PROCESSING]: StreamVideoProcessing;
+ [StreamPref.VIDEO_RATIO]: VideoRatio;
+ [StreamPref.VIDEO_SATURATION]: number;
+ [StreamPref.VIDEO_SHARPNESS]: number;
}
+
+export type AllPrefs = GlobalPref | StreamPref;
+
+export const ALL_PREFS: {
+ global: GlobalPref[],
+ stream: StreamPref[],
+} = {
+ global: [
+ GlobalPref.AUDIO_MIC_ON_PLAYING,
+ GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED,
+ GlobalPref.BLOCK_FEATURES,
+ GlobalPref.BLOCK_TRACKING,
+ GlobalPref.GAME_BAR_POSITION,
+ GlobalPref.GAME_FORTNITE_FORCE_CONSOLE,
+ GlobalPref.LOADING_SCREEN_GAME_ART,
+ GlobalPref.LOADING_SCREEN_ROCKET,
+ GlobalPref.LOADING_SCREEN_SHOW_WAIT_TIME,
+ GlobalPref.MKB_ENABLED,
+ GlobalPref.MKB_HIDE_IDLE_CURSOR,
+ GlobalPref.NATIVE_MKB_FORCED_GAMES,
+ GlobalPref.NATIVE_MKB_MODE,
+ GlobalPref.REMOTE_PLAY_ENABLED,
+ GlobalPref.REMOTE_PLAY_STREAM_RESOLUTION,
+ GlobalPref.SCREENSHOT_APPLY_FILTERS,
+ GlobalPref.SERVER_BYPASS_RESTRICTION,
+ GlobalPref.SERVER_PREFER_IPV6,
+ GlobalPref.SERVER_REGION,
+ GlobalPref.STREAM_CODEC_PROFILE,
+ GlobalPref.STREAM_COMBINE_SOURCES,
+ GlobalPref.STREAM_MAX_VIDEO_BITRATE,
+ GlobalPref.STREAM_PREFERRED_LOCALE,
+ GlobalPref.STREAM_RESOLUTION,
+ GlobalPref.TOUCH_CONTROLLER_AUTO_OFF,
+ GlobalPref.TOUCH_CONTROLLER_DEFAULT_OPACITY,
+ GlobalPref.TOUCH_CONTROLLER_MODE,
+ GlobalPref.TOUCH_CONTROLLER_STYLE_CUSTOM,
+ GlobalPref.TOUCH_CONTROLLER_STYLE_STANDARD,
+ GlobalPref.UI_CONTROLLER_FRIENDLY,
+ GlobalPref.UI_CONTROLLER_SHOW_STATUS,
+ GlobalPref.UI_DISABLE_FEEDBACK_DIALOG,
+ GlobalPref.UI_GAME_CARD_SHOW_WAIT_TIME,
+ GlobalPref.UI_HIDE_SECTIONS,
+ GlobalPref.UI_HIDE_SYSTEM_MENU_ICON,
+ GlobalPref.UI_IMAGE_QUALITY,
+ GlobalPref.UI_LAYOUT,
+ GlobalPref.UI_REDUCE_ANIMATIONS,
+ GlobalPref.UI_SCROLLBAR_HIDE,
+ GlobalPref.UI_SIMPLIFY_STREAM_MENU,
+ GlobalPref.UI_SKIP_SPLASH_VIDEO,
+ GlobalPref.VERSION_CURRENT,
+ GlobalPref.VERSION_LAST_CHECK,
+ GlobalPref.VERSION_LATEST,
+
+ GlobalPref.SCRIPT_LOCALE,
+ GlobalPref.USER_AGENT_PROFILE,
+ ],
+ stream: [
+ StreamPref.AUDIO_VOLUME,
+ StreamPref.CONTROLLER_POLLING_RATE,
+ StreamPref.CONTROLLER_SETTINGS,
+ StreamPref.DEVICE_VIBRATION_INTENSITY,
+ StreamPref.DEVICE_VIBRATION_MODE,
+ StreamPref.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID,
+ StreamPref.LOCAL_CO_OP_ENABLED,
+ StreamPref.MKB_P1_MAPPING_PRESET_ID,
+ StreamPref.MKB_P1_SLOT,
+ StreamPref.MKB_P2_MAPPING_PRESET_ID,
+ StreamPref.MKB_P2_SLOT,
+ StreamPref.NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY,
+ StreamPref.NATIVE_MKB_SCROLL_VERTICAL_SENSITIVITY,
+ StreamPref.STATS_CONDITIONAL_FORMATTING,
+ StreamPref.STATS_ITEMS,
+ StreamPref.STATS_OPACITY_ALL,
+ StreamPref.STATS_OPACITY_BACKGROUND,
+ StreamPref.STATS_POSITION,
+ StreamPref.STATS_QUICK_GLANCE_ENABLED,
+ StreamPref.STATS_SHOW_WHEN_PLAYING,
+ StreamPref.STATS_TEXT_SIZE,
+ StreamPref.VIDEO_BRIGHTNESS,
+ StreamPref.VIDEO_CONTRAST,
+ StreamPref.VIDEO_MAX_FPS,
+ StreamPref.VIDEO_PLAYER_TYPE,
+ StreamPref.VIDEO_POSITION,
+ StreamPref.VIDEO_POWER_PREFERENCE,
+ StreamPref.VIDEO_PROCESSING,
+ StreamPref.VIDEO_RATIO,
+ StreamPref.VIDEO_SATURATION,
+ StreamPref.VIDEO_SHARPNESS,
+ ],
+} as const;
+
+export type AnySettingsStorage = BaseSettingsStorage | BaseSettingsStorage;
+export type AnyPref = GlobalPref | StreamPref;
+
+export type PrefTypeMap = Key extends GlobalPref
+ ? GlobalPrefTypeMap
+ : Key extends StreamPref
+ ? StreamPrefTypeMap
+ : never;
diff --git a/src/index.ts b/src/index.ts
index 38a00fc..f3288c0 100755
--- a/src/index.ts
+++ b/src/index.ts
@@ -32,8 +32,7 @@ import { HeaderSection } from "./modules/ui/header";
import { GameTile } from "./modules/ui/game-tile";
import { ProductDetailsPage } from "./modules/ui/product-details";
import { NavigationDialogManager } from "./modules/ui/dialog/navigation-dialog";
-import { PrefKey } from "./enums/pref-keys";
-import { getPref } from "./utils/settings-storages/global-settings-storage";
+import { GlobalPref, StreamPref } from "./enums/pref-keys";
import { SettingsDialog } from "./modules/ui/dialog/settings-dialog";
import { StreamUiHandler } from "./modules/stream/stream-ui";
import { UserAgent } from "./utils/user-agent";
@@ -45,6 +44,11 @@ import { KeyboardShortcutHandler } from "./modules/mkb/keyboard-shortcut-handler
import { GhPagesUtils } from "./utils/gh-pages";
import { DeviceVibrationManager } from "./modules/device-vibration-manager";
import { BxEventBus } from "./utils/bx-event-bus";
+import { getGlobalPref, getStreamPref } from "./utils/pref-utils";
+import { SettingsManager } from "./modules/settings-manager";
+import { Toast } from "./utils/toast";
+
+SettingsManager.getInstance();
// Handle login page
if (window.location.pathname.includes('/auth/msa')) {
@@ -173,7 +177,7 @@ document.addEventListener('readystatechange', e => {
}
// Hide "Play with Friends" skeleton section
- if (getPref(PrefKey.UI_HIDE_SECTIONS).includes(UiSection.FRIENDS) || getPref(PrefKey.BLOCK_FEATURES).includes(BlockFeature.FRIENDS)) {
+ if (getGlobalPref(GlobalPref.UI_HIDE_SECTIONS).includes(UiSection.FRIENDS) || getGlobalPref(GlobalPref.BLOCK_FEATURES).includes(BlockFeature.FRIENDS)) {
const $parent = document.querySelector('div[class*=PlayWithFriendsSkeleton]')?.closest('div[class*=HomePage-module]');
$parent && ($parent.style.display = 'none');
}
@@ -219,7 +223,7 @@ BxEventBus.Stream.on('state.loading', () => {
});
// Setup loading screen
-getPref(PrefKey.LOADING_SCREEN_GAME_ART) && BxEventBus.Script.on('titleInfo.ready', LoadingScreen.setup);
+getGlobalPref(GlobalPref.LOADING_SCREEN_GAME_ART) && BxEventBus.Script.on('titleInfo.ready', LoadingScreen.setup);
BxEventBus.Stream.on('state.starting', () => {
// Hide loading screen
@@ -260,7 +264,10 @@ BxEventBus.Stream.on('state.playing', payload => {
ScreenshotManager.getInstance().updateCanvasSize($video.videoWidth, $video.videoHeight);
// Setup local co-op
- getPref(PrefKey.LOCAL_CO_OP_ENABLED) && BxExposed.toggleLocalCoOp(getPref(PrefKey.LOCAL_CO_OP_ENABLED));
+ if (getStreamPref(StreamPref.LOCAL_CO_OP_ENABLED)) {
+ BxExposed.toggleLocalCoOp(true);
+ Toast.show(t('local-co-op'), t('enabled'));
+ }
}
@@ -295,20 +302,32 @@ BxEventBus.Stream.on('dataChannelCreated', payload => {
}
// Get xboxTitleId from message
+ const currentStream = STATES.currentStream;
const json = JSON.parse(JSON.parse(msg.data).content);
- const xboxTitleId = parseInt(json.titleid, 16);
- STATES.currentStream.xboxTitleId = xboxTitleId;
+ const currentId = currentStream.xboxTitleId ?? null;
+ let newId: number = parseInt(json.titleid, 16);
// Get titleSlug for Remote Play
if (STATES.remotePlay.isPlaying) {
- STATES.currentStream.titleSlug = 'remote-play';
+ currentStream.titleSlug = 'remote-play';
if (json.focused) {
- const productTitle = await XboxApi.getProductTitle(xboxTitleId);
+ const productTitle = await XboxApi.getProductTitle(newId);
if (productTitle) {
- STATES.currentStream.titleSlug = productTitleToSlug(productTitle);
+ currentStream.titleSlug = productTitleToSlug(productTitle);
+ } else {
+ newId = -1;
}
+ } else {
+ newId = 0;
}
}
+
+ if (currentId !== newId) {
+ currentStream.xboxTitleId = newId;
+ BxEventBus.Stream.emit('xboxTitleId.changed', {
+ id: newId,
+ });
+ }
});
});
@@ -345,6 +364,8 @@ function unload() {
TouchController.reset();
GameBar.getInstance()?.disable();
+
+ BxEventBus.Stream.emit('xboxTitleId.changed', { id: -1 });
}
}
@@ -362,8 +383,8 @@ function main() {
GhPagesUtils.fetchLatestCommit();
if (isFullVersion()) {
- if (getPref(PrefKey.NATIVE_MKB_MODE) !== NativeMkbMode.OFF) {
- const customList = getPref(PrefKey.NATIVE_MKB_FORCED_GAMES);
+ if (getGlobalPref(GlobalPref.NATIVE_MKB_MODE) !== NativeMkbMode.OFF) {
+ const customList = getGlobalPref(GlobalPref.NATIVE_MKB_FORCED_GAMES);
BX_FLAGS.ForceNativeMkbTitles.push(...customList);
}
}
@@ -378,9 +399,9 @@ function main() {
patchCanvasContext();
isFullVersion() && AppInterface && patchPointerLockApi();
- getPref(PrefKey.AUDIO_VOLUME_CONTROL_ENABLED) && patchAudioContext();
+ getGlobalPref(GlobalPref.AUDIO_VOLUME_CONTROL_ENABLED) && patchAudioContext();
- if (getPref(PrefKey.BLOCK_TRACKING)) {
+ if (getGlobalPref(GlobalPref.BLOCK_TRACKING)) {
patchMeControl();
disableAdobeAudienceManager();
}
@@ -407,28 +428,28 @@ function main() {
disablePwa();
// Preload Remote Play
- if (getPref(PrefKey.REMOTE_PLAY_ENABLED)) {
+ if (getGlobalPref(GlobalPref.REMOTE_PLAY_ENABLED)) {
RemotePlayManager.detect();
}
- if (getPref(PrefKey.TOUCH_CONTROLLER_MODE) === TouchControllerMode.ALL) {
+ if (getGlobalPref(GlobalPref.TOUCH_CONTROLLER_MODE) === TouchControllerMode.ALL) {
TouchController.setup();
}
// Start PointerProviderServer
- if (AppInterface && (getPref(PrefKey.MKB_ENABLED) || getPref(PrefKey.NATIVE_MKB_MODE) === NativeMkbMode.ON)) {
+ if (AppInterface && (getGlobalPref(GlobalPref.MKB_ENABLED) || getGlobalPref(GlobalPref.NATIVE_MKB_MODE) === NativeMkbMode.ON)) {
STATES.pointerServerPort = AppInterface.startPointerServer() || 9269;
BxLogger.info('startPointerServer', 'Port', STATES.pointerServerPort.toString());
}
// Show wait time in game card
- getPref(PrefKey.UI_GAME_CARD_SHOW_WAIT_TIME) && GameTile.setup();
+ getGlobalPref(GlobalPref.UI_GAME_CARD_SHOW_WAIT_TIME) && GameTile.setup();
EmulatedMkbHandler.setupEvents();
}
// Show a toast when connecting/disconecting controller
- if (getPref(PrefKey.UI_CONTROLLER_SHOW_STATUS)) {
+ if (getGlobalPref(GlobalPref.UI_CONTROLLER_SHOW_STATUS)) {
window.addEventListener('gamepadconnected', e => showGamepadToast(e.gamepad));
window.addEventListener('gamepaddisconnected', e => showGamepadToast(e.gamepad));
}
diff --git a/src/modules/device-vibration-manager.ts b/src/modules/device-vibration-manager.ts
index f3aa5d7..d703add 100755
--- a/src/modules/device-vibration-manager.ts
+++ b/src/modules/device-vibration-manager.ts
@@ -47,7 +47,7 @@ export class DeviceVibrationManager {
}
});
- BxEventBus.Script.on('deviceVibration.updated', () => this.setupDataChannel());
+ BxEventBus.Stream.on('deviceVibration.updated', () => this.setupDataChannel());
}
private setupDataChannel() {
diff --git a/src/modules/game-bar/game-bar.ts b/src/modules/game-bar/game-bar.ts
index e8c339f..aeab255 100755
--- a/src/modules/game-bar/game-bar.ts
+++ b/src/modules/game-bar/game-bar.ts
@@ -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(),
diff --git a/src/modules/loading-screen.ts b/src/modules/loading-screen.ts
index c7b7853..4fbfc5d 100755
--- a/src/modules/loading-screen.ts
+++ b/src/modules/loading-screen.ts
@@ -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(`
diff --git a/src/modules/mkb/key-helper.ts b/src/modules/mkb/key-helper.ts
index 86e2306..282fbc5 100755
--- a/src/modules/mkb/key-helper.ts
+++ b/src/modules/mkb/key-helper.ts
@@ -1,4 +1,4 @@
-import { MouseButtonCode, WheelCode, type KeyCode } from "@/enums/mkb";
+import { MouseButtonCode, WheelCode } from "@/enums/mkb";
export const enum KeyModifier {
CTRL = 1,
diff --git a/src/modules/mkb/mkb-handler.ts b/src/modules/mkb/mkb-handler.ts
index 9ba3857..fe8c8db 100755
--- a/src/modules/mkb/mkb-handler.ts
+++ b/src/modules/mkb/mkb-handler.ts
@@ -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();
});
}
diff --git a/src/modules/mkb/mkb-popup.ts b/src/modules/mkb/mkb-popup.ts
index 93be796..49d27c9 100755
--- a/src/modules/mkb/mkb-popup.ts
+++ b/src/modules/mkb/mkb-popup.ts
@@ -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;
diff --git a/src/modules/mkb/mouse-cursor-hider.ts b/src/modules/mkb/mouse-cursor-hider.ts
index 1bbf475..d6b072b 100755
--- a/src/modules/mkb/mouse-cursor-hider.ts
+++ b/src/modules/mkb/mouse-cursor-hider.ts
@@ -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;
diff --git a/src/modules/mkb/native-mkb-handler.ts b/src/modules/mkb/native-mkb-handler.ts
index 97d7821..2a99ad7 100755
--- a/src/modules/mkb/native-mkb-handler.ts
+++ b/src/modules/mkb/native-mkb-handler.ts
@@ -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);
diff --git a/src/modules/patcher/patcher.ts b/src/modules/patcher/patcher.ts
index b0655cd..ec588bb 100755
--- a/src/modules/patcher/patcher.ts
+++ b/src/modules/patcher/patcher.ts
@@ -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 = {
@@ -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',
] : []),
diff --git a/src/modules/patcher/patches/src/local-co-op-enable.ts b/src/modules/patcher/patches/src/local-co-op-enable.ts
index 106c072..dc6000d 100644
--- a/src/modules/patcher/patches/src/local-co-op-enable.ts
+++ b/src/modules/patcher/patches/src/local-co-op-enable.ts
@@ -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 }));
}
diff --git a/src/modules/player/webgl2-player.ts b/src/modules/player/webgl2-player.ts
index a872f05..4029345 100755
--- a/src/modules/player/webgl2-player.ts
+++ b/src/modules/player/webgl2-player.ts
@@ -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;
diff --git a/src/modules/remote-play-manager.ts b/src/modules/remote-play-manager.ts
index 40d1c28..662551d 100755
--- a/src/modules/remote-play-manager.ts
+++ b/src/modules/remote-play-manager.ts
@@ -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;
}
diff --git a/src/modules/settings-manager.ts b/src/modules/settings-manager.ts
new file mode 100644
index 0000000..db4504d
--- /dev/null
+++ b/src/modules/settings-manager.ts
@@ -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.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) {
+ 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 = 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;
+ }
+}
diff --git a/src/modules/shortcuts/renderer-shortcut.ts b/src/modules/shortcuts/renderer-shortcut.ts
index dc80fa6..dde76c6 100755
--- a/src/modules/shortcuts/renderer-shortcut.ts
+++ b/src/modules/shortcuts/renderer-shortcut.ts
@@ -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 });
}
}
diff --git a/src/modules/shortcuts/shortcut-actions.ts b/src/modules/shortcuts/shortcut-actions.ts
index 4541804..fd3c1c4 100755
--- a/src/modules/shortcuts/shortcut-actions.ts
+++ b/src/modules/shortcuts/shortcut-actions.ts
@@ -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')],
} : {}),
diff --git a/src/modules/shortcuts/sound-shortcut.ts b/src/modules/shortcuts/sound-shortcut.ts
index 6010d7e..7a147a7 100755
--- a/src/modules/shortcuts/sound-shortcut.ts
+++ b/src/modules/shortcuts/sound-shortcut.ts
@@ -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
diff --git a/src/modules/stream-player.ts b/src/modules/stream-player.ts
index 5bb50ba..3b6a842 100755
--- a/src/modules/stream-player.ts
+++ b/src/modules/stream-player.ts
@@ -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);
}
diff --git a/src/modules/stream/stream-settings-utils.ts b/src/modules/stream/stream-settings-utils.ts
index 51fa98a..7353b1a 100755
--- a/src/modules/stream/stream-settings-utils.ts
+++ b/src/modules/stream/stream-settings-utils.ts
@@ -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(`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();
}
diff --git a/src/modules/stream/stream-stats.ts b/src/modules/stream/stream-stats.ts
index d77fb44..a66b7bf 100755
--- a/src/modules/stream/stream-stats.ts
+++ b/src/modules/stream/stream-stats.ts
@@ -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();
diff --git a/src/modules/touch-controller.ts b/src/modules/touch-controller.ts
index 43a6519..c1c83af 100755
--- a/src/modules/touch-controller.ts
+++ b/src/modules/touch-controller.ts
@@ -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;
diff --git a/src/modules/ui/dialog/profile-manger/controller-customizations-manager-dialog.ts b/src/modules/ui/dialog/profile-manger/controller-customizations-manager-dialog.ts
index 717d5bc..d6314d0 100644
--- a/src/modules/ui/dialog/profile-manger/controller-customizations-manager-dialog.ts
+++ b/src/modules/ui/dialog/profile-manger/controller-customizations-manager-dialog.ts
@@ -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);
}
}
diff --git a/src/modules/ui/dialog/profile-manger/mkb-mapping-manager-dialog.ts b/src/modules/ui/dialog/profile-manger/mkb-mapping-manager-dialog.ts
index be88e6f..975f5bc 100755
--- a/src/modules/ui/dialog/profile-manger/mkb-mapping-manager-dialog.ts
+++ b/src/modules/ui/dialog/profile-manger/mkb-mapping-manager-dialog.ts
@@ -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";
diff --git a/src/modules/ui/dialog/remote-play-dialog.ts b/src/modules/ui/dialog/remote-play-dialog.ts
index 664590e..28a9062 100755
--- a/src/modules/ui/dialog/remote-play-dialog.ts
+++ b/src/modules/ui/dialog/remote-play-dialog.ts
@@ -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;
diff --git a/src/modules/ui/dialog/settings-dialog.ts b/src/modules/ui/dialog/settings-dialog.ts
index 20fe35b..84f067a 100755
--- a/src/modules/ui/dialog/settings-dialog.ts
+++ b/src/modules/ui/dialog/settings-dialog.ts
@@ -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;
@@ -59,17 +56,15 @@ type SettingTabSection = {
unsupportedNote?: HTMLElement | string | Text | null;
helpUrl?: string;
content?: HTMLElement;
- lazyContent?: boolean | (() => HTMLElement);
- items?: Array void) | false>;
+ items?: Array void) | false>;
requiredVariants?: BuildVariant | Array;
};
type SettingTab = {
icon: BxIconRaw;
group: SettingTabGroup,
- items: Array | (() => Array);
+ items: Array;
requiredVariants?: BuildVariant | Array;
- 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> = {
+ protected suggestedSettings: Record> = {
recommended: {},
default: {},
lowest: {},
highest: {},
};
- protected suggestedSettingLabels: PartialRecord = {};
- protected settingElements: PartialRecord = {};
+ protected settingLabels: PartialRecord = {};
+
+ protected settingsManager: SettingsManager;
private readonly TAB_GLOBAL_ITEMS: Array = [{
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('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 = 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) = isFullVersion() ? () => [
+ private readonly TAB_MKB_ITEMS: Array = 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 = [{
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(`#bx_setting_${escapeCssSelector(PrefKey.USER_AGENT_PROFILE)}`);
+ const $selectUserAgent = document.querySelector(`#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 {
- 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