mirror of
https://github.com/System-End/Vencord.git
synced 2026-04-19 16:28:16 +00:00
refactor: fix circular dependency issues & improve organisation (#3729)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
This commit is contained in:
parent
40fe13feda
commit
6afcce39dd
106 changed files with 1039 additions and 2273 deletions
|
|
@ -19,14 +19,16 @@
|
|||
/// <reference path="../src/modules.d.ts" />
|
||||
/// <reference path="../src/globals.d.ts" />
|
||||
|
||||
// Be very careful with imports in this file to avoid circular dependency issues.
|
||||
// Only import pure modules that don't import other parts of Vencord.
|
||||
import monacoHtmlLocal from "file://monacoWin.html?minify";
|
||||
import * as DataStore from "../src/api/DataStore";
|
||||
import { debounce, localStorage } from "../src/utils";
|
||||
import { EXTENSION_BASE_URL } from "../src/utils/web-metadata";
|
||||
import { getTheme, Theme } from "../src/utils/discord";
|
||||
import { getThemeInfo } from "../src/main/themes";
|
||||
import { Settings } from "../src/Vencord";
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import type { Settings } from "@api/Settings";
|
||||
import { getThemeInfo } from "@main/themes";
|
||||
import { debounce } from "@shared/debounce";
|
||||
import { localStorage } from "@utils/localStorage";
|
||||
import { getStylusWebStoreUrl } from "@utils/web";
|
||||
import { EXTENSION_BASE_URL } from "@utils/web-metadata";
|
||||
|
||||
// listeners for ipc.on
|
||||
const cssListeners = new Set<(css: string) => void>();
|
||||
|
|
@ -90,6 +92,8 @@ window.VencordNative = {
|
|||
return;
|
||||
}
|
||||
|
||||
const { getTheme, Theme } = require("@utils/discord");
|
||||
|
||||
win.baseUrl = EXTENSION_BASE_URL;
|
||||
win.setCss = setCssDebounced;
|
||||
win.getCurrentCss = () => VencordNative.quickCss.get();
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"@types/chrome": "^0.0.312",
|
||||
"@types/diff": "^7.0.2",
|
||||
"@types/lodash": "^4.17.14",
|
||||
"@types/node": "^22.13.13",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@types/yazl": "^2.4.5",
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
"ts-pattern": "^5.6.0",
|
||||
"tsx": "^4.19.3",
|
||||
"type-fest": "^4.38.0",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.28.0",
|
||||
"typescript-transform-paths": "^3.5.5",
|
||||
"zip-local": "^0.3.5"
|
||||
|
|
|
|||
298
pnpm-lock.yaml
generated
298
pnpm-lock.yaml
generated
|
|
@ -43,7 +43,7 @@ importers:
|
|||
devDependencies:
|
||||
'@stylistic/eslint-plugin':
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
version: 4.2.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
'@types/chrome':
|
||||
specifier: ^0.0.312
|
||||
version: 0.0.312
|
||||
|
|
@ -54,8 +54,8 @@ importers:
|
|||
specifier: ^4.17.14
|
||||
version: 4.17.15
|
||||
'@types/node':
|
||||
specifier: ^22.13.13
|
||||
version: 22.13.13
|
||||
specifier: ^24.10.1
|
||||
version: 24.10.1
|
||||
'@types/react':
|
||||
specifier: ^19.0.10
|
||||
version: 19.0.12
|
||||
|
|
@ -79,7 +79,7 @@ importers:
|
|||
version: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
eslint-import-resolver-alias:
|
||||
specifier: ^1.1.2
|
||||
version: 1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)))
|
||||
version: 1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)))
|
||||
eslint-plugin-path-alias:
|
||||
specifier: 2.1.0
|
||||
version: 2.1.0(patch_hash=87545cb13985b338c8fa2ea7b0a3c75c57ad7fbc81c56b38d6c9438329957727)(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
|
|
@ -94,7 +94,7 @@ importers:
|
|||
version: 12.1.1(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
eslint-plugin-unused-imports:
|
||||
specifier: ^4.1.4
|
||||
version: 4.1.4(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
version: 4.1.4(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
highlight.js:
|
||||
specifier: 11.11.1
|
||||
version: 11.11.1
|
||||
|
|
@ -112,10 +112,10 @@ importers:
|
|||
version: 34.2.0
|
||||
stylelint:
|
||||
specifier: ^16.17.0
|
||||
version: 16.17.0(typescript@5.8.2)
|
||||
version: 16.17.0(typescript@5.9.3)
|
||||
stylelint-config-standard:
|
||||
specifier: ^37.0.0
|
||||
version: 37.0.0(stylelint@16.17.0(typescript@5.8.2))
|
||||
version: 37.0.0(stylelint@16.17.0(typescript@5.9.3))
|
||||
ts-patch:
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0
|
||||
|
|
@ -129,14 +129,14 @@ importers:
|
|||
specifier: ^4.38.0
|
||||
version: 4.38.0
|
||||
typescript:
|
||||
specifier: ^5.8.2
|
||||
version: 5.8.2
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
typescript-eslint:
|
||||
specifier: ^8.28.0
|
||||
version: 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
version: 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
typescript-transform-paths:
|
||||
specifier: ^3.5.5
|
||||
version: 3.5.5(typescript@5.8.2)
|
||||
version: 3.5.5(typescript@5.9.3)
|
||||
zip-local:
|
||||
specifier: ^0.3.5
|
||||
version: 0.3.5
|
||||
|
|
@ -163,13 +163,13 @@ importers:
|
|||
version: 22.13.13
|
||||
'@types/react':
|
||||
specifier: 18.3.1
|
||||
version: 19.0.12
|
||||
version: 18.3.1
|
||||
'@types/react-dom':
|
||||
specifier: 18.3.1
|
||||
version: 18.3.1
|
||||
'@vencord/discord-types':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0(@types/react@19.0.12)
|
||||
version: 1.0.0(@types/react@18.3.1)
|
||||
highlight.js:
|
||||
specifier: 11.11.1
|
||||
version: 11.11.1
|
||||
|
|
@ -529,6 +529,15 @@ packages:
|
|||
'@types/node@22.13.13':
|
||||
resolution: {integrity: sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==}
|
||||
|
||||
'@types/node@22.19.1':
|
||||
resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==}
|
||||
|
||||
'@types/node@24.10.1':
|
||||
resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==}
|
||||
|
||||
'@types/prop-types@15.7.15':
|
||||
resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
|
||||
|
||||
'@types/react-dom@18.3.1':
|
||||
resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==}
|
||||
|
||||
|
|
@ -537,6 +546,9 @@ packages:
|
|||
peerDependencies:
|
||||
'@types/react': ^19.0.0
|
||||
|
||||
'@types/react@18.3.1':
|
||||
resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==}
|
||||
|
||||
'@types/react@19.0.12':
|
||||
resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==}
|
||||
|
||||
|
|
@ -651,6 +663,10 @@ packages:
|
|||
resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
array-includes@3.1.9:
|
||||
resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
array-union@2.1.0:
|
||||
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -887,6 +903,9 @@ packages:
|
|||
csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
csstype@3.2.1:
|
||||
resolution: {integrity: sha512-98XGutrXoh75MlgLihlNxAGbUuFQc7l1cqcnEZlLNKc0UrVdPndgmaDmYTDDh929VS/eqTZV0rozmhu2qqT1/g==}
|
||||
|
||||
data-uri-to-buffer@6.0.2:
|
||||
resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==}
|
||||
engines: {node: '>= 14'}
|
||||
|
|
@ -1002,6 +1021,10 @@ packages:
|
|||
resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-abstract@1.24.0:
|
||||
resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-define-property@1.0.1:
|
||||
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -1057,8 +1080,8 @@ packages:
|
|||
eslint-import-resolver-node@0.3.9:
|
||||
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
|
||||
|
||||
eslint-module-utils@2.12.0:
|
||||
resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==}
|
||||
eslint-module-utils@2.12.1:
|
||||
resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
|
|
@ -1560,6 +1583,10 @@ packages:
|
|||
resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-negative-zero@2.0.3:
|
||||
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-number-object@1.1.1:
|
||||
resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -2063,6 +2090,11 @@ packages:
|
|||
engines: {node: '>= 0.4'}
|
||||
hasBin: true
|
||||
|
||||
resolve@1.22.11:
|
||||
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
hasBin: true
|
||||
|
||||
resolve@2.0.0-next.5:
|
||||
resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
|
||||
hasBin: true
|
||||
|
|
@ -2207,6 +2239,10 @@ packages:
|
|||
resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
stop-iteration-iterator@1.1.0:
|
||||
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
streamx@2.22.0:
|
||||
resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==}
|
||||
|
||||
|
|
@ -2374,8 +2410,8 @@ packages:
|
|||
peerDependencies:
|
||||
typescript: '>=3.6.5'
|
||||
|
||||
typescript@5.8.2:
|
||||
resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
|
||||
typescript@5.9.3:
|
||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
|
|
@ -2386,6 +2422,12 @@ packages:
|
|||
undici-types@6.20.0:
|
||||
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
|
||||
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
|
||||
union-value@1.0.1:
|
||||
resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
@ -2719,9 +2761,9 @@ snapshots:
|
|||
|
||||
'@rtsao/scc@1.1.0': {}
|
||||
|
||||
'@stylistic/eslint-plugin@4.2.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)':
|
||||
'@stylistic/eslint-plugin@4.2.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
eslint-visitor-keys: 4.2.0
|
||||
espree: 10.3.0
|
||||
|
|
@ -2769,53 +2811,68 @@ snapshots:
|
|||
dependencies:
|
||||
undici-types: 6.20.0
|
||||
|
||||
'@types/node@22.19.1':
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@types/node@24.10.1':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
|
||||
'@types/prop-types@15.7.15': {}
|
||||
|
||||
'@types/react-dom@18.3.1':
|
||||
dependencies:
|
||||
'@types/react': 19.0.12
|
||||
'@types/react': 18.3.1
|
||||
|
||||
'@types/react-dom@19.0.4(@types/react@19.0.12)':
|
||||
dependencies:
|
||||
'@types/react': 19.0.12
|
||||
|
||||
'@types/react@18.3.1':
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.15
|
||||
csstype: 3.2.1
|
||||
|
||||
'@types/react@19.0.12':
|
||||
dependencies:
|
||||
csstype: 3.1.3
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
dependencies:
|
||||
'@types/node': 22.13.13
|
||||
'@types/node': 24.10.1
|
||||
optional: true
|
||||
|
||||
'@types/yazl@2.4.6':
|
||||
dependencies:
|
||||
'@types/node': 22.13.13
|
||||
'@types/node': 24.10.1
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)':
|
||||
'@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.1
|
||||
'@typescript-eslint/parser': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/parser': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
'@typescript-eslint/scope-manager': 8.28.0
|
||||
'@typescript-eslint/type-utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/type-utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.28.0
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
graphemer: 1.4.0
|
||||
ignore: 5.3.2
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 2.1.0(typescript@5.8.2)
|
||||
typescript: 5.8.2
|
||||
ts-api-utils: 2.1.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)':
|
||||
'@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.28.0
|
||||
'@typescript-eslint/types': 8.28.0
|
||||
'@typescript-eslint/typescript-estree': 8.28.0(typescript@5.8.2)
|
||||
'@typescript-eslint/typescript-estree': 8.28.0(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.28.0
|
||||
debug: 4.4.0
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
typescript: 5.8.2
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -2824,20 +2881,20 @@ snapshots:
|
|||
'@typescript-eslint/types': 8.28.0
|
||||
'@typescript-eslint/visitor-keys': 8.28.0
|
||||
|
||||
'@typescript-eslint/type-utils@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)':
|
||||
'@typescript-eslint/type-utils@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 8.28.0(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/typescript-estree': 8.28.0(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
debug: 4.4.0
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
ts-api-utils: 2.1.0(typescript@5.8.2)
|
||||
typescript: 5.8.2
|
||||
ts-api-utils: 2.1.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/types@8.28.0': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.28.0(typescript@5.8.2)':
|
||||
'@typescript-eslint/typescript-estree@8.28.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.28.0
|
||||
'@typescript-eslint/visitor-keys': 8.28.0
|
||||
|
|
@ -2846,19 +2903,19 @@ snapshots:
|
|||
is-glob: 4.0.3
|
||||
minimatch: 9.0.5
|
||||
semver: 7.7.1
|
||||
ts-api-utils: 2.1.0(typescript@5.8.2)
|
||||
typescript: 5.8.2
|
||||
ts-api-utils: 2.1.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)':
|
||||
'@typescript-eslint/utils@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.5.1(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
'@typescript-eslint/scope-manager': 8.28.0
|
||||
'@typescript-eslint/types': 8.28.0
|
||||
'@typescript-eslint/typescript-estree': 8.28.0(typescript@5.8.2)
|
||||
'@typescript-eslint/typescript-estree': 8.28.0(typescript@5.9.3)
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
typescript: 5.8.2
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -2877,9 +2934,9 @@ snapshots:
|
|||
vscode-oniguruma: 1.7.0
|
||||
vscode-textmate: 5.2.0
|
||||
|
||||
'@vencord/discord-types@1.0.0(@types/react@19.0.12)':
|
||||
'@vencord/discord-types@1.0.0(@types/react@18.3.1)':
|
||||
dependencies:
|
||||
'@types/react': 19.0.12
|
||||
'@types/react': 18.3.1
|
||||
moment: 2.30.1
|
||||
type-fest: 4.41.0
|
||||
|
||||
|
|
@ -2931,6 +2988,17 @@ snapshots:
|
|||
get-intrinsic: 1.3.0
|
||||
is-string: 1.1.1
|
||||
|
||||
array-includes@3.1.9:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.24.0
|
||||
es-object-atoms: 1.1.1
|
||||
get-intrinsic: 1.3.0
|
||||
is-string: 1.1.1
|
||||
math-intrinsics: 1.1.0
|
||||
|
||||
array-union@2.1.0: {}
|
||||
|
||||
array-unique@0.3.2: {}
|
||||
|
|
@ -2949,7 +3017,7 @@ snapshots:
|
|||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.23.9
|
||||
es-abstract: 1.24.0
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.1
|
||||
es-shim-unscopables: 1.1.0
|
||||
|
|
@ -3163,14 +3231,14 @@ snapshots:
|
|||
|
||||
copy-descriptor@0.1.1: {}
|
||||
|
||||
cosmiconfig@9.0.0(typescript@5.8.2):
|
||||
cosmiconfig@9.0.0(typescript@5.9.3):
|
||||
dependencies:
|
||||
env-paths: 2.2.1
|
||||
import-fresh: 3.3.1
|
||||
js-yaml: 4.1.0
|
||||
parse-json: 5.2.0
|
||||
optionalDependencies:
|
||||
typescript: 5.8.2
|
||||
typescript: 5.9.3
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
|
|
@ -3189,6 +3257,8 @@ snapshots:
|
|||
|
||||
csstype@3.1.3: {}
|
||||
|
||||
csstype@3.2.1: {}
|
||||
|
||||
data-uri-to-buffer@6.0.2: {}
|
||||
|
||||
data-view-buffer@1.0.2:
|
||||
|
|
@ -3347,6 +3417,63 @@ snapshots:
|
|||
unbox-primitive: 1.1.0
|
||||
which-typed-array: 1.1.19
|
||||
|
||||
es-abstract@1.24.0:
|
||||
dependencies:
|
||||
array-buffer-byte-length: 1.0.2
|
||||
arraybuffer.prototype.slice: 1.0.4
|
||||
available-typed-arrays: 1.0.7
|
||||
call-bind: 1.0.8
|
||||
call-bound: 1.0.4
|
||||
data-view-buffer: 1.0.2
|
||||
data-view-byte-length: 1.0.2
|
||||
data-view-byte-offset: 1.0.1
|
||||
es-define-property: 1.0.1
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.1
|
||||
es-set-tostringtag: 2.1.0
|
||||
es-to-primitive: 1.3.0
|
||||
function.prototype.name: 1.1.8
|
||||
get-intrinsic: 1.3.0
|
||||
get-proto: 1.0.1
|
||||
get-symbol-description: 1.1.0
|
||||
globalthis: 1.0.4
|
||||
gopd: 1.2.0
|
||||
has-property-descriptors: 1.0.2
|
||||
has-proto: 1.2.0
|
||||
has-symbols: 1.1.0
|
||||
hasown: 2.0.2
|
||||
internal-slot: 1.1.0
|
||||
is-array-buffer: 3.0.5
|
||||
is-callable: 1.2.7
|
||||
is-data-view: 1.0.2
|
||||
is-negative-zero: 2.0.3
|
||||
is-regex: 1.2.1
|
||||
is-set: 2.0.3
|
||||
is-shared-array-buffer: 1.0.4
|
||||
is-string: 1.1.1
|
||||
is-typed-array: 1.1.15
|
||||
is-weakref: 1.1.1
|
||||
math-intrinsics: 1.1.0
|
||||
object-inspect: 1.13.4
|
||||
object-keys: 1.1.1
|
||||
object.assign: 4.1.7
|
||||
own-keys: 1.0.1
|
||||
regexp.prototype.flags: 1.5.4
|
||||
safe-array-concat: 1.1.3
|
||||
safe-push-apply: 1.0.0
|
||||
safe-regex-test: 1.1.0
|
||||
set-proto: 1.0.0
|
||||
stop-iteration-iterator: 1.1.0
|
||||
string.prototype.trim: 1.2.10
|
||||
string.prototype.trimend: 1.0.9
|
||||
string.prototype.trimstart: 1.0.8
|
||||
typed-array-buffer: 1.0.3
|
||||
typed-array-byte-length: 1.0.3
|
||||
typed-array-byte-offset: 1.0.4
|
||||
typed-array-length: 1.0.7
|
||||
unbox-primitive: 1.1.0
|
||||
which-typed-array: 1.1.19
|
||||
|
||||
es-define-property@1.0.1: {}
|
||||
|
||||
es-errors@1.3.0: {}
|
||||
|
|
@ -3431,32 +3558,32 @@ snapshots:
|
|||
optionalDependencies:
|
||||
source-map: 0.6.1
|
||||
|
||||
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))):
|
||||
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))):
|
||||
dependencies:
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
|
||||
eslint-import-resolver-node@0.3.9:
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
is-core-module: 2.16.1
|
||||
resolve: 1.22.10
|
||||
resolve: 1.22.11
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)):
|
||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/parser': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)):
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.8
|
||||
array-includes: 3.1.9
|
||||
array.prototype.findlastindex: 1.2.6
|
||||
array.prototype.flat: 1.3.3
|
||||
array.prototype.flatmap: 1.3.3
|
||||
|
|
@ -3464,7 +3591,7 @@ snapshots:
|
|||
doctrine: 2.1.0
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.16.1
|
||||
is-glob: 4.0.3
|
||||
|
|
@ -3476,7 +3603,7 @@ snapshots:
|
|||
string.prototype.trimend: 1.0.9
|
||||
tsconfig-paths: 3.15.0
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/parser': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-typescript
|
||||
- eslint-import-resolver-webpack
|
||||
|
|
@ -3521,11 +3648,11 @@ snapshots:
|
|||
dependencies:
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
|
||||
eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)):
|
||||
eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)):
|
||||
dependencies:
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/eslint-plugin': 8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
|
||||
eslint-scope@8.3.0:
|
||||
dependencies:
|
||||
|
|
@ -4020,6 +4147,8 @@ snapshots:
|
|||
|
||||
is-map@2.0.3: {}
|
||||
|
||||
is-negative-zero@2.0.3: {}
|
||||
|
||||
is-number-object@1.1.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
|
|
@ -4307,7 +4436,7 @@ snapshots:
|
|||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.23.9
|
||||
es-abstract: 1.24.0
|
||||
|
||||
object.pick@1.3.0:
|
||||
dependencies:
|
||||
|
|
@ -4531,6 +4660,12 @@ snapshots:
|
|||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
resolve@1.22.11:
|
||||
dependencies:
|
||||
is-core-module: 2.16.1
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
resolve@2.0.0-next.5:
|
||||
dependencies:
|
||||
is-core-module: 2.16.1
|
||||
|
|
@ -4702,13 +4837,18 @@ snapshots:
|
|||
|
||||
standalone-electron-types@34.2.0:
|
||||
dependencies:
|
||||
'@types/node': 22.13.13
|
||||
'@types/node': 22.19.1
|
||||
|
||||
static-extend@0.1.2:
|
||||
dependencies:
|
||||
define-property: 0.2.5
|
||||
object-copy: 0.1.0
|
||||
|
||||
stop-iteration-iterator@1.1.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
internal-slot: 1.1.0
|
||||
|
||||
streamx@2.22.0:
|
||||
dependencies:
|
||||
fast-fifo: 1.3.2
|
||||
|
|
@ -4774,16 +4914,16 @@ snapshots:
|
|||
|
||||
strip-json-comments@3.1.1: {}
|
||||
|
||||
stylelint-config-recommended@15.0.0(stylelint@16.17.0(typescript@5.8.2)):
|
||||
stylelint-config-recommended@15.0.0(stylelint@16.17.0(typescript@5.9.3)):
|
||||
dependencies:
|
||||
stylelint: 16.17.0(typescript@5.8.2)
|
||||
stylelint: 16.17.0(typescript@5.9.3)
|
||||
|
||||
stylelint-config-standard@37.0.0(stylelint@16.17.0(typescript@5.8.2)):
|
||||
stylelint-config-standard@37.0.0(stylelint@16.17.0(typescript@5.9.3)):
|
||||
dependencies:
|
||||
stylelint: 16.17.0(typescript@5.8.2)
|
||||
stylelint-config-recommended: 15.0.0(stylelint@16.17.0(typescript@5.8.2))
|
||||
stylelint: 16.17.0(typescript@5.9.3)
|
||||
stylelint-config-recommended: 15.0.0(stylelint@16.17.0(typescript@5.9.3))
|
||||
|
||||
stylelint@16.17.0(typescript@5.8.2):
|
||||
stylelint@16.17.0(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
|
||||
'@csstools/css-tokenizer': 3.0.3
|
||||
|
|
@ -4792,7 +4932,7 @@ snapshots:
|
|||
'@dual-bundle/import-meta-resolve': 4.1.0
|
||||
balanced-match: 2.0.0
|
||||
colord: 2.9.3
|
||||
cosmiconfig: 9.0.0(typescript@5.8.2)
|
||||
cosmiconfig: 9.0.0(typescript@5.9.3)
|
||||
css-functions-list: 3.2.3
|
||||
css-tree: 3.1.0
|
||||
debug: 4.4.0
|
||||
|
|
@ -4890,9 +5030,9 @@ snapshots:
|
|||
regex-not: 1.0.2
|
||||
safe-regex: 1.1.0
|
||||
|
||||
ts-api-utils@2.1.0(typescript@5.8.2):
|
||||
ts-api-utils@2.1.0(typescript@5.9.3):
|
||||
dependencies:
|
||||
typescript: 5.8.2
|
||||
typescript: 5.9.3
|
||||
|
||||
ts-patch@3.3.0:
|
||||
dependencies:
|
||||
|
|
@ -4964,22 +5104,22 @@ snapshots:
|
|||
|
||||
typed-query-selector@2.12.0: {}
|
||||
|
||||
typescript-eslint@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2):
|
||||
typescript-eslint@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/parser': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.8.2)
|
||||
'@typescript-eslint/eslint-plugin': 8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3))(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
'@typescript-eslint/parser': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.28.0(eslint@9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215))(typescript@5.9.3)
|
||||
eslint: 9.20.1(patch_hash=4f22e92770bf528b2448fbec0984b9c0761dd588ed0e83dcc41edfc9af711215)
|
||||
typescript: 5.8.2
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
typescript-transform-paths@3.5.5(typescript@5.8.2):
|
||||
typescript-transform-paths@3.5.5(typescript@5.9.3):
|
||||
dependencies:
|
||||
minimatch: 9.0.5
|
||||
typescript: 5.8.2
|
||||
typescript: 5.9.3
|
||||
|
||||
typescript@5.8.2: {}
|
||||
typescript@5.9.3: {}
|
||||
|
||||
unbox-primitive@1.1.0:
|
||||
dependencies:
|
||||
|
|
@ -4990,6 +5130,10 @@ snapshots:
|
|||
|
||||
undici-types@6.20.0: {}
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
|
||||
union-value@1.0.1:
|
||||
dependencies:
|
||||
arr-union: 3.1.0
|
||||
|
|
|
|||
|
|
@ -20,34 +20,32 @@
|
|||
import "~plugins";
|
||||
|
||||
export * as Api from "./api";
|
||||
export * as Plugins from "./api/PluginManager";
|
||||
export * as Components from "./components";
|
||||
export * as Plugins from "./plugins";
|
||||
export * as Util from "./utils";
|
||||
export * as QuickCss from "./utils/quickCss";
|
||||
export * as Updater from "./utils/updater";
|
||||
export * as Webpack from "./webpack";
|
||||
export * as WebpackPatcher from "./webpack/patchWebpack";
|
||||
export { PlainSettings, Settings };
|
||||
|
||||
import "./utils/quickCss";
|
||||
import "./webpack/patchWebpack";
|
||||
|
||||
import { addVencordUiStyles } from "@components/css";
|
||||
import { openUpdaterModal } from "@components/settings/tabs/updater";
|
||||
import { debounce } from "@shared/debounce";
|
||||
import { IS_WINDOWS } from "@utils/constants";
|
||||
import { createAndAppendStyle } from "@utils/css";
|
||||
import { StartAt } from "@utils/types";
|
||||
|
||||
import { get as dsGet } from "./api/DataStore";
|
||||
import { NotificationData, showNotification } from "./api/Notifications";
|
||||
import { PlainSettings, Settings } from "./api/Settings";
|
||||
import { patches, PMLogger, startAllPlugins } from "./plugins";
|
||||
import { initPluginManager, PMLogger, startAllPlugins } from "./api/PluginManager";
|
||||
import { PlainSettings, Settings, SettingsStore } from "./api/Settings";
|
||||
import { getCloudSettings, putCloudSettings } from "./api/SettingsSync/cloudSync";
|
||||
import { localStorage } from "./utils/localStorage";
|
||||
import { relaunch } from "./utils/native";
|
||||
import { getCloudSettings, putCloudSettings } from "./utils/settingsSync";
|
||||
import { checkForUpdates, update, UpdateLogger } from "./utils/updater";
|
||||
import { onceReady } from "./webpack";
|
||||
import { SettingsRouter } from "./webpack/common";
|
||||
import { patches } from "./webpack/patchWebpack";
|
||||
|
||||
if (IS_REPORTER) {
|
||||
require("./debug/runReporter");
|
||||
|
|
@ -90,6 +88,18 @@ async function syncSettings() {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
const saveSettingsOnFrequentAction = debounce(async () => {
|
||||
if (Settings.cloud.settingsSync && Settings.cloud.authenticated) {
|
||||
await putCloudSettings();
|
||||
delete localStorage.Vencord_settingsDirty;
|
||||
}
|
||||
}, 60_000);
|
||||
|
||||
SettingsStore.addGlobalChangeListener(() => {
|
||||
localStorage.Vencord_settingsDirty = true;
|
||||
saveSettingsOnFrequentAction();
|
||||
});
|
||||
}
|
||||
|
||||
let notifiedForUpdatesThisSession = false;
|
||||
|
|
@ -161,6 +171,7 @@ async function init() {
|
|||
}
|
||||
}
|
||||
|
||||
initPluginManager();
|
||||
startAllPlugins(StartAt.Init);
|
||||
init();
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import BadgeAPIPlugin from "plugins/_api/badges";
|
||||
import BadgeAPIPlugin from "@plugins/_api/badges";
|
||||
import { ComponentType, HTMLProps } from "react";
|
||||
|
||||
export const enum BadgePosition {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { addMessagePopoverButton, removeMessagePopoverButton } from "@api/Messag
|
|||
import { Settings, SettingsStore } from "@api/Settings";
|
||||
import { disableStyle, enableStyle } from "@api/Styles";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { onlyOnce } from "@utils/onlyOnce";
|
||||
import { canonicalizeFind, canonicalizeReplacement } from "@utils/patches";
|
||||
import { Patch, Plugin, PluginDef, ReporterTestable, StartAt } from "@utils/types";
|
||||
import { FluxEvents } from "@vencord/discord-types";
|
||||
|
|
@ -35,27 +36,23 @@ import { FluxDispatcher } from "@webpack/common";
|
|||
import { patches } from "@webpack/patcher";
|
||||
|
||||
import Plugins from "~plugins";
|
||||
export { Plugins as plugins };
|
||||
|
||||
import { traceFunction } from "../debug/Tracer";
|
||||
|
||||
const logger = new Logger("PluginManager", "#a6d189");
|
||||
|
||||
export const PMLogger = logger;
|
||||
export const plugins = Plugins;
|
||||
export { patches };
|
||||
|
||||
/** Whether we have subscribed to flux events of all the enabled plugins when FluxDispatcher was ready */
|
||||
let enabledPluginsSubscribedFlux = false;
|
||||
const subscribedFluxEventsPlugins = new Set<string>();
|
||||
|
||||
const pluginsValues = Object.values(Plugins);
|
||||
const settings = Settings.plugins;
|
||||
|
||||
export function isPluginEnabled(p: string) {
|
||||
return (
|
||||
Plugins[p]?.required ||
|
||||
Plugins[p]?.isDependency ||
|
||||
settings[p]?.enabled
|
||||
Settings.plugins[p]?.enabled
|
||||
) ?? false;
|
||||
}
|
||||
|
||||
|
|
@ -94,85 +91,6 @@ function isReporterTestable(p: Plugin, part: ReporterTestable) {
|
|||
: (p.reporterTestable & part) === part;
|
||||
}
|
||||
|
||||
const pluginKeysToBind: Array<keyof PluginDef & `${"on" | "render"}${string}`> = [
|
||||
"onBeforeMessageEdit", "onBeforeMessageSend", "onMessageClick",
|
||||
"renderChatBarButton", "renderMemberListDecorator", "renderMessageAccessory", "renderMessageDecoration", "renderMessagePopoverButton"
|
||||
];
|
||||
|
||||
const neededApiPlugins = new Set<string>();
|
||||
|
||||
// First round-trip to mark and force enable dependencies
|
||||
//
|
||||
// FIXME: might need to revisit this if there's ever nested (dependencies of dependencies) dependencies since this only
|
||||
// goes for the top level and their children, but for now this works okay with the current API plugins
|
||||
for (const p of pluginsValues) if (isPluginEnabled(p.name)) {
|
||||
p.dependencies?.forEach(d => {
|
||||
const dep = Plugins[d];
|
||||
|
||||
if (!dep) {
|
||||
const error = new Error(`Plugin ${p.name} has unresolved dependency ${d}`);
|
||||
|
||||
if (IS_DEV) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
logger.warn(error);
|
||||
return;
|
||||
}
|
||||
|
||||
settings[d].enabled = true;
|
||||
dep.isDependency = true;
|
||||
});
|
||||
|
||||
if (p.commands?.length) neededApiPlugins.add("CommandsAPI");
|
||||
if (p.onBeforeMessageEdit || p.onBeforeMessageSend || p.onMessageClick) neededApiPlugins.add("MessageEventsAPI");
|
||||
if (p.renderChatBarButton) neededApiPlugins.add("ChatInputButtonAPI");
|
||||
if (p.renderMemberListDecorator) neededApiPlugins.add("MemberListDecoratorsAPI");
|
||||
if (p.renderMessageAccessory) neededApiPlugins.add("MessageAccessoriesAPI");
|
||||
if (p.renderMessageDecoration) neededApiPlugins.add("MessageDecorationsAPI");
|
||||
if (p.renderMessagePopoverButton) neededApiPlugins.add("MessagePopoverAPI");
|
||||
if (p.userProfileBadge) neededApiPlugins.add("BadgeAPI");
|
||||
|
||||
for (const key of pluginKeysToBind) {
|
||||
p[key] &&= p[key].bind(p) as any;
|
||||
}
|
||||
}
|
||||
|
||||
for (const p of neededApiPlugins) {
|
||||
Plugins[p].isDependency = true;
|
||||
settings[p].enabled = true;
|
||||
}
|
||||
|
||||
for (const p of pluginsValues) {
|
||||
if (p.settings) {
|
||||
p.options ??= {};
|
||||
|
||||
p.settings.pluginName = p.name;
|
||||
for (const name in p.settings.def) {
|
||||
const def = p.settings.def[name];
|
||||
const checks = p.settings.checks?.[name];
|
||||
p.options[name] = { ...def, ...checks };
|
||||
}
|
||||
}
|
||||
|
||||
if (p.options) {
|
||||
for (const name in p.options) {
|
||||
const opt = p.options[name];
|
||||
if (opt.onChange != null) {
|
||||
SettingsStore.addChangeListener(`plugins.${p.name}.${name}`, opt.onChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p.patches && isPluginEnabled(p.name)) {
|
||||
if (!IS_REPORTER || isReporterTestable(p, ReporterTestable.Patches)) {
|
||||
for (const patch of p.patches) {
|
||||
addPatch(patch, p.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const startAllPlugins = traceFunction("startAllPlugins", function startAllPlugins(target: StartAt) {
|
||||
logger.info(`Starting plugins (stage ${target})`);
|
||||
for (const name in Plugins) {
|
||||
|
|
@ -188,6 +106,7 @@ export const startAllPlugins = traceFunction("startAllPlugins", function startAl
|
|||
});
|
||||
|
||||
export function startDependenciesRecursive(p: Plugin) {
|
||||
const settings = Settings.plugins;
|
||||
let restartNeeded = false;
|
||||
const failures: string[] = [];
|
||||
|
||||
|
|
@ -379,3 +298,87 @@ export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plu
|
|||
|
||||
return true;
|
||||
}, p => `stopPlugin ${p.name}`);
|
||||
|
||||
export const initPluginManager = onlyOnce(function init() {
|
||||
const pluginsValues = Object.values(Plugins);
|
||||
const settings = Settings.plugins;
|
||||
|
||||
const pluginKeysToBind: Array<keyof PluginDef & `${"on" | "render"}${string}`> = [
|
||||
"onBeforeMessageEdit", "onBeforeMessageSend", "onMessageClick",
|
||||
"renderChatBarButton", "renderMemberListDecorator", "renderMessageAccessory", "renderMessageDecoration", "renderMessagePopoverButton"
|
||||
];
|
||||
|
||||
const neededApiPlugins = new Set<string>();
|
||||
|
||||
// First round-trip to mark and force enable dependencies
|
||||
//
|
||||
// FIXME: might need to revisit this if there's ever nested (dependencies of dependencies) dependencies since this only
|
||||
// goes for the top level and their children, but for now this works okay with the current API plugins
|
||||
for (const p of pluginsValues) if (isPluginEnabled(p.name)) {
|
||||
p.dependencies?.forEach(d => {
|
||||
const dep = Plugins[d];
|
||||
|
||||
if (!dep) {
|
||||
const error = new Error(`Plugin ${p.name} has unresolved dependency ${d}`);
|
||||
|
||||
if (IS_DEV) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
logger.warn(error);
|
||||
return;
|
||||
}
|
||||
|
||||
settings[d].enabled = true;
|
||||
dep.isDependency = true;
|
||||
});
|
||||
|
||||
if (p.commands?.length) neededApiPlugins.add("CommandsAPI");
|
||||
if (p.onBeforeMessageEdit || p.onBeforeMessageSend || p.onMessageClick) neededApiPlugins.add("MessageEventsAPI");
|
||||
if (p.renderChatBarButton) neededApiPlugins.add("ChatInputButtonAPI");
|
||||
if (p.renderMemberListDecorator) neededApiPlugins.add("MemberListDecoratorsAPI");
|
||||
if (p.renderMessageAccessory) neededApiPlugins.add("MessageAccessoriesAPI");
|
||||
if (p.renderMessageDecoration) neededApiPlugins.add("MessageDecorationsAPI");
|
||||
if (p.renderMessagePopoverButton) neededApiPlugins.add("MessagePopoverAPI");
|
||||
if (p.userProfileBadge) neededApiPlugins.add("BadgeAPI");
|
||||
|
||||
for (const key of pluginKeysToBind) {
|
||||
p[key] &&= p[key].bind(p) as any;
|
||||
}
|
||||
}
|
||||
|
||||
for (const p of neededApiPlugins) {
|
||||
Plugins[p].isDependency = true;
|
||||
settings[p].enabled = true;
|
||||
}
|
||||
|
||||
for (const p of pluginsValues) {
|
||||
if (p.settings) {
|
||||
p.options ??= {};
|
||||
|
||||
p.settings.pluginName = p.name;
|
||||
for (const name in p.settings.def) {
|
||||
const def = p.settings.def[name];
|
||||
const checks = p.settings.checks?.[name];
|
||||
p.options[name] = { ...def, ...checks };
|
||||
}
|
||||
}
|
||||
|
||||
if (p.options) {
|
||||
for (const name in p.options) {
|
||||
const opt = p.options[name];
|
||||
if (opt.onChange != null) {
|
||||
SettingsStore.addChangeListener(`plugins.${p.name}.${name}`, opt.onChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p.patches && isPluginEnabled(p.name)) {
|
||||
if (!IS_REPORTER || isReporterTestable(p, ReporterTestable.Patches)) {
|
||||
for (const patch of p.patches) {
|
||||
addPatch(patch, p.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -16,12 +16,9 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { debounce } from "@shared/debounce";
|
||||
import { SettingsStore as SettingsStoreClass } from "@shared/SettingsStore";
|
||||
import { localStorage } from "@utils/localStorage";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { mergeDefaults } from "@utils/mergeDefaults";
|
||||
import { putCloudSettings } from "@utils/settingsSync";
|
||||
import { DefinedSettings, OptionType, SettingsChecks, SettingsDefinition } from "@utils/types";
|
||||
import { React, useEffect } from "@webpack/common";
|
||||
|
||||
|
|
@ -111,14 +108,6 @@ const DefaultSettings: Settings = {
|
|||
const settings = !IS_REPORTER ? VencordNative.settings.get() : {} as Settings;
|
||||
mergeDefaults(settings, DefaultSettings);
|
||||
|
||||
const saveSettingsOnFrequentAction = debounce(async () => {
|
||||
if (Settings.cloud.settingsSync && Settings.cloud.authenticated) {
|
||||
await putCloudSettings();
|
||||
delete localStorage.Vencord_settingsDirty;
|
||||
}
|
||||
}, 60_000);
|
||||
|
||||
|
||||
export const SettingsStore = new SettingsStoreClass(settings, {
|
||||
readOnly: true,
|
||||
getDefaultValue({
|
||||
|
|
@ -161,8 +150,6 @@ export const SettingsStore = new SettingsStoreClass(settings, {
|
|||
if (!IS_REPORTER) {
|
||||
SettingsStore.addGlobalChangeListener((_, path) => {
|
||||
SettingsStore.plain.cloud.settingsSyncVersion = Date.now();
|
||||
localStorage.Vencord_settingsDirty = true;
|
||||
saveSettingsOnFrequentAction();
|
||||
VencordNative.settings.set(SettingsStore.plain, path);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,18 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { relaunch } from "@utils/native";
|
||||
import { Alerts, OAuth2AuthorizeModal, UserStore } from "@webpack/common";
|
||||
|
||||
import { Logger } from "./Logger";
|
||||
import { openModal } from "./modal";
|
||||
import { relaunch } from "./native";
|
||||
|
||||
export const cloudLogger = new Logger("Cloud", "#39b7e0");
|
||||
export const logger = new Logger("SettingsSync:CloudSetup", "#39b7e0");
|
||||
|
||||
export const getCloudUrl = () => new URL(Settings.cloud.url);
|
||||
const getCloudUrlOrigin = () => getCloudUrl().origin;
|
||||
|
|
@ -137,7 +124,7 @@ export async function authorizeCloud() {
|
|||
});
|
||||
const { secret } = await res.json();
|
||||
if (secret) {
|
||||
cloudLogger.info("Authorized with secret");
|
||||
logger.info("Authorized with secret");
|
||||
await setAuthorization(secret);
|
||||
showNotification({
|
||||
title: "Cloud Integration",
|
||||
|
|
@ -152,7 +139,7 @@ export async function authorizeCloud() {
|
|||
Settings.cloud.authenticated = false;
|
||||
}
|
||||
} catch (e: any) {
|
||||
cloudLogger.error("Failed to authorize", e);
|
||||
logger.error("Failed to authorize", e);
|
||||
showNotification({
|
||||
title: "Cloud Integration",
|
||||
body: `Setup failed (${e.toString()}).`
|
||||
|
|
@ -1,116 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { PlainSettings, Settings } from "@api/Settings";
|
||||
import { moment, Toasts } from "@webpack/common";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { relaunch } from "@utils/native";
|
||||
import { deflateSync, inflateSync } from "fflate";
|
||||
|
||||
import { checkCloudUrlCsp, getCloudAuth, getCloudUrl } from "./cloud";
|
||||
import { Logger } from "./Logger";
|
||||
import { relaunch } from "./native";
|
||||
import { chooseFile, saveFile } from "./web";
|
||||
import { checkCloudUrlCsp, deauthorizeCloud, getCloudAuth, getCloudUrl } from "./cloudSetup";
|
||||
import { exportSettings, importSettings } from "./offline";
|
||||
|
||||
export async function importSettings(data: string) {
|
||||
try {
|
||||
var parsed = JSON.parse(data);
|
||||
} catch (err) {
|
||||
console.log(data);
|
||||
throw new Error("Failed to parse JSON: " + String(err));
|
||||
}
|
||||
|
||||
if ("settings" in parsed && "quickCss" in parsed) {
|
||||
Object.assign(PlainSettings, parsed.settings);
|
||||
await VencordNative.settings.set(parsed.settings);
|
||||
await VencordNative.quickCss.set(parsed.quickCss);
|
||||
} else
|
||||
throw new Error("Invalid Settings. Is this even a Vencord Settings file?");
|
||||
}
|
||||
|
||||
export async function exportSettings({ minify }: { minify?: boolean; } = {}) {
|
||||
const settings = VencordNative.settings.get();
|
||||
const quickCss = await VencordNative.quickCss.get();
|
||||
return JSON.stringify({ settings, quickCss }, null, minify ? undefined : 4);
|
||||
}
|
||||
|
||||
export async function downloadSettingsBackup() {
|
||||
const filename = `vencord-settings-backup-${moment().format("YYYY-MM-DD")}.json`;
|
||||
const backup = await exportSettings();
|
||||
const data = new TextEncoder().encode(backup);
|
||||
|
||||
if (IS_DISCORD_DESKTOP) {
|
||||
DiscordNative.fileManager.saveWithDialog(data, filename);
|
||||
} else {
|
||||
saveFile(new File([data], filename, { type: "application/json" }));
|
||||
}
|
||||
}
|
||||
|
||||
const toast = (type: string, message: string) =>
|
||||
Toasts.show({
|
||||
type,
|
||||
message,
|
||||
id: Toasts.genId()
|
||||
});
|
||||
|
||||
const toastSuccess = () =>
|
||||
toast(Toasts.Type.SUCCESS, "Settings successfully imported. Restart to apply changes!");
|
||||
|
||||
const toastFailure = (err: any) =>
|
||||
toast(Toasts.Type.FAILURE, `Failed to import settings: ${String(err)}`);
|
||||
|
||||
export async function uploadSettingsBackup(showToast = true): Promise<void> {
|
||||
if (IS_DISCORD_DESKTOP) {
|
||||
const [file] = await DiscordNative.fileManager.openFiles({
|
||||
filters: [
|
||||
{ name: "Vencord Settings Backup", extensions: ["json"] },
|
||||
{ name: "all", extensions: ["*"] }
|
||||
]
|
||||
});
|
||||
|
||||
if (file) {
|
||||
try {
|
||||
await importSettings(new TextDecoder().decode(file.data));
|
||||
if (showToast) toastSuccess();
|
||||
} catch (err) {
|
||||
new Logger("SettingsSync").error(err);
|
||||
if (showToast) toastFailure(err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const file = await chooseFile("application/json");
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = async () => {
|
||||
try {
|
||||
await importSettings(reader.result as string);
|
||||
if (showToast) toastSuccess();
|
||||
} catch (err) {
|
||||
new Logger("SettingsSync").error(err);
|
||||
if (showToast) toastFailure(err);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}
|
||||
|
||||
// Cloud settings
|
||||
const cloudSettingsLogger = new Logger("Cloud:Settings", "#39b7e0");
|
||||
const logger = new Logger("SettingsSync:Cloud", "#39b7e0");
|
||||
|
||||
export async function putCloudSettings(manual?: boolean) {
|
||||
const settings = await exportSettings({ minify: true });
|
||||
|
|
@ -124,11 +27,11 @@ export async function putCloudSettings(manual?: boolean) {
|
|||
Authorization: await getCloudAuth(),
|
||||
"Content-Type": "application/octet-stream"
|
||||
},
|
||||
body: deflateSync(new TextEncoder().encode(settings))
|
||||
body: deflateSync(new TextEncoder().encode(settings)) as Uint8Array<ArrayBuffer>
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
cloudSettingsLogger.error(`Failed to sync up, API returned ${res.status}`);
|
||||
logger.error(`Failed to sync up, API returned ${res.status}`);
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
body: `Could not synchronize settings to cloud (API returned ${res.status}).`,
|
||||
|
|
@ -141,7 +44,7 @@ export async function putCloudSettings(manual?: boolean) {
|
|||
PlainSettings.cloud.settingsSyncVersion = written;
|
||||
VencordNative.settings.set(PlainSettings);
|
||||
|
||||
cloudSettingsLogger.info("Settings uploaded to cloud successfully");
|
||||
logger.info("Settings uploaded to cloud successfully");
|
||||
|
||||
if (manual) {
|
||||
showNotification({
|
||||
|
|
@ -151,7 +54,7 @@ export async function putCloudSettings(manual?: boolean) {
|
|||
});
|
||||
}
|
||||
} catch (e: any) {
|
||||
cloudSettingsLogger.error("Failed to sync up", e);
|
||||
logger.error("Failed to sync up", e);
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
body: `Could not synchronize settings to the cloud (${e.toString()}).`,
|
||||
|
|
@ -174,7 +77,7 @@ export async function getCloudSettings(shouldNotify = true, force = false) {
|
|||
});
|
||||
|
||||
if (res.status === 404) {
|
||||
cloudSettingsLogger.info("No settings on the cloud");
|
||||
logger.info("No settings on the cloud");
|
||||
if (shouldNotify)
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
|
|
@ -185,7 +88,7 @@ export async function getCloudSettings(shouldNotify = true, force = false) {
|
|||
}
|
||||
|
||||
if (res.status === 304) {
|
||||
cloudSettingsLogger.info("Settings up to date");
|
||||
logger.info("Settings up to date");
|
||||
if (shouldNotify)
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
|
|
@ -196,7 +99,7 @@ export async function getCloudSettings(shouldNotify = true, force = false) {
|
|||
}
|
||||
|
||||
if (!res.ok) {
|
||||
cloudSettingsLogger.error(`Failed to sync down, API returned ${res.status}`);
|
||||
logger.error(`Failed to sync down, API returned ${res.status}`);
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
body: `Could not synchronize settings from the cloud (API returned ${res.status}).`,
|
||||
|
|
@ -228,7 +131,7 @@ export async function getCloudSettings(shouldNotify = true, force = false) {
|
|||
PlainSettings.cloud.settingsSyncVersion = written;
|
||||
VencordNative.settings.set(PlainSettings);
|
||||
|
||||
cloudSettingsLogger.info("Settings loaded from cloud successfully");
|
||||
logger.info("Settings loaded from cloud successfully");
|
||||
if (shouldNotify)
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
|
|
@ -240,7 +143,7 @@ export async function getCloudSettings(shouldNotify = true, force = false) {
|
|||
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
cloudSettingsLogger.error("Failed to sync down", e);
|
||||
logger.error("Failed to sync down", e);
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
body: `Could not synchronize settings from the cloud (${e.toString()}).`,
|
||||
|
|
@ -261,7 +164,7 @@ export async function deleteCloudSettings() {
|
|||
});
|
||||
|
||||
if (!res.ok) {
|
||||
cloudSettingsLogger.error(`Failed to delete, API returned ${res.status}`);
|
||||
logger.error(`Failed to delete, API returned ${res.status}`);
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
body: `Could not delete settings (API returned ${res.status}).`,
|
||||
|
|
@ -270,14 +173,14 @@ export async function deleteCloudSettings() {
|
|||
return;
|
||||
}
|
||||
|
||||
cloudSettingsLogger.info("Settings deleted from cloud successfully");
|
||||
logger.info("Settings deleted from cloud successfully");
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
body: "Settings deleted from cloud!",
|
||||
color: "var(--green-360)"
|
||||
});
|
||||
} catch (e: any) {
|
||||
cloudSettingsLogger.error("Failed to delete", e);
|
||||
logger.error("Failed to delete", e);
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
body: `Could not delete settings (${e.toString()}).`,
|
||||
|
|
@ -285,3 +188,31 @@ export async function deleteCloudSettings() {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function eraseAllCloudData() {
|
||||
if (!await checkCloudUrlCsp()) return;
|
||||
|
||||
const res = await fetch(new URL("/v1/", getCloudUrl()), {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: await getCloudAuth() }
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
logger.error(`Failed to erase data, API returned ${res.status}`);
|
||||
showNotification({
|
||||
title: "Cloud Integrations",
|
||||
body: `Could not erase all data (API returned ${res.status}), please contact support.`,
|
||||
color: "var(--red-360)"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Settings.cloud.authenticated = false;
|
||||
await deauthorizeCloud();
|
||||
|
||||
showNotification({
|
||||
title: "Cloud Integrations",
|
||||
body: "Successfully erased all data.",
|
||||
color: "var(--green-360)"
|
||||
});
|
||||
}
|
||||
95
src/api/SettingsSync/offline.ts
Normal file
95
src/api/SettingsSync/offline.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { PlainSettings } from "@api/Settings";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { chooseFile, saveFile } from "@utils/web";
|
||||
import { moment, Toasts } from "@webpack/common";
|
||||
|
||||
const toast = (type: string, message: string) =>
|
||||
Toasts.show({
|
||||
type,
|
||||
message,
|
||||
id: Toasts.genId()
|
||||
});
|
||||
|
||||
const toastSuccess = () =>
|
||||
toast(Toasts.Type.SUCCESS, "Settings successfully imported. Restart to apply changes!");
|
||||
|
||||
const toastFailure = (err: any) =>
|
||||
toast(Toasts.Type.FAILURE, `Failed to import settings: ${String(err)}`);
|
||||
|
||||
const logger = new Logger("SettingsSync:Offline", "#39b7e0");
|
||||
|
||||
export async function importSettings(data: string) {
|
||||
try {
|
||||
var parsed = JSON.parse(data);
|
||||
} catch (err) {
|
||||
console.log(data);
|
||||
throw new Error("Failed to parse JSON: " + String(err));
|
||||
}
|
||||
|
||||
if ("settings" in parsed && "quickCss" in parsed) {
|
||||
Object.assign(PlainSettings, parsed.settings);
|
||||
await VencordNative.settings.set(parsed.settings);
|
||||
await VencordNative.quickCss.set(parsed.quickCss);
|
||||
} else
|
||||
throw new Error("Invalid Settings. Is this even a Vencord Settings file?");
|
||||
}
|
||||
|
||||
export async function exportSettings({ minify }: { minify?: boolean; } = {}) {
|
||||
const settings = VencordNative.settings.get();
|
||||
const quickCss = await VencordNative.quickCss.get();
|
||||
return JSON.stringify({ settings, quickCss }, null, minify ? undefined : 4);
|
||||
}
|
||||
|
||||
export async function downloadSettingsBackup() {
|
||||
const filename = `vencord-settings-backup-${moment().format("YYYY-MM-DD")}.json`;
|
||||
const backup = await exportSettings();
|
||||
const data = new TextEncoder().encode(backup);
|
||||
|
||||
if (IS_DISCORD_DESKTOP) {
|
||||
DiscordNative.fileManager.saveWithDialog(data, filename);
|
||||
} else {
|
||||
saveFile(new File([data], filename, { type: "application/json" }));
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadSettingsBackup(showToast = true): Promise<void> {
|
||||
if (IS_DISCORD_DESKTOP) {
|
||||
const [file] = await DiscordNative.fileManager.openFiles({
|
||||
filters: [
|
||||
{ name: "Vencord Settings Backup", extensions: ["json"] },
|
||||
{ name: "all", extensions: ["*"] }
|
||||
]
|
||||
});
|
||||
|
||||
if (file) {
|
||||
try {
|
||||
await importSettings(new TextDecoder().decode(file.data));
|
||||
if (showToast) toastSuccess();
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
if (showToast) toastFailure(err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const file = await chooseFile("application/json");
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = async () => {
|
||||
try {
|
||||
await importSettings(reader.result as string);
|
||||
if (showToast) toastSuccess();
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
if (showToast) toastFailure(err);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,9 +17,8 @@
|
|||
*/
|
||||
|
||||
import { Settings, SettingsStore } from "@api/Settings";
|
||||
import { ThemeStore } from "@webpack/common";
|
||||
|
||||
import { createAndAppendStyle } from "./css";
|
||||
import { createAndAppendStyle } from "@utils/css";
|
||||
import { ThemeStore } from "@vencord/discord-types";
|
||||
|
||||
let style: HTMLStyleElement;
|
||||
let themesStyle: HTMLStyleElement;
|
||||
|
|
@ -54,6 +53,8 @@ async function initThemes() {
|
|||
|
||||
const { themeLinks, enabledThemes } = Settings;
|
||||
|
||||
const { ThemeStore } = require("@webpack/common/stores") as typeof import("@webpack/common/stores");
|
||||
|
||||
// "darker" and "midnight" both count as dark
|
||||
// This function is first called on DOMContentLoaded, so ThemeStore may not have been loaded yet
|
||||
const activeTheme = ThemeStore == null
|
||||
|
|
@ -102,16 +103,16 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
}
|
||||
}, { once: true });
|
||||
|
||||
export function initQuickCssThemeStore() {
|
||||
export function initQuickCssThemeStore(themeStore: ThemeStore) {
|
||||
if (IS_USERSCRIPT) return;
|
||||
|
||||
initThemes();
|
||||
|
||||
let currentTheme = ThemeStore.theme;
|
||||
ThemeStore.addChangeListener(() => {
|
||||
if (currentTheme === ThemeStore.theme) return;
|
||||
let currentTheme = themeStore.theme;
|
||||
themeStore.addChangeListener(() => {
|
||||
if (currentTheme === themeStore.theme) return;
|
||||
|
||||
currentTheme = ThemeStore.theme;
|
||||
currentTheme = themeStore.theme;
|
||||
initThemes();
|
||||
});
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@ import { proxyLazy } from "@utils/lazy";
|
|||
import { Logger } from "@utils/Logger";
|
||||
import { findModuleId, proxyLazyWebpack, wreq } from "@webpack";
|
||||
|
||||
import { isPluginEnabled } from "./PluginManager";
|
||||
|
||||
interface UserSettingDefinition<T> {
|
||||
/**
|
||||
* Get the setting value
|
||||
|
|
@ -45,7 +47,7 @@ interface UserSettingDefinition<T> {
|
|||
|
||||
export const UserSettings: Record<PropertyKey, UserSettingDefinition<any>> | undefined = proxyLazyWebpack(() => {
|
||||
const modId = findModuleId('"textAndImages","renderSpoilers"');
|
||||
if (modId == null) return new Logger("UserSettingsAPI ").error("Didn't find settings module.");
|
||||
if (modId == null) return new Logger("UserSettingsAPI").error("Didn't find settings module.");
|
||||
|
||||
return wreq(modId as any);
|
||||
});
|
||||
|
|
@ -57,7 +59,7 @@ export const UserSettings: Record<PropertyKey, UserSettingDefinition<any>> | und
|
|||
* @param name The name of the setting
|
||||
*/
|
||||
export function getUserSetting<T = any>(group: string, name: string): UserSettingDefinition<T> | undefined {
|
||||
if (!Vencord.Plugins.isPluginEnabled("UserSettingsAPI")) throw new Error("Cannot use UserSettingsAPI without setting as dependency.");
|
||||
if (!isPluginEnabled("UserSettingsAPI")) throw new Error("Cannot use UserSettingsAPI without setting it as a dependency.");
|
||||
|
||||
for (const key in UserSettings) {
|
||||
const userSetting = UserSettings[key];
|
||||
|
|
|
|||
|
|
@ -29,9 +29,11 @@ import * as $MessagePopover from "./MessagePopover";
|
|||
import * as $MessageUpdater from "./MessageUpdater";
|
||||
import * as $Notices from "./Notices";
|
||||
import * as $Notifications from "./Notifications";
|
||||
export * as PluginManager from "./PluginManager";
|
||||
import * as $ServerList from "./ServerList";
|
||||
import * as $Settings from "./Settings";
|
||||
import * as $Styles from "./Styles";
|
||||
import * as $Themes from "./Themes";
|
||||
import * as $UserSettings from "./UserSettings";
|
||||
|
||||
/**
|
||||
|
|
@ -122,3 +124,8 @@ export const MessageUpdater = $MessageUpdater;
|
|||
* An API allowing you to get an user setting
|
||||
*/
|
||||
export const UserSettings = $UserSettings;
|
||||
|
||||
/**
|
||||
* Don't use this
|
||||
*/
|
||||
export const Themes = $Themes;
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ import { Flex } from "@components/Flex";
|
|||
import { HeadingTertiary } from "@components/Heading";
|
||||
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
||||
import { debounce } from "@shared/debounce";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { stripIndent } from "@utils/text";
|
||||
import { ReplaceFn } from "@utils/types";
|
||||
import { search } from "@webpack";
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
*/
|
||||
|
||||
import { showNotice } from "@api/Notices";
|
||||
import { isPluginEnabled, startDependenciesRecursive, startPlugin, stopPlugin } from "@api/PluginManager";
|
||||
import { CogWheel, InfoIcon } from "@components/Icons";
|
||||
import { AddonCard } from "@components/settings/AddonCard";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { isObjectEmpty } from "@utils/misc";
|
||||
import { Plugin } from "@utils/types";
|
||||
import { React, showToast, Toasts } from "@webpack/common";
|
||||
|
|
@ -16,9 +16,6 @@ import { Settings } from "Vencord";
|
|||
import { cl, logger } from ".";
|
||||
import { openPluginModal } from "./PluginModal";
|
||||
|
||||
// Avoid circular dependency
|
||||
const { startDependenciesRecursive, startPlugin, stopPlugin, isPluginEnabled } = proxyLazy(() => require("plugins") as typeof import("plugins"));
|
||||
|
||||
interface PluginCardProps extends React.HTMLProps<HTMLDivElement> {
|
||||
plugin: Plugin;
|
||||
disabled: boolean;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
import "./styles.css";
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { useSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Divider } from "@components/Divider";
|
||||
|
|
@ -157,7 +158,7 @@ function PluginSettings() {
|
|||
|
||||
const pluginFilter = (plugin: typeof Plugins[keyof typeof Plugins]) => {
|
||||
const { status } = searchValue;
|
||||
const enabled = Vencord.Plugins.isPluginEnabled(plugin.name);
|
||||
const enabled = isPluginEnabled(plugin.name);
|
||||
|
||||
switch (status) {
|
||||
case SearchStatus.DISABLED:
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { downloadSettingsBackup, uploadSettingsBackup } from "@api/SettingsSync/offline";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes } from "@utils/misc";
|
||||
import { downloadSettingsBackup, uploadSettingsBackup } from "@utils/settingsSync";
|
||||
import { Button, Card, Text } from "@webpack/common";
|
||||
|
||||
function BackupAndRestoreTab() {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { Settings, useSettings } from "@api/Settings";
|
||||
import { useSettings } from "@api/Settings";
|
||||
import { authorizeCloud, deauthorizeCloud } from "@api/SettingsSync/cloudSetup";
|
||||
import { deleteCloudSettings, eraseAllCloudData, getCloudSettings, putCloudSettings } from "@api/SettingsSync/cloudSync";
|
||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||
import { Divider } from "@components/Divider";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
|
|
@ -25,9 +26,7 @@ import { Grid } from "@components/Grid";
|
|||
import { Link } from "@components/Link";
|
||||
import { Paragraph } from "@components/Paragraph";
|
||||
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
||||
import { authorizeCloud, checkCloudUrlCsp, cloudLogger, deauthorizeCloud, getCloudAuth, getCloudUrl } from "@utils/cloud";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { deleteCloudSettings, getCloudSettings, putCloudSettings } from "@utils/settingsSync";
|
||||
import { Alerts, Button, Forms, Tooltip } from "@webpack/common";
|
||||
|
||||
function validateUrl(url: string) {
|
||||
|
|
@ -39,34 +38,6 @@ function validateUrl(url: string) {
|
|||
}
|
||||
}
|
||||
|
||||
async function eraseAllData() {
|
||||
if (!await checkCloudUrlCsp()) return;
|
||||
|
||||
const res = await fetch(new URL("/v1/", getCloudUrl()), {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: await getCloudAuth() }
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
cloudLogger.error(`Failed to erase data, API returned ${res.status}`);
|
||||
showNotification({
|
||||
title: "Cloud Integrations",
|
||||
body: `Could not erase all data (API returned ${res.status}), please contact support.`,
|
||||
color: "var(--red-360)"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Settings.cloud.authenticated = false;
|
||||
await deauthorizeCloud();
|
||||
|
||||
showNotification({
|
||||
title: "Cloud Integrations",
|
||||
body: "Successfully erased all data.",
|
||||
color: "var(--green-360)"
|
||||
});
|
||||
}
|
||||
|
||||
function SettingsSyncSection() {
|
||||
const { cloud } = useSettings(["cloud.authenticated", "cloud.settingsSync"]);
|
||||
const sectionEnabled = cloud.authenticated && cloud.settingsSync;
|
||||
|
|
@ -181,7 +152,7 @@ function CloudTab() {
|
|||
onClick={() => Alerts.show({
|
||||
title: "Are you sure?",
|
||||
body: "Once your data is erased, we cannot recover it. There's no going back!",
|
||||
onConfirm: eraseAllData,
|
||||
onConfirm: eraseAllCloudData,
|
||||
confirmText: "Erase it!",
|
||||
confirmColor: "vc-cloud-erase-data-danger-btn",
|
||||
cancelText: "Nevermind"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { Settings, useSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { FolderIcon, PaintbrushIcon, PencilIcon, PlusIcon, RestartIcon } from "@components/Icons";
|
||||
|
|
@ -11,9 +12,9 @@ import { Link } from "@components/Link";
|
|||
import { QuickAction, QuickActionCard } from "@components/settings/QuickAction";
|
||||
import { openPluginModal } from "@components/settings/tabs/plugins/PluginModal";
|
||||
import { UserThemeHeader } from "@main/themes";
|
||||
import ClientThemePlugin from "@plugins/clientTheme";
|
||||
import { findLazy } from "@webpack";
|
||||
import { Card, Forms, useEffect, useRef, useState } from "@webpack/common";
|
||||
import ClientThemePlugin from "plugins/clientTheme";
|
||||
import type { ComponentType, Ref, SyntheticEvent } from "react";
|
||||
|
||||
import { ThemeCard } from "./ThemeCard";
|
||||
|
|
@ -140,7 +141,7 @@ export function LocalThemesTab() {
|
|||
Icon={PaintbrushIcon}
|
||||
/>
|
||||
|
||||
{Vencord.Plugins.isPluginEnabled(ClientThemePlugin.name) && (
|
||||
{isPluginEnabled(ClientThemePlugin.name) && (
|
||||
<QuickAction
|
||||
text="Edit ClientTheme"
|
||||
action={() => openPluginModal(ClientThemePlugin)}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
*/
|
||||
|
||||
import DonateButton from "@components/settings/DonateButton";
|
||||
import BadgeAPI from "@plugins/_api/badges";
|
||||
import { DONOR_ROLE_ID, VENCORD_GUILD_ID } from "@utils/constants";
|
||||
import { Button, GuildMemberStore } from "@webpack/common";
|
||||
import BadgeAPI from "plugins/_api/badges";
|
||||
|
||||
export const isDonor = (userId: string) => !!(
|
||||
BadgeAPI.getDonorBadges(userId)?.length > 0
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
|||
import { useSettings } from "@api/Settings";
|
||||
import { Divider } from "@components/Divider";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { FolderIcon, GithubIcon, LogIcon, PaintbrushIcon, RestartIcon } from "@components/index";
|
||||
import { FolderIcon, GithubIcon, LogIcon, PaintbrushIcon, RestartIcon } from "@components/Icons";
|
||||
import { QuickAction, QuickActionCard } from "@components/settings/QuickAction";
|
||||
import { SpecialCard } from "@components/settings/SpecialCard";
|
||||
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addPatch } from "@api/PluginManager";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import * as Webpack from "@webpack";
|
||||
import { getBuildNumber, patchTimings } from "@webpack/patcher";
|
||||
import { getBuildNumber, patches, patchTimings } from "@webpack/patcher";
|
||||
|
||||
import { addPatch, patches } from "../plugins";
|
||||
import { loadLazyChunks } from "./loadLazyChunks";
|
||||
|
||||
async function runReporter() {
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@ import { Heart } from "@components/Heart";
|
|||
import DonateButton from "@components/settings/DonateButton";
|
||||
import { openContributorModal } from "@components/settings/tabs";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { copyWithToast, shouldShowContributorBadge } from "@utils/misc";
|
||||
import { shouldShowContributorBadge } from "@utils/misc";
|
||||
import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
||||
import definePlugin from "@utils/types";
|
||||
import { User } from "@vencord/discord-types";
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { getUserSettingLazy } from "@api/UserSettings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
|
|
@ -95,7 +96,6 @@ async function generateDebugInfoMessage() {
|
|||
}
|
||||
|
||||
const commonIssues = {
|
||||
"NoRPC enabled": Vencord.Plugins.isPluginEnabled("NoRPC"),
|
||||
"Activity Sharing disabled": tryOrElse(() => !ShowCurrentGame.getSetting(), false),
|
||||
"Vencord DevBuild": !IS_STANDALONE,
|
||||
"Has UserPlugins": Object.values(PluginMeta).some(m => m.userPlugin),
|
||||
|
|
@ -114,7 +114,7 @@ function generatePluginList() {
|
|||
const isApiPlugin = (plugin: string) => plugin.endsWith("API") || plugins[plugin].required;
|
||||
|
||||
const enabledPlugins = Object.keys(plugins)
|
||||
.filter(p => Vencord.Plugins.isPluginEnabled(p) && !isApiPlugin(p));
|
||||
.filter(p => isPluginEnabled(p) && !isApiPlugin(p));
|
||||
|
||||
const enabledStockPlugins = enabledPlugins.filter(p => !PluginMeta[p].userPlugin);
|
||||
const enabledUserPlugins = enabledPlugins.filter(p => PluginMeta[p].userPlugin);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
*/
|
||||
|
||||
import { Button } from "@components/Button";
|
||||
import { SessionInfo } from "@plugins/betterSessions/types";
|
||||
import { openModal } from "@utils/modal";
|
||||
|
||||
import { SessionInfo } from "../types";
|
||||
import { RenameModal } from "./RenameModal";
|
||||
|
||||
export function RenameButton({ session, state }: { session: SessionInfo["session"], state: [string, React.Dispatch<React.SetStateAction<string>>]; }) {
|
||||
|
|
|
|||
|
|
@ -16,13 +16,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SessionInfo } from "@plugins/betterSessions/types";
|
||||
import { getDefaultName, savedSessionsCache, saveSessionsToDataStore } from "@plugins/betterSessions/utils";
|
||||
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
|
||||
import { Button, Forms, React, TextInput } from "@webpack/common";
|
||||
import { KeyboardEvent } from "react";
|
||||
|
||||
import { SessionInfo } from "../types";
|
||||
import { getDefaultName, savedSessionsCache, saveSessionsToDataStore } from "../utils";
|
||||
|
||||
export function RenameModal({ props, session, state }: { props: ModalProps, session: SessionInfo["session"], state: [string, React.Dispatch<React.SetStateAction<string>>]; }) {
|
||||
const [title, setTitle] = state;
|
||||
const [value, setValue] = React.useState(savedSessionsCache.get(session.id_hash)?.name ?? "");
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { UserStore } from "@webpack/common";
|
||||
|
||||
import { ChromeIcon, DiscordIcon, EdgeIcon, FirefoxIcon, IEIcon, MobileIcon, OperaIcon, SafariIcon, UnknownIcon } from "./components/icons";
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { openPluginModal } from "@components/settings/tabs";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { isObjectEmpty } from "@utils/misc";
|
||||
|
|
@ -28,7 +29,7 @@ export default function PluginsSubmenu() {
|
|||
|
||||
const search = query.toLowerCase();
|
||||
const include = (p: typeof Plugins[keyof typeof Plugins]) => (
|
||||
Vencord.Plugins.isPluginEnabled(p.name)
|
||||
isPluginEnabled(p.name)
|
||||
&& p.options && !isObjectEmpty(p.options)
|
||||
&& (
|
||||
p.name.toLowerCase().includes(search)
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { ErrorCard } from "@components/ErrorCard";
|
||||
import { relativeLuminance } from "@plugins/clientTheme/utils/colorUtils";
|
||||
import { createOrUpdateThemeColorVars } from "@plugins/clientTheme/utils/styleUtils";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
||||
import { Button, ColorPicker, Forms, ThemeStore, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { settings } from "..";
|
||||
import { relativeLuminance } from "../utils/colorUtils";
|
||||
import { createOrUpdateThemeColorVars } from "../utils/styleUtils";
|
||||
|
||||
const saveClientTheme = findByCodeLazy('type:"UNSYNCED_USER_SETTINGS_UPDATE', '"system"===');
|
||||
const NitroThemeStore = findStoreLazy("ClientThemesBackgroundStore");
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ function makeShortcuts() {
|
|||
openModal: { getter: () => ModalAPI.openModal },
|
||||
openModalLazy: { getter: () => ModalAPI.openModalLazy },
|
||||
|
||||
Stores: Webpack.fluxStores,
|
||||
Stores: { getter: () => Object.fromEntries(Webpack.fluxStores) },
|
||||
|
||||
// e.g. "2024-05_desktop_visual_refresh", 0
|
||||
setExperiment: (id: string, bucket: number) => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { Menu } from "@webpack/common";
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import "./style.css";
|
|||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { CopyIcon, NoEntrySignIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Tooltip, useState } from "@webpack/common";
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,13 @@
|
|||
*/
|
||||
|
||||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import ExpressionClonerPlugin from "@plugins/expressionCloner";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Message, Sticker } from "@vencord/discord-types";
|
||||
import { Menu, React, StickersStore } from "@webpack/common";
|
||||
import ExpressionClonerPlugin from "plugins/expressionCloner";
|
||||
|
||||
const StickerExt = [, "png", "png", "json", "gif"] as const;
|
||||
|
||||
|
|
@ -79,7 +80,7 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t
|
|||
|
||||
const sticker = StickersStore.getStickerById(id);
|
||||
if (sticker) {
|
||||
children.push(buildMenuItem(sticker, Vencord.Plugins.isPluginEnabled(ExpressionClonerPlugin.name)));
|
||||
children.push(buildMenuItem(sticker, isPluginEnabled(ExpressionClonerPlugin.name)));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Notices } from "@api/index";
|
||||
import { currentNotice, noticesQueue, popNotice, showNotice } from "@api/Notices";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { makeRange, OptionType } from "@utils/types";
|
||||
|
|
@ -62,12 +62,12 @@ export default definePlugin({
|
|||
|
||||
const backOnlineMessage = "Welcome back! Click the button to go online. Click the X to stay idle until reload.";
|
||||
if (
|
||||
Notices.currentNotice?.[1] === backOnlineMessage ||
|
||||
Notices.noticesQueue.some(([, noticeMessage]) => noticeMessage === backOnlineMessage)
|
||||
currentNotice?.[1] === backOnlineMessage ||
|
||||
noticesQueue.some(([, noticeMessage]) => noticeMessage === backOnlineMessage)
|
||||
) return;
|
||||
|
||||
Notices.showNotice(backOnlineMessage, "Exit idle", () => {
|
||||
Notices.popNotice();
|
||||
showNotice(backOnlineMessage, "Exit idle", () => {
|
||||
popNotice();
|
||||
FluxDispatcher.dispatch({
|
||||
type: "IDLE",
|
||||
idle: false
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import "./settings.css";
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Divider } from "@components/Divider";
|
||||
import { Heading } from "@components/Heading";
|
||||
|
|
@ -14,7 +15,7 @@ import { debounce } from "@shared/debounce";
|
|||
import { ActivityType } from "@vencord/discord-types/enums";
|
||||
import { Select, Text, TextInput, useState } from "@webpack/common";
|
||||
|
||||
import { setRpc, settings, TimestampMode } from ".";
|
||||
import CustomRPCPlugin, { setRpc, settings, TimestampMode } from ".";
|
||||
|
||||
const cl = classNameFactory("vc-customRPC-settings-");
|
||||
|
||||
|
|
@ -50,7 +51,7 @@ function isAppIdValid(value: string) {
|
|||
|
||||
const updateRPC = debounce(() => {
|
||||
setRpc(true);
|
||||
if (Vencord.Plugins.isPluginEnabled("CustomRPC")) setRpc();
|
||||
if (isPluginEnabled(CustomRPCPlugin.name)) setRpc();
|
||||
});
|
||||
|
||||
function isStreamLinkDisabled() {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { AUTHORIZE_URL, CLIENT_ID } from "@plugins/decor/lib/constants";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { OAuth2AuthorizeModal, showToast, Toasts, UserStore, zustandCreate, zustandPersist } from "@webpack/common";
|
||||
|
||||
import { AUTHORIZE_URL, CLIENT_ID } from "../constants";
|
||||
|
||||
interface AuthorizationState {
|
||||
token: string | null;
|
||||
tokens: Record<string, string>;
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Decoration, deleteDecoration, getUserDecoration, getUserDecorations, NewDecoration, setUserDecoration } from "@plugins/decor/lib/api";
|
||||
import { decorationToAsset } from "@plugins/decor/lib/utils/decoration";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { UserStore, zustandCreate } from "@webpack/common";
|
||||
|
||||
import { Decoration, deleteDecoration, getUserDecoration, getUserDecorations, NewDecoration, setUserDecoration } from "../api";
|
||||
import { decorationToAsset } from "../utils/decoration";
|
||||
import { useUsersDecorationsStore } from "./UsersDecorationsStore";
|
||||
|
||||
interface UserDecorationsState {
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { AvatarDecoration } from "@plugins/decor";
|
||||
import { getUsersDecorations } from "@plugins/decor/lib/api";
|
||||
import { DECORATION_FETCH_COOLDOWN, SKU_ID } from "@plugins/decor/lib/constants";
|
||||
import { debounce } from "@shared/debounce";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { User } from "@vencord/discord-types";
|
||||
import { useEffect, useState, zustandCreate } from "@webpack/common";
|
||||
|
||||
import { AvatarDecoration } from "../../";
|
||||
import { getUsersDecorations } from "../api";
|
||||
import { DECORATION_FETCH_COOLDOWN, SKU_ID } from "../constants";
|
||||
|
||||
interface UserDecorationData {
|
||||
asset: string | null;
|
||||
fetchedAt: Date;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { AvatarDecoration } from "../../";
|
||||
import { Decoration } from "../api";
|
||||
import { SKU_ID } from "../constants";
|
||||
import { AvatarDecoration } from "@plugins/decor";
|
||||
import { Decoration } from "@plugins/decor/lib/api";
|
||||
import { SKU_ID } from "@plugins/decor/lib/constants";
|
||||
|
||||
export function decorationToAsset(decoration: Decoration) {
|
||||
return `${decoration.animated ? "a_" : ""}${decoration.hash}`;
|
||||
|
|
|
|||
|
|
@ -12,13 +12,14 @@ import { closeAllModals } from "@utils/modal";
|
|||
import { OptionType } from "@utils/types";
|
||||
import { FluxDispatcher, Forms } from "@webpack/common";
|
||||
|
||||
import DecorPlugin from ".";
|
||||
import DecorSection from "./ui/components/DecorSection";
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
changeDecoration: {
|
||||
type: OptionType.COMPONENT,
|
||||
component() {
|
||||
if (!Vencord.Plugins.plugins.Decor.started) return <Forms.FormText>
|
||||
if (!DecorPlugin.started) return <Forms.FormText>
|
||||
Enable Decor and restart your client to change your avatar decoration.
|
||||
</Forms.FormText>;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Decoration } from "@plugins/decor/lib/api";
|
||||
import { decorationToAvatarDecoration } from "@plugins/decor/lib/utils/decoration";
|
||||
import { ContextMenuApi } from "@webpack/common";
|
||||
import type { HTMLProps } from "react";
|
||||
|
||||
import { Decoration } from "../../lib/api";
|
||||
import { decorationToAvatarDecoration } from "../../lib/utils/decoration";
|
||||
import { DecorationGridDecoration } from ".";
|
||||
import DecorationContextMenu from "./DecorationContextMenu";
|
||||
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@
|
|||
|
||||
import { Button } from "@components/Button";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { useAuthorizationStore } from "@plugins/decor/lib/stores/AuthorizationStore";
|
||||
import { useCurrentUserDecorationsStore } from "@plugins/decor/lib/stores/CurrentUserDecorationsStore";
|
||||
import { cl } from "@plugins/decor/ui";
|
||||
import { openChangeDecorationModal } from "@plugins/decor/ui/modals/ChangeDecorationModal";
|
||||
import { findComponentByCodeLazy } from "@webpack";
|
||||
import { useEffect } from "@webpack/common";
|
||||
|
||||
import { useAuthorizationStore } from "../../lib/stores/AuthorizationStore";
|
||||
import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDecorationsStore";
|
||||
import { cl } from "../";
|
||||
import { openChangeDecorationModal } from "../modals/ChangeDecorationModal";
|
||||
|
||||
const CustomizationSection = findComponentByCodeLazy(".customizationSectionBackground");
|
||||
|
||||
export interface DecorSectionProps {
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@
|
|||
*/
|
||||
|
||||
import { CopyIcon, DeleteIcon } from "@components/Icons";
|
||||
import { Decoration } from "@plugins/decor/lib/api";
|
||||
import { useCurrentUserDecorationsStore } from "@plugins/decor/lib/stores/CurrentUserDecorationsStore";
|
||||
import { cl } from "@plugins/decor/ui";
|
||||
import { copyToClipboard } from "@utils/clipboard";
|
||||
import { Alerts, ContextMenuApi, Menu, UserStore } from "@webpack/common";
|
||||
|
||||
import { Decoration } from "../../lib/api";
|
||||
import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDecorationsStore";
|
||||
import { cl } from "../";
|
||||
|
||||
export default function DecorationContextMenu({ decoration }: { decoration: Decoration; }) {
|
||||
const { delete: deleteDecoration } = useCurrentUserDecorationsStore();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { cl } from "@plugins/decor/ui";
|
||||
import { React } from "@webpack/common";
|
||||
import { JSX } from "react";
|
||||
|
||||
import { cl } from "../";
|
||||
|
||||
export interface GridProps<ItemT> {
|
||||
renderItem: (item: ItemT) => JSX.Element;
|
||||
getItemKey: (item: ItemT) => string;
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { cl } from "@plugins/decor/ui";
|
||||
import { classes } from "@utils/misc";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { React } from "@webpack/common";
|
||||
import { JSX } from "react";
|
||||
|
||||
import { cl } from "../";
|
||||
import Grid, { GridProps } from "./Grid";
|
||||
|
||||
const ScrollerClasses = findByPropsLazy("managedReactiveScroller");
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { AvatarDecoration } from "@plugins/decor";
|
||||
import { findComponentByCode, LazyComponentWebpack } from "@webpack";
|
||||
import { React } from "@webpack/common";
|
||||
import type { ComponentType, HTMLProps, PropsWithChildren } from "react";
|
||||
|
||||
import { AvatarDecoration } from "../..";
|
||||
|
||||
type DecorationGridItemComponent = ComponentType<PropsWithChildren<HTMLProps<HTMLDivElement>> & {
|
||||
onSelect: () => void,
|
||||
isSelected: boolean,
|
||||
|
|
|
|||
|
|
@ -7,26 +7,25 @@
|
|||
import { Button as NewButton } from "@components/Button";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { openInviteModal } from "@utils/discord";
|
||||
import { Decoration, getPresets, Preset } from "@plugins/decor/lib/api";
|
||||
import { GUILD_ID, INVITE_KEY } from "@plugins/decor/lib/constants";
|
||||
import { useAuthorizationStore } from "@plugins/decor/lib/stores/AuthorizationStore";
|
||||
import { useCurrentUserDecorationsStore } from "@plugins/decor/lib/stores/CurrentUserDecorationsStore";
|
||||
import { decorationToAvatarDecoration } from "@plugins/decor/lib/utils/decoration";
|
||||
import { settings } from "@plugins/decor/settings";
|
||||
import { cl, DecorationModalStyles, requireAvatarDecorationModal } from "@plugins/decor/ui";
|
||||
import { AvatarDecorationModalPreview } from "@plugins/decor/ui/components";
|
||||
import DecorationGridCreate from "@plugins/decor/ui/components/DecorationGridCreate";
|
||||
import DecorationGridNone from "@plugins/decor/ui/components/DecorationGridNone";
|
||||
import DecorDecorationGridDecoration from "@plugins/decor/ui/components/DecorDecorationGridDecoration";
|
||||
import SectionedGridList from "@plugins/decor/ui/components/SectionedGridList";
|
||||
import { copyWithToast, openInviteModal } from "@utils/discord";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { Queue } from "@utils/Queue";
|
||||
import { User } from "@vencord/discord-types";
|
||||
import { Alerts, Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Parser, Text, Tooltip, useEffect, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common";
|
||||
|
||||
import { Decoration, getPresets, Preset } from "../../lib/api";
|
||||
import { GUILD_ID, INVITE_KEY } from "../../lib/constants";
|
||||
import { useAuthorizationStore } from "../../lib/stores/AuthorizationStore";
|
||||
import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDecorationsStore";
|
||||
import { decorationToAvatarDecoration } from "../../lib/utils/decoration";
|
||||
import { settings } from "../../settings";
|
||||
import { cl, DecorationModalStyles, requireAvatarDecorationModal } from "../";
|
||||
import { AvatarDecorationModalPreview } from "../components";
|
||||
import DecorationGridCreate from "../components/DecorationGridCreate";
|
||||
import DecorationGridNone from "../components/DecorationGridNone";
|
||||
import DecorDecorationGridDecoration from "../components/DecorDecorationGridDecoration";
|
||||
import SectionedGridList from "../components/SectionedGridList";
|
||||
import { openCreateDecorationModal } from "./CreateDecorationModal";
|
||||
import { openGuidelinesModal } from "./GuidelinesModal";
|
||||
|
||||
|
|
|
|||
|
|
@ -6,17 +6,16 @@
|
|||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Link } from "@components/Link";
|
||||
import { GUILD_ID, INVITE_KEY, RAW_SKU_ID } from "@plugins/decor/lib/constants";
|
||||
import { useCurrentUserDecorationsStore } from "@plugins/decor/lib/stores/CurrentUserDecorationsStore";
|
||||
import { cl, DecorationModalStyles, requireAvatarDecorationModal, requireCreateStickerModal } from "@plugins/decor/ui";
|
||||
import { AvatarDecorationModalPreview } from "@plugins/decor/ui/components";
|
||||
import { openInviteModal } from "@utils/discord";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { filters, findComponentByCodeLazy, mapMangledModuleLazy } from "@webpack";
|
||||
import { Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Text, TextInput, useEffect, useMemo, UserStore, useState } from "@webpack/common";
|
||||
|
||||
import { GUILD_ID, INVITE_KEY, RAW_SKU_ID } from "../../lib/constants";
|
||||
import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDecorationsStore";
|
||||
import { cl, DecorationModalStyles, requireAvatarDecorationModal, requireCreateStickerModal } from "../";
|
||||
import { AvatarDecorationModalPreview } from "../components";
|
||||
|
||||
const FileUpload = findComponentByCodeLazy(".fileUpload),");
|
||||
|
||||
const { HelpMessage, HelpMessageTypes } = mapMangledModuleLazy('POSITIVE="positive', {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Link } from "@components/Link";
|
||||
import { settings } from "@plugins/decor/settings";
|
||||
import { cl, DecorationModalStyles, requireAvatarDecorationModal } from "@plugins/decor/ui";
|
||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { Button, Forms, Text } from "@webpack/common";
|
||||
|
||||
import { settings } from "../../settings";
|
||||
import { cl, DecorationModalStyles, requireAvatarDecorationModal } from "../";
|
||||
import { openCreateDecorationModal } from "./CreateDecorationModal";
|
||||
|
||||
function GuidelinesModal(props: ModalProps) {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
import { addMessagePreEditListener, addMessagePreSendListener, removeMessagePreEditListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { ApngBlendOp, ApngDisposeOp, parseAPNG } from "@utils/apng";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
||||
import { getCurrentGuild, getEmojiURL } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType, Patch } from "@utils/types";
|
||||
|
|
@ -706,9 +706,10 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
async sendAnimatedSticker(stickerLink: string, stickerId: string, channelId: string) {
|
||||
const { parseURL } = importApngJs();
|
||||
|
||||
const { frames, width, height } = await parseURL(stickerLink);
|
||||
const { frames, width, height } = await fetch(stickerLink)
|
||||
.then(res => res.arrayBuffer())
|
||||
.then(parseAPNG);
|
||||
|
||||
const gif = GIFEncoder();
|
||||
const resolution = settings.store.stickerSize;
|
||||
|
|
@ -757,7 +758,7 @@ export default definePlugin({
|
|||
|
||||
gif.finish();
|
||||
|
||||
const file = new File([gif.bytesView()], `${stickerId}.gif`, { type: "image/gif" });
|
||||
const file = new File([gif.bytesView() as Uint8Array<ArrayBuffer>], `${stickerId}.gif`, { type: "image/gif" });
|
||||
UploadHandler.promptToUpload([file], ChannelStore.getChannel(channelId), DraftType.ChannelMessage);
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -17,15 +17,15 @@
|
|||
*/
|
||||
|
||||
// This plugin is a port from Alyxia's Vendetta plugin
|
||||
import "./index.css";
|
||||
import "./styles.css";
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Divider } from "@components/Divider";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { fetchUserProfile } from "@utils/discord";
|
||||
import { copyWithToast, fetchUserProfile } from "@utils/discord";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes, copyWithToast } from "@utils/misc";
|
||||
import { classes } from "@utils/misc";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { User, UserProfile } from "@vencord/discord-types";
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@
|
|||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { settings } from "@plugins/imageZoom";
|
||||
import { ELEMENT_ID } from "@plugins/imageZoom/constants";
|
||||
import { waitFor } from "@plugins/imageZoom/utils/waitFor";
|
||||
import { FluxDispatcher, useLayoutEffect, useMemo, useRef, useState } from "@webpack/common";
|
||||
|
||||
import { ELEMENT_ID } from "../constants";
|
||||
import { settings } from "../index";
|
||||
import { waitFor } from "../utils/waitFor";
|
||||
|
||||
interface Vec2 {
|
||||
x: number,
|
||||
y: number;
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalRoot,
|
||||
openModal,
|
||||
} from "@utils/modal";
|
||||
import { Button, Forms, React, TextInput } from "@webpack/common";
|
||||
|
||||
import { decrypt } from "../index";
|
||||
|
||||
export function DecModal(props: any) {
|
||||
const encryptedMessage: string = props?.message?.content;
|
||||
const [password, setPassword] = React.useState("password");
|
||||
|
||||
return (
|
||||
<ModalRoot {...props}>
|
||||
<ModalHeader>
|
||||
<Forms.FormTitle tag="h4">Decrypt Message</Forms.FormTitle>
|
||||
</ModalHeader>
|
||||
|
||||
<ModalContent>
|
||||
<Forms.FormTitle tag="h5" style={{ marginTop: "10px" }}>Message with Encryption</Forms.FormTitle>
|
||||
<TextInput defaultValue={encryptedMessage} disabled={true}></TextInput>
|
||||
<Forms.FormTitle tag="h5" style={{ marginTop: "10px" }}>Password</Forms.FormTitle>
|
||||
<TextInput
|
||||
style={{ marginBottom: "20px" }}
|
||||
onChange={setPassword}
|
||||
/>
|
||||
</ModalContent>
|
||||
|
||||
<ModalFooter>
|
||||
<Button
|
||||
color={Button.Colors.GREEN}
|
||||
onClick={() => {
|
||||
const toSend = decrypt(encryptedMessage, password, true);
|
||||
if (!toSend || !props?.message) return;
|
||||
// @ts-expect-error
|
||||
Vencord.Plugins.plugins.InvisibleChat.buildEmbed(props?.message, toSend);
|
||||
props.onClose();
|
||||
}}>
|
||||
Decrypt
|
||||
</Button>
|
||||
<Button
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
look={Button.Looks.LINK}
|
||||
style={{ left: 15, position: "absolute" }}
|
||||
onClick={props.onClose}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export function buildDecModal(msg: any): any {
|
||||
openModal((props: any) => <DecModal {...props} {...msg} />);
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { insertTextIntoChatInputBox } from "@utils/discord";
|
||||
import {
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalProps,
|
||||
ModalRoot,
|
||||
openModal,
|
||||
} from "@utils/modal";
|
||||
import { Button, Forms, React, TextInput } from "@webpack/common";
|
||||
|
||||
import { encrypt } from "../index";
|
||||
|
||||
function EncModal(props: ModalProps) {
|
||||
const [secret, setSecret] = React.useState("");
|
||||
const [cover, setCover] = React.useState("");
|
||||
const [password, setPassword] = React.useState("password");
|
||||
const [noCover, setNoCover] = React.useState(false);
|
||||
|
||||
const isValid = secret && (noCover || (cover && cover.trim().split(" ").length > 1));
|
||||
|
||||
return (
|
||||
<ModalRoot {...props}>
|
||||
<ModalHeader>
|
||||
<Forms.FormTitle tag="h4">Encrypt Message</Forms.FormTitle>
|
||||
</ModalHeader>
|
||||
|
||||
<ModalContent>
|
||||
<Forms.FormTitle tag="h5" style={{ marginTop: "10px" }}>Secret</Forms.FormTitle>
|
||||
<TextInput
|
||||
onChange={(e: string) => {
|
||||
setSecret(e);
|
||||
}}
|
||||
/>
|
||||
<Forms.FormTitle tag="h5" style={{ marginTop: "10px" }}>Cover (2 or more Words!!)</Forms.FormTitle>
|
||||
<TextInput
|
||||
disabled={noCover}
|
||||
onChange={(e: string) => {
|
||||
setCover(e);
|
||||
}}
|
||||
/>
|
||||
<Forms.FormTitle tag="h5" style={{ marginTop: "10px" }}>Password</Forms.FormTitle>
|
||||
<TextInput
|
||||
style={{ marginBottom: "20px" }}
|
||||
defaultValue={"password"}
|
||||
onChange={(e: string) => {
|
||||
setPassword(e);
|
||||
}}
|
||||
/>
|
||||
<FormSwitch
|
||||
title="Don't use a Cover"
|
||||
value={noCover}
|
||||
onChange={(e: boolean) => {
|
||||
setNoCover(e);
|
||||
}}
|
||||
/>
|
||||
</ModalContent>
|
||||
|
||||
<ModalFooter>
|
||||
<Button
|
||||
color={Button.Colors.GREEN}
|
||||
disabled={!isValid}
|
||||
onClick={() => {
|
||||
if (!isValid) return;
|
||||
const encrypted = encrypt(secret, password, noCover ? "d d" : cover);
|
||||
const toSend = noCover ? encrypted.replaceAll("d", "") : encrypted;
|
||||
if (!toSend) return;
|
||||
|
||||
insertTextIntoChatInputBox(toSend);
|
||||
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
Send
|
||||
</Button>
|
||||
<Button
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
look={Button.Looks.LINK}
|
||||
style={{ left: 15, position: "absolute" }}
|
||||
onClick={() => {
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export function buildEncModal(): any {
|
||||
openModal(props => <EncModal {...props} />);
|
||||
}
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ChatBarButton, ChatBarButtonFactory } from "@api/ChatButtons";
|
||||
import { updateMessage } from "@api/MessageUpdater";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getStegCloak } from "@utils/dependencies";
|
||||
import definePlugin, { OptionType, ReporterTestable } from "@utils/types";
|
||||
import { Message } from "@vencord/discord-types";
|
||||
import { ChannelStore, Constants, RestAPI, Tooltip } from "@webpack/common";
|
||||
|
||||
import { buildDecModal } from "./components/DecryptionModal";
|
||||
import { buildEncModal } from "./components/EncryptionModal";
|
||||
|
||||
let steggo: any;
|
||||
|
||||
function PopOverIcon() {
|
||||
return (
|
||||
|
||||
<svg
|
||||
fill="var(--header-secondary)"
|
||||
width={24} height={24}
|
||||
viewBox={"0 0 64 64"}
|
||||
>
|
||||
<path d="M 32 9 C 24.832 9 19 14.832 19 22 L 19 27.347656 C 16.670659 28.171862 15 30.388126 15 33 L 15 49 C 15 52.314 17.686 55 21 55 L 43 55 C 46.314 55 49 52.314 49 49 L 49 33 C 49 30.388126 47.329341 28.171862 45 27.347656 L 45 22 C 45 14.832 39.168 9 32 9 z M 32 13 C 36.963 13 41 17.038 41 22 L 41 27 L 23 27 L 23 22 C 23 17.038 27.037 13 32 13 z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function Indicator() {
|
||||
return (
|
||||
<Tooltip text="This message has a hidden message! (InvisibleChat)">
|
||||
{({ onMouseEnter, onMouseLeave }) => (
|
||||
<img
|
||||
aria-label="Hidden Message Indicator (InvisibleChat)"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
src="https://github.com/SammCheese/invisible-chat/raw/NewReplugged/src/assets/lock.png"
|
||||
width={20}
|
||||
height={20}
|
||||
style={{ transform: "translateY(4p)", paddingInline: 4 }}
|
||||
/>
|
||||
)}
|
||||
</Tooltip>
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
const ChatBarIcon: ChatBarButtonFactory = ({ isMainChat }) => {
|
||||
if (!isMainChat) return null;
|
||||
|
||||
return (
|
||||
<ChatBarButton
|
||||
tooltip="Encrypt Message"
|
||||
onClick={() => buildEncModal()}
|
||||
buttonProps={{
|
||||
"aria-haspopup": "dialog",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
aria-hidden
|
||||
role="img"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox={"0 0 64 64"}
|
||||
style={{ scale: "1.39", translate: "0 -1px" }}
|
||||
>
|
||||
<path fill="currentColor" d="M 32 9 C 24.832 9 19 14.832 19 22 L 19 27.347656 C 16.670659 28.171862 15 30.388126 15 33 L 15 49 C 15 52.314 17.686 55 21 55 L 43 55 C 46.314 55 49 52.314 49 49 L 49 33 C 49 30.388126 47.329341 28.171862 45 27.347656 L 45 22 C 45 14.832 39.168 9 32 9 z M 32 13 C 36.963 13 41 17.038 41 22 L 41 27 L 23 27 L 23 22 C 23 17.038 27.037 13 32 13 z" />
|
||||
</svg>
|
||||
</ChatBarButton>
|
||||
);
|
||||
};
|
||||
|
||||
const settings = definePluginSettings({
|
||||
savedPasswords: {
|
||||
type: OptionType.STRING,
|
||||
default: "password, Password",
|
||||
description: "Saved Passwords (Seperated with a , )"
|
||||
}
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "InvisibleChat",
|
||||
description: "Encrypt your Messages in a non-suspicious way!",
|
||||
authors: [Devs.SammCheese],
|
||||
dependencies: ["MessageUpdaterAPI"],
|
||||
reporterTestable: ReporterTestable.Patches,
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
// Indicator
|
||||
find: ".SEND_FAILED,",
|
||||
replacement: {
|
||||
match: /let\{className:\i,message:\i[^}]*\}=(\i)/,
|
||||
replace: "try {$1 && $self.INV_REGEX.test($1.message.content) ? $1.content.push($self.indicator()) : null } catch {};$&"
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
EMBED_API_URL: "https://embed.sammcheese.net",
|
||||
INV_REGEX: new RegExp(/( \u200c|\u200d |[\u2060-\u2064])[^\u200b]/),
|
||||
URL_REGEX: new RegExp(
|
||||
/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/,
|
||||
),
|
||||
async start() {
|
||||
const { default: StegCloak } = await getStegCloak();
|
||||
steggo = new StegCloak(true, false);
|
||||
},
|
||||
|
||||
renderMessagePopoverButton(message) {
|
||||
return this.INV_REGEX.test(message?.content)
|
||||
? {
|
||||
label: "Decrypt Message",
|
||||
icon: this.popOverIcon,
|
||||
message: message,
|
||||
channel: ChannelStore.getChannel(message.channel_id),
|
||||
onClick: async () => {
|
||||
const res = await iteratePasswords(message);
|
||||
|
||||
if (res)
|
||||
this.buildEmbed(message, res);
|
||||
else
|
||||
buildDecModal({ message });
|
||||
}
|
||||
}
|
||||
: null;
|
||||
},
|
||||
|
||||
renderChatBarButton: ChatBarIcon,
|
||||
|
||||
colorCodeFromNumber(color: number): string {
|
||||
return `#${[color >> 16, color >> 8, color]
|
||||
.map(x => (x & 0xFF).toString(16))
|
||||
.join("")}`;
|
||||
},
|
||||
|
||||
// Gets the Embed of a Link
|
||||
async getEmbed(url: URL): Promise<Object | {}> {
|
||||
const { body } = await RestAPI.post({
|
||||
url: Constants.Endpoints.UNFURL_EMBED_URLS,
|
||||
body: {
|
||||
urls: [url]
|
||||
}
|
||||
});
|
||||
// The endpoint returns the color as a number, but Discord expects a string
|
||||
body.embeds[0].color = this.colorCodeFromNumber(body.embeds[0].color);
|
||||
return await body.embeds[0];
|
||||
},
|
||||
|
||||
async buildEmbed(message: any, revealed: string): Promise<void> {
|
||||
const urlCheck = revealed.match(this.URL_REGEX);
|
||||
|
||||
message.embeds.push({
|
||||
type: "rich",
|
||||
rawTitle: "Decrypted Message",
|
||||
color: "#45f5f5",
|
||||
rawDescription: revealed,
|
||||
footer: {
|
||||
text: "Made with ❤️ by c0dine and Sammy!",
|
||||
},
|
||||
});
|
||||
|
||||
if (urlCheck?.length) {
|
||||
const embed = await this.getEmbed(new URL(urlCheck[0]));
|
||||
if (embed)
|
||||
message.embeds.push(embed);
|
||||
}
|
||||
|
||||
updateMessage(message.channel_id, message.id, { embeds: message.embeds });
|
||||
},
|
||||
|
||||
popOverIcon: () => <PopOverIcon />,
|
||||
indicator: ErrorBoundary.wrap(Indicator, { noop: true })
|
||||
});
|
||||
|
||||
export function encrypt(secret: string, password: string, cover: string): string {
|
||||
return steggo.hide(secret + "\u200b", password, cover);
|
||||
}
|
||||
|
||||
export function decrypt(encrypted: string, password: string, removeIndicator: boolean): string {
|
||||
const decrypted = steggo.reveal(encrypted, password);
|
||||
return removeIndicator ? decrypted.replace("\u200b", "") : decrypted;
|
||||
}
|
||||
|
||||
export function isCorrectPassword(result: string): boolean {
|
||||
return result.endsWith("\u200b");
|
||||
}
|
||||
|
||||
export async function iteratePasswords(message: Message): Promise<string | false> {
|
||||
const passwords = settings.store.savedPasswords.split(",").map(s => s.trim());
|
||||
|
||||
if (!message?.content || !passwords?.length) return false;
|
||||
|
||||
let { content } = message;
|
||||
|
||||
// we use an extra variable so we dont have to edit the message content directly
|
||||
if (/^\W/.test(message.content)) content = `d ${message.content}d`;
|
||||
|
||||
for (let i = 0; i < passwords.length; i++) {
|
||||
const result = decrypt(content, passwords[i], false);
|
||||
if (isCorrectPassword(result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -16,13 +16,14 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import NoReplyMentionPlugin from "@plugins/noReplyMention";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { MessageFlags } from "@vencord/discord-types/enums";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { FluxDispatcher, MessageTypeSets, PermissionsBits, PermissionStore, UserStore, WindowStore } from "@webpack/common";
|
||||
import NoReplyMentionPlugin from "plugins/noReplyMention";
|
||||
|
||||
const MessageActions = findByPropsLazy("deleteMessage", "startEditMessage");
|
||||
const EditStore = findByPropsLazy("isEditing", "isEditingAny");
|
||||
|
|
@ -93,7 +94,7 @@ export default definePlugin({
|
|||
if (!MessageTypeSets.REPLYABLE.has(msg.type) || msg.hasFlag(MessageFlags.EPHEMERAL)) return;
|
||||
|
||||
const isShiftPress = event.shiftKey && !settings.store.requireModifier;
|
||||
const shouldMention = Vencord.Plugins.isPluginEnabled(NoReplyMentionPlugin.name)
|
||||
const shouldMention = isPluginEnabled(NoReplyMentionPlugin.name)
|
||||
? NoReplyMentionPlugin.shouldMention(msg, isShiftPress)
|
||||
: !isShiftPress;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { InfoIcon, OwnerCrownIcon } from "@components/Icons";
|
||||
import { cl, getGuildPermissionSpecMap } from "@plugins/permissionsViewer/utils";
|
||||
import { copyToClipboard } from "@utils/clipboard";
|
||||
import { getIntlMessage, getUniqueUsername } from "@utils/discord";
|
||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
|
|
@ -27,7 +28,6 @@ import { findByCodeLazy } from "@webpack";
|
|||
import { ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildRoleStore, i18n, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, useMemo, UserStore, useState, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { settings } from "..";
|
||||
import { cl, getGuildPermissionSpecMap } from "../utils";
|
||||
import { PermissionAllowedIcon, PermissionDefaultIcon, PermissionDeniedIcon } from "./icons";
|
||||
|
||||
export const enum PermissionType {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { HeadingTertiary } from "@components/Heading";
|
||||
import { cl, getGuildPermissionSpecMap, getSortedRolesForMember, sortUserRoles } from "@plugins/permissionsViewer/utils";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { classes } from "@utils/misc";
|
||||
import type { Guild, GuildMember } from "@vencord/discord-types";
|
||||
|
|
@ -25,7 +26,6 @@ import { filters, findBulk, proxyLazyWebpack } from "@webpack";
|
|||
import { PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/common";
|
||||
|
||||
import { PermissionsSortOrder, settings } from "..";
|
||||
import { cl, getGuildPermissionSpecMap, getSortedRolesForMember, sortUserRoles } from "../utils";
|
||||
import openRolesAndUsersPermissionsModal, { PermissionType, type RoleOrUserPermission } from "./RolesAndUsersPermissions";
|
||||
|
||||
interface UserPermission {
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@
|
|||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Divider } from "@components/Divider";
|
||||
import { DEFAULT_COLOR, SWATCHES } from "@plugins/pinDms/constants";
|
||||
import { categoryLen, createCategory, getCategory } from "@plugins/pinDms/data";
|
||||
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModalLazy } from "@utils/modal";
|
||||
import { extractAndLoadChunksLazy, findComponentByCodeLazy } from "@webpack";
|
||||
import { Button, ColorPicker, Forms, Text, TextInput, Toasts, useMemo, useState } from "@webpack/common";
|
||||
|
||||
import { DEFAULT_COLOR, SWATCHES } from "../constants";
|
||||
import { categoryLen, createCategory, getCategory } from "../data";
|
||||
|
||||
interface ColorPickerWithSwatchesProps {
|
||||
defaultColor: number;
|
||||
colors: number[];
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
*/
|
||||
|
||||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { PinOrder, settings } from "@plugins/pinDms";
|
||||
import { addChannelToCategory, canMoveChannelInDirection, currentUserCategories, isPinned, moveChannel, removeChannelFromCategory } from "@plugins/pinDms/data";
|
||||
import { Menu } from "@webpack/common";
|
||||
|
||||
import { addChannelToCategory, canMoveChannelInDirection, currentUserCategories, isPinned, moveChannel, removeChannelFromCategory } from "../data";
|
||||
import { PinOrder, settings } from "../index";
|
||||
import { openCategoryModal } from "./CreateCategoryModal";
|
||||
|
||||
function createPinMenuItem(channelId: string) {
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { PinOrder, PrivateChannelSortStore, settings } from "@plugins/pinDms";
|
||||
import { useForceUpdater } from "@utils/react";
|
||||
import { UserStore } from "@webpack/common";
|
||||
|
||||
import { PinOrder, PrivateChannelSortStore, settings } from "./index";
|
||||
|
||||
export interface Category {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -16,14 +16,15 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import NoBlockedMessagesPlugin from "@plugins/noBlockedMessages";
|
||||
import NoReplyMentionPlugin from "@plugins/noReplyMention";
|
||||
import { Devs, IS_MAC } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Message } from "@vencord/discord-types";
|
||||
import { MessageFlags } from "@vencord/discord-types/enums";
|
||||
import { ChannelStore, ComponentDispatch, FluxDispatcher as Dispatcher, MessageActions, MessageStore, MessageTypeSets, PermissionsBits, PermissionStore, RelationshipStore, SelectedChannelStore, UserStore } from "@webpack/common";
|
||||
import NoBlockedMessagesPlugin from "plugins/noBlockedMessages";
|
||||
import NoReplyMentionPlugin from "plugins/noReplyMention";
|
||||
|
||||
let currentlyReplyingId: string | null = null;
|
||||
let currentlyEditingId: string | null = null;
|
||||
|
|
@ -134,7 +135,7 @@ function getNextMessage(isUp: boolean, isReply: boolean) {
|
|||
let messages: Message[] = MessageStore.getMessages(SelectedChannelStore.getChannelId())._array;
|
||||
|
||||
const meId = UserStore.getCurrentUser().id;
|
||||
const hasNoBlockedMessages = Vencord.Plugins.isPluginEnabled(NoBlockedMessagesPlugin.name);
|
||||
const hasNoBlockedMessages = isPluginEnabled(NoBlockedMessagesPlugin.name);
|
||||
|
||||
messages = messages.filter(m => {
|
||||
if (m.deleted) return false;
|
||||
|
|
@ -170,7 +171,7 @@ function getNextMessage(isUp: boolean, isReply: boolean) {
|
|||
function shouldMention(message: Message) {
|
||||
switch (settings.store.shouldMention) {
|
||||
case MentionOptions.NO_REPLY_MENTION_PLUGIN:
|
||||
if (!Vencord.Plugins.isPluginEnabled(NoReplyMentionPlugin.name)) return true;
|
||||
if (!isPluginEnabled(NoReplyMentionPlugin.name)) return true;
|
||||
return NoReplyMentionPlugin.shouldMention(message, false);
|
||||
case MentionOptions.DISABLED:
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { DataStore, Notices } from "@api/index";
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { popNotice, showNotice } from "@api/Notices";
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { getUniqueUsername, openUserProfile } from "@utils/discord";
|
||||
import { FluxStore } from "@vencord/discord-types";
|
||||
|
|
@ -111,7 +112,7 @@ export async function syncAndRunChecks() {
|
|||
|
||||
export function notify(text: string, icon?: string, onClick?: () => void) {
|
||||
if (settings.store.notices)
|
||||
Notices.showNotice(text, "OK", () => Notices.popNotice());
|
||||
showNotice(text, "OK", () => popNotice());
|
||||
|
||||
showNotification({
|
||||
title: "Relationship Notifier",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { OAuth2AuthorizeModal, showToast, Toasts, UserStore } from "@webpack/common";
|
||||
|
|
|
|||
|
|
@ -4,16 +4,15 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Auth } from "@plugins/reviewDB/auth";
|
||||
import { ReviewDBUser } from "@plugins/reviewDB/entities";
|
||||
import { fetchBlocks, unblockUser } from "@plugins/reviewDB/reviewDbApi";
|
||||
import { cl } from "@plugins/reviewDB/utils";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { Forms, Tooltip, useState } from "@webpack/common";
|
||||
|
||||
import { Auth } from "../auth";
|
||||
import { ReviewDBUser } from "../entities";
|
||||
import { fetchBlocks, unblockUser } from "../reviewDbApi";
|
||||
import { cl } from "../utils";
|
||||
|
||||
function UnblockButton(props: { onClick?(): void; }) {
|
||||
return (
|
||||
<Tooltip text="Unblock user">
|
||||
|
|
|
|||
|
|
@ -16,12 +16,11 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Badge } from "@plugins/reviewDB/entities";
|
||||
import { cl } from "@plugins/reviewDB/utils";
|
||||
import { MaskedLink, React, Tooltip } from "@webpack/common";
|
||||
import { HTMLAttributes } from "react";
|
||||
|
||||
import { Badge } from "../entities";
|
||||
import { cl } from "../utils";
|
||||
|
||||
export default function ReviewBadge(badge: Badge & { onClick?(): void; }) {
|
||||
const Wrapper = badge.redirectURL
|
||||
? MaskedLink
|
||||
|
|
|
|||
|
|
@ -16,17 +16,17 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Auth, getToken } from "@plugins/reviewDB/auth";
|
||||
import { Review, ReviewType } from "@plugins/reviewDB/entities";
|
||||
import { blockUser, deleteReview, reportReview, unblockUser } from "@plugins/reviewDB/reviewDbApi";
|
||||
import { settings } from "@plugins/reviewDB/settings";
|
||||
import { canBlockReviewAuthor, canDeleteReview, canReportReview, cl, showToast } from "@plugins/reviewDB/utils";
|
||||
import { openUserProfile } from "@utils/discord";
|
||||
import { classes } from "@utils/misc";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { filters, findBulk } from "@webpack";
|
||||
import { Alerts, Parser, Timestamp, useState } from "@webpack/common";
|
||||
|
||||
import { Auth, getToken } from "../auth";
|
||||
import { Review, ReviewType } from "../entities";
|
||||
import { blockUser, deleteReview, reportReview, unblockUser } from "../reviewDbApi";
|
||||
import { settings } from "../settings";
|
||||
import { canBlockReviewAuthor, canDeleteReview, canReportReview, cl, showToast } from "../utils";
|
||||
import { openBlockModal } from "./BlockedUserModal";
|
||||
import { BlockButton, DeleteButton, ReportButton } from "./MessageButton";
|
||||
import ReviewBadge from "./ReviewBadge";
|
||||
|
|
|
|||
|
|
@ -17,14 +17,14 @@
|
|||
*/
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Auth } from "@plugins/reviewDB/auth";
|
||||
import { ReviewType } from "@plugins/reviewDB/entities";
|
||||
import { Response, REVIEWS_PER_PAGE } from "@plugins/reviewDB/reviewDbApi";
|
||||
import { cl } from "@plugins/reviewDB/utils";
|
||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { useForceUpdater } from "@utils/react";
|
||||
import { Paginator, Text, useRef, useState } from "@webpack/common";
|
||||
|
||||
import { Auth } from "../auth";
|
||||
import { ReviewType } from "../entities";
|
||||
import { Response, REVIEWS_PER_PAGE } from "../reviewDbApi";
|
||||
import { cl } from "../utils";
|
||||
import ReviewComponent from "./ReviewComponent";
|
||||
import ReviewsView, { ReviewsInputComponent } from "./ReviewsView";
|
||||
|
||||
|
|
|
|||
|
|
@ -16,15 +16,15 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Auth, authorize } from "@plugins/reviewDB/auth";
|
||||
import { Review, ReviewType } from "@plugins/reviewDB/entities";
|
||||
import { addReview, getReviews, Response, REVIEWS_PER_PAGE } from "@plugins/reviewDB/reviewDbApi";
|
||||
import { settings } from "@plugins/reviewDB/settings";
|
||||
import { cl, showToast } from "@plugins/reviewDB/utils";
|
||||
import { useAwaiter, useForceUpdater } from "@utils/react";
|
||||
import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy } from "@webpack";
|
||||
import { Forms, React, RelationshipStore, useRef, UserStore } from "@webpack/common";
|
||||
|
||||
import { Auth, authorize } from "../auth";
|
||||
import { Review, ReviewType } from "../entities";
|
||||
import { addReview, getReviews, Response, REVIEWS_PER_PAGE } from "../reviewDbApi";
|
||||
import { settings } from "../settings";
|
||||
import { cl, showToast } from "../utils";
|
||||
import ReviewComponent from "./ReviewComponent";
|
||||
|
||||
const Transforms = findByPropsLazy("insertNodes", "textToText");
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { hasGuildFeature } from "@utils/discord";
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { dispatchTheme } from "@plugins/shikiCodeblocks.desktop/hooks/useTheme";
|
||||
import type { ShikiSpec } from "@plugins/shikiCodeblocks.desktop/types";
|
||||
import { shikiOnigasmSrc, shikiWorkerSrc } from "@utils/dependencies";
|
||||
import { WorkerClient } from "@vap/core/ipc";
|
||||
import type { IShikiTheme, IThemedToken } from "@vap/shiki";
|
||||
|
||||
import { dispatchTheme } from "../hooks/useTheme";
|
||||
import type { ShikiSpec } from "../types";
|
||||
import { getGrammar, languages, loadLanguages, resolveLang } from "./languages";
|
||||
import { themes } from "./themes";
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { cl } from "../utils/misc";
|
||||
import { cl } from "@plugins/shikiCodeblocks.desktop/utils/misc";
|
||||
|
||||
import { CopyButton } from "./CopyButton";
|
||||
|
||||
export interface ButtonRowProps {
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { cl } from "@plugins/shikiCodeblocks.desktop/utils/misc";
|
||||
import type { IThemedToken } from "@vap/shiki";
|
||||
import { hljs } from "@webpack/common";
|
||||
import { JSX } from "react";
|
||||
|
||||
import { cl } from "../utils/misc";
|
||||
import { ThemeBase } from "./Highlighter";
|
||||
|
||||
export interface CodeProps {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useCopyCooldown } from "../hooks/useCopyCooldown";
|
||||
import { useCopyCooldown } from "@plugins/shikiCodeblocks.desktop/hooks/useCopyCooldown";
|
||||
|
||||
export interface CopyButtonProps extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
|
||||
content: string;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Language } from "../api/languages";
|
||||
import { DeviconSetting } from "../types";
|
||||
import { cl } from "../utils/misc";
|
||||
import { Language } from "@plugins/shikiCodeblocks.desktop/api/languages";
|
||||
import { DeviconSetting } from "@plugins/shikiCodeblocks.desktop/types";
|
||||
import { cl } from "@plugins/shikiCodeblocks.desktop/utils/misc";
|
||||
|
||||
export interface HeaderProps {
|
||||
langName?: string;
|
||||
|
|
|
|||
|
|
@ -17,15 +17,15 @@
|
|||
*/
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { resolveLang } from "@plugins/shikiCodeblocks.desktop/api/languages";
|
||||
import { shiki } from "@plugins/shikiCodeblocks.desktop/api/shiki";
|
||||
import { useShikiSettings } from "@plugins/shikiCodeblocks.desktop/hooks/useShikiSettings";
|
||||
import { useTheme } from "@plugins/shikiCodeblocks.desktop/hooks/useTheme";
|
||||
import { hex2Rgb } from "@plugins/shikiCodeblocks.desktop/utils/color";
|
||||
import { cl, shouldUseHljs } from "@plugins/shikiCodeblocks.desktop/utils/misc";
|
||||
import { useAwaiter, useIntersection } from "@utils/react";
|
||||
import { hljs, React } from "@webpack/common";
|
||||
|
||||
import { resolveLang } from "../api/languages";
|
||||
import { shiki } from "../api/shiki";
|
||||
import { useShikiSettings } from "../hooks/useShikiSettings";
|
||||
import { useTheme } from "../hooks/useTheme";
|
||||
import { hex2Rgb } from "../utils/color";
|
||||
import { cl, shouldUseHljs } from "../utils/misc";
|
||||
import { ButtonRow } from "./ButtonRow";
|
||||
import { Code } from "./Code";
|
||||
import { Header } from "./Header";
|
||||
|
|
|
|||
|
|
@ -16,11 +16,10 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { shiki } from "@plugins/shikiCodeblocks.desktop/api/shiki";
|
||||
import { settings as pluginSettings, ShikiSettings } from "@plugins/shikiCodeblocks.desktop/settings";
|
||||
import { React } from "@webpack/common";
|
||||
|
||||
import { shiki } from "../api/shiki";
|
||||
import { settings as pluginSettings, ShikiSettings } from "../settings";
|
||||
|
||||
export function useShikiSettings<F extends keyof ShikiSettings>(settingKeys: F[]) {
|
||||
const settings = pluginSettings.use([...settingKeys, "customTheme", "theme"]);
|
||||
const [isLoading, setLoading] = React.useState(false);
|
||||
|
|
|
|||
|
|
@ -17,12 +17,11 @@
|
|||
*/
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { resolveLang } from "@plugins/shikiCodeblocks.desktop/api/languages";
|
||||
import { HighlighterProps } from "@plugins/shikiCodeblocks.desktop/components/Highlighter";
|
||||
import { HljsSetting } from "@plugins/shikiCodeblocks.desktop/types";
|
||||
import { hljs } from "@webpack/common";
|
||||
|
||||
import { resolveLang } from "../api/languages";
|
||||
import { HighlighterProps } from "../components/Highlighter";
|
||||
import { HljsSetting } from "../types";
|
||||
|
||||
export const cl = classNameFactory("vc-shiki-");
|
||||
|
||||
export const shouldUseHljs = ({
|
||||
|
|
|
|||
|
|
@ -18,17 +18,18 @@
|
|||
|
||||
import "./styles.css";
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { CopyIcon, LinkIcon } from "@components/Icons";
|
||||
import OpenInAppPlugin from "@plugins/openInApp";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { ConnectedAccount, User } from "@vencord/discord-types";
|
||||
import { findByCodeLazy, findByPropsLazy } from "@webpack";
|
||||
import { Tooltip, UserProfileStore } from "@webpack/common";
|
||||
import OpenInAppPlugin from "plugins/openInApp";
|
||||
|
||||
import { VerifiedIcon } from "./VerifiedIcon";
|
||||
|
||||
|
|
@ -133,7 +134,7 @@ function CompactConnectionComponent({ connection, theme }: { connection: Connect
|
|||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={e => {
|
||||
if (Vencord.Plugins.isPluginEnabled("OpenInApp")) {
|
||||
if (isPluginEnabled(OpenInAppPlugin.name)) {
|
||||
// handleLink will .preventDefault() if applicable
|
||||
OpenInAppPlugin.handleLink(e.currentTarget, e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,16 +16,18 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import PermissionsViewerPlugin from "@plugins/permissionsViewer";
|
||||
import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "@plugins/permissionsViewer/components/RolesAndUsersPermissions";
|
||||
import { sortPermissionOverwrites } from "@plugins/permissionsViewer/utils";
|
||||
import { classes } from "@utils/misc";
|
||||
import { formatDuration } from "@utils/text";
|
||||
import type { Channel } from "@vencord/discord-types";
|
||||
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
|
||||
import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common";
|
||||
|
||||
import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "../../permissionsViewer/components/RolesAndUsersPermissions";
|
||||
import { sortPermissionOverwrites } from "../../permissionsViewer/utils";
|
||||
import { cl, settings } from "..";
|
||||
|
||||
const enum SortOrderTypes {
|
||||
|
|
@ -274,7 +276,7 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
|
|||
}
|
||||
<div className={cl("allowed-users-and-roles-container")}>
|
||||
<div className={cl("allowed-users-and-roles-container-title")}>
|
||||
{Vencord.Plugins.isPluginEnabled("PermissionsViewer") && (
|
||||
{isPluginEnabled(PermissionsViewerPlugin.name) && (
|
||||
<Tooltip text="Permission Details">
|
||||
{({ onMouseLeave, onMouseEnter }) => (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ import { CopyIcon, ImageIcon, LinkIcon, OpenExternalIcon } from "@components/Ico
|
|||
import { Paragraph } from "@components/Paragraph";
|
||||
import { Span } from "@components/Span";
|
||||
import { debounce } from "@shared/debounce";
|
||||
import { openImageModal } from "@utils/discord";
|
||||
import { classes, copyWithToast } from "@utils/misc";
|
||||
import { copyWithToast, openImageModal } from "@utils/discord";
|
||||
import { classes } from "@utils/misc";
|
||||
import { ContextMenuApi, FluxDispatcher, Menu, React, useEffect, useState, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { SeekBar } from "./SeekBar";
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { Settings } from "@api/Settings";
|
||||
import OpenInAppPlugin from "@plugins/openInApp";
|
||||
import { findByProps, findByPropsLazy, proxyLazyWebpack } from "@webpack";
|
||||
import { Flux, FluxDispatcher } from "@webpack/common";
|
||||
|
||||
|
|
@ -89,7 +91,7 @@ export const SpotifyStore = proxyLazyWebpack(() => {
|
|||
public isSettingPosition = false;
|
||||
|
||||
public openExternal(path: string) {
|
||||
const url = Settings.plugins.SpotifyControls.useSpotifyUris || Vencord.Plugins.isPluginEnabled("OpenInApp")
|
||||
const url = Settings.plugins.SpotifyControls.useSpotifyUris || isPluginEnabled(OpenInAppPlugin.name)
|
||||
? "spotify:" + path.replaceAll("/", (_, idx) => idx === 0 ? "" : ":")
|
||||
: "https://open.spotify.com" + path;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,13 @@ import "./style.css";
|
|||
|
||||
import { definePluginSettings, Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { buildSeveralUsers } from "@plugins/typingTweaks";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
||||
import { GuildMemberStore, RelationshipStore, SelectedChannelStore, Tooltip, TypingStore, UserStore, UserSummaryItem, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { buildSeveralUsers } from "../typingTweaks";
|
||||
|
||||
const ThreeDots = findComponentByCodeLazy(".dots,", "dotRadius:");
|
||||
|
||||
const UserGuildSettingsStore = findStoreLazy("UserGuildSettingsStore");
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export default definePlugin({
|
|||
find: "inQuote:",
|
||||
replacement: {
|
||||
match: /,content:([^,]+),inQuote/,
|
||||
replace: (_, content) => `,content:Vencord.Plugins.plugins.Unindent.unindent(${content}),inQuote`
|
||||
replace: (_, content) => `,content:$self.unindent(${content}),inQuote`
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import ShowHiddenChannelsPlugin from "@plugins/showHiddenChannels";
|
||||
import { classes } from "@utils/misc";
|
||||
import { Channel } from "@vencord/discord-types";
|
||||
import { filters, findByPropsLazy, mapMangledModuleLazy } from "@webpack";
|
||||
|
|
@ -141,7 +143,7 @@ export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, isProfile, is
|
|||
if (channel == null) return null;
|
||||
|
||||
const isDM = channel.isDM() || channel.isMultiUserDM();
|
||||
if (!isDM && !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) && !Vencord.Plugins.isPluginEnabled("ShowHiddenChannels")) return null;
|
||||
if (!isDM && !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) && !isPluginEnabled(ShowHiddenChannelsPlugin.name)) return null;
|
||||
|
||||
const isLocked = !isDM && (!PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) || !PermissionStore.can(PermissionsBits.CONNECT, channel));
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./index.css";
|
||||
import "./styles.css";
|
||||
|
||||
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
||||
import { isPluginEnabled, plugins } from "@api/PluginManager";
|
||||
import { Settings, useSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
|
|
@ -34,8 +35,8 @@ function VencordPopout(onClose: () => void) {
|
|||
|
||||
const pluginEntries = [] as ReactNode[];
|
||||
|
||||
for (const plugin of Object.values(Vencord.Plugins.plugins)) {
|
||||
if (plugin.toolboxActions && Vencord.Plugins.isPluginEnabled(plugin.name)) {
|
||||
for (const plugin of Object.values(plugins)) {
|
||||
if (plugin.toolboxActions && isPluginEnabled(plugin.name)) {
|
||||
pluginEntries.push(
|
||||
<Menu.MenuGroup
|
||||
label={plugin.name}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,8 @@ import { Divider } from "@components/Divider";
|
|||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentGuild, getIntlMessage } from "@utils/discord";
|
||||
import { copyWithToast, getCurrentGuild, getIntlMessage } from "@utils/discord";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Message } from "@vencord/discord-types";
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
258
src/utils/apng.ts
Normal file
258
src/utils/apng.ts
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* apng-canvas v2.1.2 - heavily modified and converted to Typescript
|
||||
*
|
||||
* @copyright 2011-2019 David Mzareulyan
|
||||
* @link https://github.com/davidmz/apng-canvas
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
// https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk
|
||||
export const enum ApngDisposeOp {
|
||||
/**
|
||||
* no disposal is done on this frame before rendering the next; the contents of the output buffer are left as is.
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* the frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame.
|
||||
*/
|
||||
BACKGROUND,
|
||||
/**
|
||||
* the frame's region of the output buffer is to be reverted to the previous contents before rendering the next frame.
|
||||
*/
|
||||
PREVIOUS
|
||||
}
|
||||
|
||||
// TODO: Might need to somehow implement this
|
||||
export const enum ApngBlendOp {
|
||||
SOURCE,
|
||||
OVER
|
||||
}
|
||||
|
||||
interface Frame {
|
||||
width: number;
|
||||
height: number;
|
||||
left: number;
|
||||
top: number;
|
||||
delay: number;
|
||||
disposeOp: ApngDisposeOp;
|
||||
blendOp: ApngBlendOp;
|
||||
dataParts?: U8Arr[];
|
||||
img: HTMLImageElement;
|
||||
}
|
||||
|
||||
class Animation {
|
||||
width = 0;
|
||||
height = 0;
|
||||
numPlays = 0;
|
||||
playTime = 0;
|
||||
frames: Frame[] = [];
|
||||
}
|
||||
|
||||
// Typescript has become more strict, requiring you to explicitly specify the ArrayBuffer generic
|
||||
type U8Arr = Uint8Array<ArrayBuffer>;
|
||||
|
||||
const table = new Uint32Array(256);
|
||||
|
||||
for (let i = 0; i < 256; i++) {
|
||||
let c = i;
|
||||
for (let k = 0; k < 8; k++) c = (c & 1) ? 0xEDB88320 ^ (c >>> 1) : c >>> 1;
|
||||
table[i] = c;
|
||||
}
|
||||
|
||||
function crc32(bytes: U8Arr, start: number = 0, length?: number): number {
|
||||
length = length ?? (bytes.length - start);
|
||||
let crc = -1;
|
||||
for (let i = start, l = start + length; i < l; i++) {
|
||||
crc = (crc >>> 8) ^ table[(crc ^ bytes[i]) & 0xFF];
|
||||
}
|
||||
return crc ^ (-1);
|
||||
}
|
||||
|
||||
|
||||
const PNG_SIGNATURE_BYTES = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
||||
|
||||
export function parseAPNG(buffer: ArrayBuffer): Promise<Animation> {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
for (let i = 0; i < PNG_SIGNATURE_BYTES.length; i++) {
|
||||
if (PNG_SIGNATURE_BYTES[i] != bytes[i]) {
|
||||
reject("Not a PNG file (invalid file signature)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// fast animation test
|
||||
let isAnimated = false;
|
||||
parseChunks(bytes, function (type) {
|
||||
if (type == "acTL") {
|
||||
isAnimated = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!isAnimated) {
|
||||
reject("Not an animated PNG");
|
||||
return;
|
||||
}
|
||||
|
||||
const preDataParts: U8Arr[] = [];
|
||||
const postDataParts: U8Arr[] = [];
|
||||
let headerDataBytes: U8Arr | null = null;
|
||||
let frame: Frame | null = null;
|
||||
const anim = new Animation();
|
||||
|
||||
parseChunks(bytes, function (type, bytes, off, length) {
|
||||
switch (type) {
|
||||
case "IHDR":
|
||||
headerDataBytes = bytes.subarray(off + 8, off + 8 + length);
|
||||
anim.width = readDWord(bytes, off + 8);
|
||||
anim.height = readDWord(bytes, off + 12);
|
||||
break;
|
||||
case "acTL":
|
||||
anim.numPlays = readDWord(bytes, off + 8 + 4);
|
||||
break;
|
||||
case "fcTL":
|
||||
if (frame) anim.frames.push(frame);
|
||||
frame = {} as Frame;
|
||||
frame.width = readDWord(bytes, off + 8 + 4);
|
||||
frame.height = readDWord(bytes, off + 8 + 8);
|
||||
frame.left = readDWord(bytes, off + 8 + 12);
|
||||
frame.top = readDWord(bytes, off + 8 + 16);
|
||||
let delayN = readWord(bytes, off + 8 + 20);
|
||||
let delayD = readWord(bytes, off + 8 + 22);
|
||||
if (delayD == 0) delayD = 100;
|
||||
frame.delay = 1000 * delayN / delayD;
|
||||
// see http://mxr.mozilla.org/mozilla/source/gfx/src/shared/gfxImageFrame.cpp#343
|
||||
if (frame.delay <= 10) frame.delay = 100;
|
||||
anim.playTime += frame.delay;
|
||||
frame.disposeOp = readByte(bytes, off + 8 + 24);
|
||||
frame.blendOp = readByte(bytes, off + 8 + 25);
|
||||
frame.dataParts = [];
|
||||
break;
|
||||
case "fdAT":
|
||||
if (frame) frame.dataParts!.push(bytes.subarray(off + 8 + 4, off + 8 + length));
|
||||
break;
|
||||
case "IDAT":
|
||||
if (frame) frame.dataParts!.push(bytes.subarray(off + 8, off + 8 + length));
|
||||
break;
|
||||
case "IEND":
|
||||
postDataParts.push(subBuffer(bytes, off, 12 + length));
|
||||
break;
|
||||
default:
|
||||
preDataParts.push(subBuffer(bytes, off, 12 + length));
|
||||
}
|
||||
});
|
||||
|
||||
if (frame) anim.frames.push(frame);
|
||||
|
||||
if (anim.frames.length == 0) {
|
||||
reject("Not an animated PNG");
|
||||
return;
|
||||
}
|
||||
|
||||
// creating images
|
||||
let createdImages = 0;
|
||||
const preBlob = new Blob(preDataParts);
|
||||
const postBlob = new Blob(postDataParts);
|
||||
for (let f = 0; f < anim.frames.length; f++) {
|
||||
frame = anim.frames[f];
|
||||
|
||||
const bb: (U8Arr | Blob)[] = [];
|
||||
bb.push(PNG_SIGNATURE_BYTES);
|
||||
headerDataBytes!.set(makeDWordArray(frame.width), 0);
|
||||
headerDataBytes!.set(makeDWordArray(frame.height), 4);
|
||||
bb.push(makeChunkBytes("IHDR", headerDataBytes!));
|
||||
bb.push(preBlob);
|
||||
for (let j = 0; j < frame.dataParts!.length; j++) {
|
||||
bb.push(makeChunkBytes("IDAT", frame.dataParts![j]));
|
||||
}
|
||||
bb.push(postBlob);
|
||||
const url = URL.createObjectURL(new Blob(bb, { "type": "image/png" }));
|
||||
delete frame.dataParts;
|
||||
|
||||
/**
|
||||
* Using "createElement" instead of "new Image" because of bug in Chrome 27
|
||||
* https://code.google.com/p/chromium/issues/detail?id=238071
|
||||
* http://stackoverflow.com/questions/16377375/using-canvas-drawimage-in-chrome-extension-content-script/16378270
|
||||
*/
|
||||
const img = frame.img = new Image();
|
||||
img.onload = function () {
|
||||
URL.revokeObjectURL(img.src);
|
||||
createdImages++;
|
||||
if (createdImages == anim.frames.length) {
|
||||
resolve(anim);
|
||||
}
|
||||
};
|
||||
img.onerror = function () {
|
||||
reject("Image creation error");
|
||||
};
|
||||
img.src = url;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseChunks(bytes: U8Arr, callback: (type: string, bytes: U8Arr, off: number, length: number) => boolean | void): void {
|
||||
let off = 8;
|
||||
let res: boolean | void;
|
||||
let type: string;
|
||||
|
||||
do {
|
||||
const length = readDWord(bytes, off);
|
||||
type = readString(bytes, off + 4, 4);
|
||||
res = callback(type, bytes, off, length);
|
||||
off += 12 + length;
|
||||
} while (res !== false && type != "IEND" && off < bytes.length);
|
||||
}
|
||||
|
||||
function readDWord(bytes: U8Arr, off: number): number {
|
||||
let x = 0;
|
||||
// Force the most-significant byte to unsigned.
|
||||
x += ((bytes[0 + off] << 24) >>> 0);
|
||||
for (let i = 1; i < 4; i++) x += ((bytes[i + off] << ((3 - i) * 8)));
|
||||
return x;
|
||||
}
|
||||
|
||||
function readWord(bytes: U8Arr, off: number): number {
|
||||
let x = 0;
|
||||
for (let i = 0; i < 2; i++) x += (bytes[i + off] << ((1 - i) * 8));
|
||||
return x;
|
||||
}
|
||||
|
||||
function readByte(bytes: U8Arr, off: number): number {
|
||||
return bytes[off];
|
||||
}
|
||||
|
||||
function subBuffer(bytes: U8Arr, start: number, length: number): U8Arr {
|
||||
const a = new Uint8Array(length);
|
||||
a.set(bytes.subarray(start, start + length));
|
||||
return a;
|
||||
}
|
||||
|
||||
function readString(bytes: U8Arr, off: number, length: number): string {
|
||||
const chars = Array.prototype.slice.call(bytes.subarray(off, off + length));
|
||||
return String.fromCharCode.apply(String, chars);
|
||||
}
|
||||
|
||||
function makeDWordArray(x: number): number[] {
|
||||
return [(x >>> 24) & 0xff, (x >>> 16) & 0xff, (x >>> 8) & 0xff, x & 0xff];
|
||||
}
|
||||
|
||||
function makeStringArray(x: string): number[] {
|
||||
const res: number[] = [];
|
||||
for (let i = 0; i < x.length; i++) res.push(x.charCodeAt(i));
|
||||
return res;
|
||||
}
|
||||
|
||||
function makeChunkBytes(type: string, dataBytes: U8Arr): U8Arr {
|
||||
const crcLen = type.length + dataBytes.length;
|
||||
const bytes = new Uint8Array(new ArrayBuffer(crcLen + 8));
|
||||
bytes.set(makeDWordArray(dataBytes.length), 0);
|
||||
bytes.set(makeStringArray(type), 4);
|
||||
bytes.set(dataBytes, 8);
|
||||
const crc = crc32(bytes, 4, crcLen);
|
||||
bytes.set(makeDWordArray(crc), crcLen + 4);
|
||||
return bytes;
|
||||
};
|
||||
|
|
@ -30,6 +30,9 @@ const platform = navigator.platform.toLowerCase();
|
|||
export const IS_WINDOWS = platform.startsWith("win");
|
||||
export const IS_MAC = platform.startsWith("mac");
|
||||
export const IS_LINUX = platform.startsWith("linux");
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#mobile_tablet_or_desktop
|
||||
// "In summary, we recommend looking for the string Mobi anywhere in the User Agent to detect a mobile device."
|
||||
export const IS_MOBILE = navigator.userAgent.includes("Mobi");
|
||||
|
||||
export interface Dev {
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -16,61 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { makeLazy } from "./lazy";
|
||||
|
||||
/*
|
||||
Add dynamically loaded dependencies for plugins here.
|
||||
*/
|
||||
|
||||
// needed to parse APNGs in the nitroBypass plugin
|
||||
export const importApngJs = makeLazy(() => {
|
||||
return require("./apng-canvas").APNG as { parseURL(url: string): Promise<ApngFrameData>; };
|
||||
});
|
||||
|
||||
// https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk
|
||||
export const enum ApngDisposeOp {
|
||||
/**
|
||||
* no disposal is done on this frame before rendering the next; the contents of the output buffer are left as is.
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* the frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame.
|
||||
*/
|
||||
BACKGROUND,
|
||||
/**
|
||||
* the frame's region of the output buffer is to be reverted to the previous contents before rendering the next frame.
|
||||
*/
|
||||
PREVIOUS
|
||||
}
|
||||
|
||||
// TODO: Might need to somehow implement this
|
||||
export const enum ApngBlendOp {
|
||||
SOURCE,
|
||||
OVER
|
||||
}
|
||||
export interface ApngFrame {
|
||||
left: number;
|
||||
top: number;
|
||||
width: number;
|
||||
height: number;
|
||||
img: HTMLImageElement;
|
||||
delay: number;
|
||||
blendOp: ApngBlendOp;
|
||||
disposeOp: ApngDisposeOp;
|
||||
}
|
||||
|
||||
export interface ApngFrameData {
|
||||
width: number;
|
||||
height: number;
|
||||
frames: ApngFrame[];
|
||||
playTime: number;
|
||||
}
|
||||
|
||||
// The below code is only used on the Desktop (electron) build of Vencord.
|
||||
// Browser (extension) builds do not contain these remote imports.
|
||||
|
||||
export const shikiWorkerSrc = `https://cdn.jsdelivr.net/npm/@vap/shiki-worker@0.0.8/dist/${IS_DEV ? "index.js" : "index.min.js"}`;
|
||||
export const shikiOnigasmSrc = "https://cdn.jsdelivr.net/npm/@vap/shiki@0.10.3/dist/onig.wasm";
|
||||
|
||||
// @ts-expect-error
|
||||
export const getStegCloak = /* #__PURE__*/ makeLazy(() => import("https://cdn.jsdelivr.net/npm/stegcloak-dist@1.0.0/index.js"));
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { MessageObject } from "@api/MessageEvents";
|
||||
import { Channel, CloudUpload, Guild, GuildFeatures, Message, User } from "@vencord/discord-types";
|
||||
import { ChannelActionCreators, ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, IconUtils, InviteActions, MessageActions, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common";
|
||||
import type { MessageObject } from "@api/MessageEvents";
|
||||
import type { Channel, CloudUpload, Guild, GuildFeatures, Message, User } from "@vencord/discord-types";
|
||||
import { ChannelActionCreators, ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, IconUtils, InviteActions, MessageActions, RestAPI, SelectedChannelStore, SelectedGuildStore, Toasts, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common";
|
||||
import { Except } from "type-fest";
|
||||
|
||||
import { copyToClipboard } from "./clipboard";
|
||||
import { runtimeHashMessageKey, runtimeHashMessageKeyLegacy } from "./intlHash";
|
||||
import { Logger } from "./Logger";
|
||||
import { MediaModalItem, MediaModalProps, openMediaModal } from "./modal";
|
||||
|
|
@ -116,6 +117,15 @@ export function insertTextIntoChatInputBox(text: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function copyWithToast(text: string, toastMessage = "Copied to clipboard!") {
|
||||
await copyToClipboard(text);
|
||||
Toasts.show({
|
||||
message: toastMessage,
|
||||
id: Toasts.genId(),
|
||||
type: Toasts.Type.SUCCESS
|
||||
});
|
||||
}
|
||||
|
||||
interface MessageOptions {
|
||||
messageReference: Message["messageReference"];
|
||||
allowedMentions: {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export * from "./ChangeList";
|
|||
export * from "./clipboard";
|
||||
export * from "./constants";
|
||||
export * from "./cspViolations";
|
||||
export * from "./css";
|
||||
export * from "./discord";
|
||||
export * from "./guards";
|
||||
export * from "./intlHash";
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Toasts } from "@webpack/common";
|
||||
|
||||
import { copyToClipboard } from "./clipboard";
|
||||
import { DevsById } from "./constants";
|
||||
|
||||
/**
|
||||
|
|
@ -36,15 +33,6 @@ export function sleep(ms: number): Promise<void> {
|
|||
return new Promise(r => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
export async function copyWithToast(text: string, toastMessage = "Copied to clipboard!") {
|
||||
await copyToClipboard(text);
|
||||
Toasts.show({
|
||||
message: toastMessage,
|
||||
id: Toasts.genId(),
|
||||
type: Toasts.Type.SUCCESS
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if obj is a true object: of type "object" and not null or array
|
||||
*/
|
||||
|
|
@ -87,10 +75,6 @@ export function identity<T>(value: T): T {
|
|||
return value;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#mobile_tablet_or_desktop
|
||||
// "In summary, we recommend looking for the string Mobi anywhere in the User Agent to detect a mobile device."
|
||||
export const isMobile = navigator.userAgent.includes("Mobi");
|
||||
|
||||
export const isPluginDev = (id: string) => Object.hasOwn(DevsById, id);
|
||||
export const shouldShowContributorBadge = (id: string) => isPluginDev(id) && DevsById[id].badge !== false;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,13 +19,8 @@
|
|||
export function relaunch() {
|
||||
if (IS_DISCORD_DESKTOP)
|
||||
window.DiscordNative.app.relaunch();
|
||||
else
|
||||
else if (IS_VESKTOP)
|
||||
window.VesktopNative.app.relaunch();
|
||||
}
|
||||
|
||||
export function showItemInFolder(path: string) {
|
||||
if (IS_DISCORD_DESKTOP)
|
||||
window.DiscordNative.fileManager.showItemInFolder(path);
|
||||
else
|
||||
window.VesktopNative.fileManager.showItemInFolder(path);
|
||||
location.reload();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
import { React, useEffect, useMemo, useReducer, useState } from "@webpack/common";
|
||||
import { ActionDispatch, ReactNode } from "react";
|
||||
import type { ActionDispatch, ReactNode } from "react";
|
||||
|
||||
import { checkIntersecting } from "./misc";
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { moment } from "@webpack/common";
|
||||
|
||||
// Utils for readable text transformations eg: `toTitle(fromKebab())`
|
||||
|
||||
// Case style to words
|
||||
|
|
@ -54,6 +52,7 @@ function getUnitStr(unit: Units, isOne: boolean, short: boolean) {
|
|||
* @param short Whether to use short units like "d" instead of "days"
|
||||
*/
|
||||
export function formatDuration(time: number, unit: Units, short: boolean = false) {
|
||||
const { moment } = require("@webpack/common") as typeof import("@webpack/common");
|
||||
const dur = moment.duration(time, unit);
|
||||
|
||||
let unitsAmounts = units.map(unit => ({ amount: dur[unit](), unit }));
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue