Merge branch 'Vencord:main' into main

This commit is contained in:
Sammie Zhang 2024-05-28 17:32:20 -07:00 committed by GitHub
commit 9c0b22db1b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 107 additions and 51 deletions

1
.npmrc
View file

@ -1 +1,2 @@
node-linker=hoisted node-linker=hoisted
package-manager-strict=false

View file

@ -27,7 +27,7 @@
"arrpc": "github:OpenAsar/arrpc#6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c" "arrpc": "github:OpenAsar/arrpc#6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c"
}, },
"optionalDependencies": { "optionalDependencies": {
"@vencord/venmic": "^3.4.2" "@vencord/venmic": "^3.5.0"
}, },
"devDependencies": { "devDependencies": {
"@fal-works/esbuild-plugin-global-externals": "^2.1.2", "@fal-works/esbuild-plugin-global-externals": "^2.1.2",

View file

@ -13,8 +13,8 @@ importers:
version: https://codeload.github.com/OpenAsar/arrpc/tar.gz/6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c version: https://codeload.github.com/OpenAsar/arrpc/tar.gz/6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c
optionalDependencies: optionalDependencies:
'@vencord/venmic': '@vencord/venmic':
specifier: ^3.4.2 specifier: ^3.5.0
version: 3.4.2 version: 3.5.0
devDependencies: devDependencies:
'@fal-works/esbuild-plugin-global-externals': '@fal-works/esbuild-plugin-global-externals':
specifier: ^2.1.2 specifier: ^2.1.2
@ -603,8 +603,8 @@ packages:
'@vencord/types@1.8.4': '@vencord/types@1.8.4':
resolution: {integrity: sha512-ogLqIOHVO+5zxKUVxAfGIAUZoEfIomrlg6f0cZ/2yd5vBAn1fA9Gi/NASoKfHZuJt8ZcYw329bgn0ah/VufqMg==} resolution: {integrity: sha512-ogLqIOHVO+5zxKUVxAfGIAUZoEfIomrlg6f0cZ/2yd5vBAn1fA9Gi/NASoKfHZuJt8ZcYw329bgn0ah/VufqMg==}
'@vencord/venmic@3.4.2': '@vencord/venmic@3.5.0':
resolution: {integrity: sha512-nwGjarof1wVvecGksGONfb+PduhY4gSuHTm39LktiQayHS69+yv4lepq4k1lxZzjOgFTy5VXfmJqxt+BpqoUUQ==} resolution: {integrity: sha512-kPvrPcIeMkuqQriuiQAJ9rEBeqGR2nmFBuUtbZRGyiNRF9RDAfWSJYqhHVm6F7wbcqrSZio6FazZuBo0LvjJRw==}
engines: {node: '>=14.15'} engines: {node: '>=14.15'}
os: [linux] os: [linux]
@ -678,6 +678,7 @@ packages:
are-we-there-yet@3.0.1: are-we-there-yet@3.0.1:
resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
deprecated: This package is no longer supported.
argparse@2.0.1: argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@ -1400,6 +1401,7 @@ packages:
gauge@4.0.4: gauge@4.0.4:
resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
deprecated: This package is no longer supported.
get-caller-file@2.0.5: get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
@ -1937,6 +1939,7 @@ packages:
npmlog@6.0.2: npmlog@6.0.2:
resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
deprecated: This package is no longer supported.
object-copy@0.1.0: object-copy@0.1.0:
resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==}
@ -3028,7 +3031,7 @@ snapshots:
standalone-electron-types: 1.0.0 standalone-electron-types: 1.0.0
type-fest: 3.13.1 type-fest: 3.13.1
'@vencord/venmic@3.4.2': '@vencord/venmic@3.5.0':
dependencies: dependencies:
cmake-js: 7.3.0 cmake-js: 7.3.0
node-addon-api: 8.0.0 node-addon-api: 8.0.0

View file

@ -5,11 +5,22 @@
*/ */
import { app } from "electron"; import { app } from "electron";
import { existsSync, readdirSync, renameSync, rmdirSync } from "fs"; import { existsSync, mkdirSync, readdirSync, renameSync, rmdirSync } from "fs";
import { join } from "path"; import { dirname, join } from "path";
const vesktopDir = dirname(process.execPath);
export const PORTABLE =
process.platform === "win32" &&
!process.execPath.toLowerCase().endsWith("electron.exe") &&
!existsSync(join(vesktopDir, "Uninstall Vesktop.exe"));
const LEGACY_DATA_DIR = join(app.getPath("appData"), "VencordDesktop", "VencordDesktop"); const LEGACY_DATA_DIR = join(app.getPath("appData"), "VencordDesktop", "VencordDesktop");
export const DATA_DIR = process.env.VENCORD_USER_DATA_DIR || join(app.getPath("userData")); export const DATA_DIR =
process.env.VENCORD_USER_DATA_DIR || (PORTABLE ? join(vesktopDir, "Data") : join(app.getPath("userData")));
mkdirSync(DATA_DIR, { recursive: true });
// TODO: remove eventually // TODO: remove eventually
if (existsSync(LEGACY_DATA_DIR)) { if (existsSync(LEGACY_DATA_DIR)) {
try { try {

View file

@ -42,7 +42,13 @@ function init() {
// disable renderer backgrounding to prevent the app from unloading when in the background // disable renderer backgrounding to prevent the app from unloading when in the background
// https://github.com/electron/electron/issues/2822 // https://github.com/electron/electron/issues/2822
// https://github.com/GoogleChrome/chrome-launcher/blob/5a27dd574d47a75fec0fb50f7b774ebf8a9791ba/docs/chrome-flags-for-tools.md#task-throttling
app.commandLine.appendSwitch("disable-renderer-backgrounding"); app.commandLine.appendSwitch("disable-renderer-backgrounding");
app.commandLine.appendSwitch("disable-background-timer-throttling");
app.commandLine.appendSwitch("disable-backgrounding-occluded-windows");
if (process.platform === "win32") {
disabledFeatures.push("CalculateNativeWinOcclusion");
}
// work around chrome 66 disabling autoplay by default // work around chrome 66 disabling autoplay by default
app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required"); app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required");
@ -50,12 +56,7 @@ function init() {
// HardwareMediaKeyHandling,MediaSessionService: Prevent Discord from registering as a media service. // HardwareMediaKeyHandling,MediaSessionService: Prevent Discord from registering as a media service.
// //
// WidgetLayering (Vencord Added): Fix DevTools context menus https://github.com/electron/electron/issues/38790 // WidgetLayering (Vencord Added): Fix DevTools context menus https://github.com/electron/electron/issues/38790
disabledFeatures.push( disabledFeatures.push("WinRetrieveSuggestionsOnlyOnDemand", "HardwareMediaKeyHandling", "MediaSessionService");
"WinRetrieveSuggestionsOnlyOnDemand",
"HardwareMediaKeyHandling",
"MediaSessionService",
"WidgetLayering"
);
app.commandLine.appendSwitch("enable-features", [...new Set(enabledFeatures)].filter(Boolean).join(",")); app.commandLine.appendSwitch("enable-features", [...new Set(enabledFeatures)].filter(Boolean).join(","));
app.commandLine.appendSwitch("disable-features", [...new Set(disabledFeatures)].filter(Boolean).join(",")); app.commandLine.appendSwitch("disable-features", [...new Set(disabledFeatures)].filter(Boolean).join(","));

View file

@ -93,12 +93,8 @@ handle(IpcEvents.MAXIMIZE, e => {
} }
}); });
handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => { handleSync(IpcEvents.SPELLCHECK_GET_AVAILABLE_LANGUAGES, e => {
const ses = session.defaultSession; e.returnValue = session.defaultSession.availableSpellCheckerLanguages;
const available = ses.availableSpellCheckerLanguages;
const applicable = languages.filter(l => available.includes(l)).slice(0, 3);
if (applicable.length) ses.setSpellCheckerLanguages(applicable);
}); });
handle(IpcEvents.SPELLCHECK_REPLACE_MISSPELLING, (e, word: string) => { handle(IpcEvents.SPELLCHECK_REPLACE_MISSPELLING, (e, word: string) => {

View file

@ -13,6 +13,7 @@ import {
MenuItemConstructorOptions, MenuItemConstructorOptions,
nativeTheme, nativeTheme,
screen, screen,
session,
Tray Tray
} from "electron"; } from "electron";
import { rm } from "fs/promises"; import { rm } from "fs/promises";
@ -360,12 +361,27 @@ function initSettingsListeners(win: BrowserWindow) {
addSettingsListener("enableMenu", enabled => { addSettingsListener("enableMenu", enabled => {
win.setAutoHideMenuBar(enabled ?? false); win.setAutoHideMenuBar(enabled ?? false);
}); });
addSettingsListener("spellCheckLanguages", languages => initSpellCheckLanguages(win, languages));
}
async function initSpellCheckLanguages(win: BrowserWindow, languages?: string[]) {
languages ??= await win.webContents.executeJavaScript("[...new Set(navigator.languages)]").catch(() => []);
if (!languages) return;
const ses = session.defaultSession;
const available = ses.availableSpellCheckerLanguages;
const applicable = languages.filter(l => available.includes(l)).slice(0, 5);
if (applicable.length) ses.setSpellCheckerLanguages(applicable);
} }
function initSpellCheck(win: BrowserWindow) { function initSpellCheck(win: BrowserWindow) {
win.webContents.on("context-menu", (_, data) => { win.webContents.on("context-menu", (_, data) => {
win.webContents.send(IpcEvents.SPELLCHECK_RESULT, data.misspelledWord, data.dictionarySuggestions); win.webContents.send(IpcEvents.SPELLCHECK_RESULT, data.misspelledWord, data.dictionarySuggestions);
}); });
initSpellCheckLanguages(win, Settings.store.spellCheckLanguages);
} }
function createMainWindow() { function createMainWindow() {
@ -387,7 +403,9 @@ function createMainWindow() {
contextIsolation: true, contextIsolation: true,
devTools: true, devTools: true,
preload: join(__dirname, "preload.js"), preload: join(__dirname, "preload.js"),
spellcheck: true spellcheck: true,
// disable renderer backgrounding to prevent the app from unloading when in the background
backgroundThrottling: false
}, },
icon: ICON_PATH, icon: ICON_PATH,
frame: !noFrame, frame: !noFrame,

View file

@ -35,11 +35,6 @@ function loadSettings<T extends object = any>(file: string, name: string) {
} }
export const Settings = loadSettings<TSettings>(SETTINGS_FILE, "Vesktop settings"); export const Settings = loadSettings<TSettings>(SETTINGS_FILE, "Vesktop settings");
if (Object.hasOwn(Settings.plain, "discordWindowsTitleBar")) {
Settings.plain.customTitleBar = Settings.plain.discordWindowsTitleBar;
delete Settings.plain.discordWindowsTitleBar;
Settings.markAsChanged();
}
export const VencordSettings = loadSettings<any>(VENCORD_SETTINGS_FILE, "Vencord settings"); export const VencordSettings = loadSettings<any>(VENCORD_SETTINGS_FILE, "Vencord settings");

View file

@ -41,7 +41,7 @@ export const VesktopNative = {
set: (settings: Settings, path?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, path) set: (settings: Settings, path?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, path)
}, },
spellcheck: { spellcheck: {
setLanguages: (languages: readonly string[]) => invoke<void>(IpcEvents.SPELLCHECK_SET_LANGUAGES, languages), getAvailableLanguages: () => sendSync<string[]>(IpcEvents.SPELLCHECK_GET_AVAILABLE_LANGUAGES),
onSpellcheckResult(cb: SpellCheckerResultCallback) { onSpellcheckResult(cb: SpellCheckerResultCallback) {
spellCheckCallbacks.add(cb); spellCheckCallbacks.add(cb);
}, },

View file

@ -40,5 +40,3 @@ if (IS_DEV) {
}); });
} }
// #endregion // #endregion
VesktopNative.spellcheck.setLanguages(window.navigator.languages);

View file

@ -12,7 +12,7 @@ import "./themedSplash";
console.log("read if cute :3"); console.log("read if cute :3");
export * as Components from "./components"; export * as Components from "./components";
import { findByPropsLazy } from "@vencord/types/webpack"; import { findByPropsLazy, onceReady } from "@vencord/types/webpack";
import { FluxDispatcher } from "@vencord/types/webpack/common"; import { FluxDispatcher } from "@vencord/types/webpack/common";
import SettingsUi from "./components/settings/Settings"; import SettingsUi from "./components/settings/Settings";
@ -52,8 +52,10 @@ const arRPC = Vencord.Plugins.plugins["WebRichPresence (arRPC)"] as any as {
handleEvent(e: MessageEvent): void; handleEvent(e: MessageEvent): void;
}; };
VesktopNative.arrpc.onActivity(data => { VesktopNative.arrpc.onActivity(async data => {
if (!Settings.store.arRPC) return; if (!Settings.store.arRPC) return;
await onceReady;
arRPC.handleEvent(new MessageEvent("message", { data })); arRPC.handleEvent(new MessageEvent("message", { data }));
}); });

View file

@ -6,7 +6,8 @@
import { addContextMenuPatch } from "@vencord/types/api/ContextMenu"; import { addContextMenuPatch } from "@vencord/types/api/ContextMenu";
import { findStoreLazy } from "@vencord/types/webpack"; import { findStoreLazy } from "@vencord/types/webpack";
import { FluxDispatcher, Menu, useStateFromStores } from "@vencord/types/webpack/common"; import { FluxDispatcher, Menu, useMemo, useStateFromStores } from "@vencord/types/webpack/common";
import { useSettings } from "renderer/settings";
import { addPatch } from "./shared"; import { addPatch } from "./shared";
@ -50,7 +51,16 @@ addContextMenuPatch("textarea-context", children => {
const spellCheckEnabled = useStateFromStores([SpellCheckStore], () => SpellCheckStore.isEnabled()); const spellCheckEnabled = useStateFromStores([SpellCheckStore], () => SpellCheckStore.isEnabled());
const hasCorrections = Boolean(word && corrections?.length); const hasCorrections = Boolean(word && corrections?.length);
children.push( const availableLanguages = useMemo(VesktopNative.spellcheck.getAvailableLanguages, []);
const settings = useSettings();
const spellCheckLanguages = (settings.spellCheckLanguages ??= [...new Set(navigator.languages)]);
const pasteSectionIndex = children.findIndex(c => c?.props?.children?.some(c => c?.props?.id === "paste"));
children.splice(
pasteSectionIndex === -1 ? children.length : pasteSectionIndex,
0,
<Menu.MenuGroup> <Menu.MenuGroup>
{hasCorrections && ( {hasCorrections && (
<> <>
@ -69,6 +79,8 @@ addContextMenuPatch("textarea-context", children => {
/> />
</> </>
)} )}
<Menu.MenuItem id="vcd-spellcheck-settings" label="Spellcheck Settings">
<Menu.MenuCheckboxItem <Menu.MenuCheckboxItem
id="vcd-spellcheck-enabled" id="vcd-spellcheck-enabled"
label="Enable Spellcheck" label="Enable Spellcheck"
@ -77,6 +89,29 @@ addContextMenuPatch("textarea-context", children => {
FluxDispatcher.dispatch({ type: "SPELLCHECK_TOGGLE" }); FluxDispatcher.dispatch({ type: "SPELLCHECK_TOGGLE" });
}} }}
/> />
<Menu.MenuItem id="vcd-spellcheck-languages" label="Languages" disabled={!spellCheckEnabled}>
{availableLanguages.map(lang => {
const isEnabled = spellCheckLanguages.includes(lang);
return (
<Menu.MenuCheckboxItem
id={"vcd-spellcheck-lang-" + lang}
label={lang}
checked={isEnabled}
disabled={!isEnabled && spellCheckLanguages.length >= 5}
action={() => {
const newSpellCheckLanguages = spellCheckLanguages.filter(l => l !== lang);
if (newSpellCheckLanguages.length === spellCheckLanguages.length) {
newSpellCheckLanguages.push(lang);
}
settings.spellCheckLanguages = newSpellCheckLanguages;
}}
/>
);
})}
</Menu.MenuItem>
</Menu.MenuItem>
</Menu.MenuGroup> </Menu.MenuGroup>
); );
}); });

View file

@ -30,7 +30,7 @@ export const enum IpcEvents {
UPDATER_DOWNLOAD = "VCD_UPDATER_DOWNLOAD", UPDATER_DOWNLOAD = "VCD_UPDATER_DOWNLOAD",
UPDATE_IGNORE = "VCD_UPDATE_IGNORE", UPDATE_IGNORE = "VCD_UPDATE_IGNORE",
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES", SPELLCHECK_GET_AVAILABLE_LANGUAGES = "VCD_SPELLCHECK_GET_AVAILABLE_LANGUAGES",
SPELLCHECK_RESULT = "VCD_SPELLCHECK_RESULT", SPELLCHECK_RESULT = "VCD_SPELLCHECK_RESULT",
SPELLCHECK_REPLACE_MISSPELLING = "VCD_SPELLCHECK_REPLACE_MISSPELLING", SPELLCHECK_REPLACE_MISSPELLING = "VCD_SPELLCHECK_REPLACE_MISSPELLING",
SPELLCHECK_ADD_TO_DICTIONARY = "VCD_SPELLCHECK_ADD_TO_DICTIONARY", SPELLCHECK_ADD_TO_DICTIONARY = "VCD_SPELLCHECK_ADD_TO_DICTIONARY",

View file

@ -21,8 +21,6 @@ export interface Settings {
appBadge?: boolean; appBadge?: boolean;
disableMinSize?: boolean; disableMinSize?: boolean;
clickTrayToShowHide?: boolean; clickTrayToShowHide?: boolean;
/** @deprecated use customTitleBar */
discordWindowsTitleBar?: boolean;
customTitleBar?: boolean; customTitleBar?: boolean;
checkUpdates?: boolean; checkUpdates?: boolean;
@ -31,6 +29,8 @@ export interface Settings {
splashColor?: string; splashColor?: string;
splashAnimationPath?: string; splashAnimationPath?: string;
splashBackground?: string; splashBackground?: string;
spellCheckLanguages?: string[];
} }
export interface State { export interface State {

View file

@ -5,6 +5,7 @@
*/ */
import { app, BrowserWindow, shell } from "electron"; import { app, BrowserWindow, shell } from "electron";
import { PORTABLE } from "main/constants";
import { Settings, State } from "main/settings"; import { Settings, State } from "main/settings";
import { handle } from "main/utils/ipcWrappers"; import { handle } from "main/utils/ipcWrappers";
import { makeLinksOpenExternally } from "main/utils/makeLinksOpenExternally"; import { makeLinksOpenExternally } from "main/utils/makeLinksOpenExternally";
@ -23,17 +24,12 @@ let updateData: UpdateData;
handle(IpcEvents.UPDATER_GET_DATA, () => updateData); handle(IpcEvents.UPDATER_GET_DATA, () => updateData);
handle(IpcEvents.UPDATER_DOWNLOAD, () => { handle(IpcEvents.UPDATER_DOWNLOAD, () => {
const portable = !!process.env.PORTABLE_EXECUTABLE_FILE;
const { assets } = updateData.release; const { assets } = updateData.release;
const url = (() => { const url = (() => {
switch (process.platform) { switch (process.platform) {
case "win32": case "win32":
return assets.find(a => { return assets.find(a => {
if (!a.name.endsWith(".exe")) return false; return a.name.endsWith(PORTABLE ? "win.zip" : ".exe");
const isSetup = a.name.includes("Setup");
return portable ? !isSetup : isSetup;
})!.browser_download_url; })!.browser_download_url;
case "darwin": case "darwin":
return assets.find(a => return assets.find(a =>