Update to latest vesktop
This commit is contained in:
parent
d51659566b
commit
47aff140b8
23 changed files with 1558 additions and 615 deletions
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -7,25 +7,38 @@ assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Please do not open issues for the following things. We cannot help you with them:
|
||||||
|
- "Vesktop.app is damaged" on MacOs ~ Fake issue created by crApple. Google how to fix it https://google.it/search?q=fix+app+is+damaged
|
||||||
|
- Screenshare does not start / is black ~ This is an issue with your desktop environment, specifically its xdg-desktop-portal
|
||||||
|
- Purely graphical glitches, like flickering, scaling issues, short whitescreens, etc ~ These are most likely issues with your GPU. try to disable hardware acceleration
|
||||||
|
- Vencord related issues ~ This is the Vesktop repo, not Vencord
|
||||||
|
- Getting logged out after restart ~ If you use DevTools, make sure you have NoDevtoolsWarning enabled. Otherwise try reinstalling Vesktop
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
|
|
||||||
A clear and concise description of what the bug is.
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
|
|
||||||
|
<!--
|
||||||
Steps to reproduce the behavior:
|
Steps to reproduce the behavior:
|
||||||
1. Go to '...'
|
1. Go to '...'
|
||||||
2. Click on '....'
|
2. Click on '....'
|
||||||
3. Scroll down to '....'
|
3. Scroll down to '....'
|
||||||
4. See error
|
4. See error
|
||||||
|
-->
|
||||||
|
|
||||||
**Expected behavior**
|
**Expected behavior**
|
||||||
|
|
||||||
A clear and concise description of what you expected to happen.
|
<!-- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
**Screenshots**
|
**Screenshots**
|
||||||
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||||
|
|
||||||
**Desktop (please complete the following information):**
|
**Desktop (please complete the following information):**
|
||||||
- OS/Distro: [e.g. Windows / Fedora Linux / MacOs]
|
- OS/Distro: [e.g. Windows / Fedora Linux / MacOs]
|
||||||
|
@ -34,11 +47,12 @@ If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
**Command line output**
|
**Command line output**
|
||||||
|
|
||||||
Run vesktop from the command line. Include the relevant command line output here:
|
<!-- Run vesktop from the command line. Include the relevant command line output here: -->
|
||||||
|
|
||||||
```
|
```
|
||||||
paste inside these backticks
|
paste inside these backticks
|
||||||
```
|
```
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
|
|
||||||
Add any other context about the problem here.
|
<!-- Add any other context about the problem here. -->
|
||||||
|
|
|
@ -54,6 +54,7 @@ Below you can find unofficial packages created by the community. They are not of
|
||||||
|
|
||||||
- Arch Linux: [Vesktop on the Arch user repository](https://aur.archlinux.org/packages?K=vesktop)
|
- Arch Linux: [Vesktop on the Arch user repository](https://aur.archlinux.org/packages?K=vesktop)
|
||||||
- NixOS: https://nixos.wiki/wiki/Discord#Vesktop
|
- NixOS: https://nixos.wiki/wiki/Discord#Vesktop
|
||||||
|
- Windows - Scoop: https://scoop.sh/#/apps?q=Vesktop
|
||||||
|
|
||||||
## Building from Source
|
## Building from Source
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,24 @@
|
||||||
</screenshot>
|
</screenshot>
|
||||||
</screenshots>
|
</screenshots>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="1.5.1" date="2024-03-12" type="stable">
|
||||||
|
<url>https://github.com/Vencord/Vesktop/releases/tag/v1.5.1</url>
|
||||||
|
<description>
|
||||||
|
<p>New Features</p>
|
||||||
|
<ul>
|
||||||
|
<li>Added categories to Vesktop settings to reduce visual clutter by @justin13888</li>
|
||||||
|
<li>Added support for Vencord's transparent window options</li>
|
||||||
|
</ul>
|
||||||
|
<p>Fixes</p>
|
||||||
|
<ul>
|
||||||
|
<li>Fixed ugly error popups when starting Vesktop without working internet connection</li>
|
||||||
|
<li>Fixed popout title bars on Windows</li>
|
||||||
|
<li>Fixed spellcheck entries</li>
|
||||||
|
<li>Fixed screenshare audio using microphone on debian, by @Curve</li>
|
||||||
|
<li>Fixed a bug where autostart on Linux won't preserve command line flags</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="1.5.0" date="2024-01-16" type="stable">
|
<release version="1.5.0" date="2024-01-16" type="stable">
|
||||||
<url>https://github.com/Vencord/Vesktop/releases/tag/v1.5.0</url>
|
<url>https://github.com/Vencord/Vesktop/releases/tag/v1.5.0</url>
|
||||||
<description>
|
<description>
|
||||||
|
@ -162,11 +180,7 @@
|
||||||
<control>voice</control>
|
<control>voice</control>
|
||||||
<display_length compare="ge">760</display_length>
|
<display_length compare="ge">760</display_length>
|
||||||
<display_length compare="le">1200</display_length>
|
<display_length compare="le">1200</display_length>
|
||||||
<internet>always</internet>
|
|
||||||
</recommends>
|
</recommends>
|
||||||
<supports>
|
|
||||||
<internet>always</internet>
|
|
||||||
</supports>
|
|
||||||
<content_rating type="oars-1.1">
|
<content_rating type="oars-1.1">
|
||||||
<content_attribute id="social-chat">intense</content_attribute>
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
<content_attribute id="social-audio">intense</content_attribute>
|
<content_attribute id="social-audio">intense</content_attribute>
|
||||||
|
|
34
package.json
34
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "vesktop",
|
"name": "vesktop",
|
||||||
"version": "1.5.0",
|
"version": "1.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "",
|
"description": "",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
@ -31,29 +31,29 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
||||||
"@types/node": "^20.11.2",
|
"@types/node": "^20.11.26",
|
||||||
"@types/react": "^18.2.48",
|
"@types/react": "^18.2.65",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||||
"@typescript-eslint/parser": "^6.19.0",
|
"@typescript-eslint/parser": "^7.2.0",
|
||||||
"@vencord/types": "^0.1.2",
|
"@vencord/types": "^0.1.2",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.4.5",
|
||||||
"electron": "^28.1.3",
|
"electron": "^29.1.1",
|
||||||
"electron-builder": "^24.9.1",
|
"electron-builder": "^24.13.3",
|
||||||
"esbuild": "^0.19.11",
|
"esbuild": "^0.20.1",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-import-resolver-alias": "^1.1.2",
|
"eslint-import-resolver-alias": "^1.1.2",
|
||||||
"eslint-plugin-license-header": "^0.6.0",
|
"eslint-plugin-license-header": "^0.6.0",
|
||||||
"eslint-plugin-path-alias": "^1.0.0",
|
"eslint-plugin-path-alias": "^1.0.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
"eslint-plugin-simple-import-sort": "^12.0.0",
|
||||||
"eslint-plugin-unused-imports": "^3.0.0",
|
"eslint-plugin-unused-imports": "^3.1.0",
|
||||||
"prettier": "^3.2.2",
|
"prettier": "^3.2.5",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"tsx": "^4.7.0",
|
"tsx": "^4.7.1",
|
||||||
"type-fest": "^4.9.0",
|
"type-fest": "^4.12.0",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.4.2",
|
||||||
"xml-formatter": "^3.6.0"
|
"xml-formatter": "^3.6.2"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.11.0",
|
"packageManager": "pnpm@8.11.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
1531
pnpm-lock.yaml
1531
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -8,4 +8,4 @@ import "./utils/dotenv";
|
||||||
|
|
||||||
import { spawnNodeModuleBin } from "./utils/spawn.mjs";
|
import { spawnNodeModuleBin } from "./utils/spawn.mjs";
|
||||||
|
|
||||||
spawnNodeModuleBin("electron", [".", ...(process.env.ELECTRON_LAUNCH_FLAGS?.split(" ") ?? [])]);
|
spawnNodeModuleBin("electron", [process.cwd(), ...(process.env.ELECTRON_LAUNCH_FLAGS?.split(" ") ?? [])]);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
|
import { existsSync, mkdirSync, renameSync, rmSync, writeFileSync } from "fs";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
interface AutoStart {
|
interface AutoStart {
|
||||||
|
@ -17,7 +17,16 @@ interface AutoStart {
|
||||||
function makeAutoStartLinux(): AutoStart {
|
function makeAutoStartLinux(): AutoStart {
|
||||||
const configDir = process.env.XDG_CONFIG_HOME || join(process.env.HOME!, ".config");
|
const configDir = process.env.XDG_CONFIG_HOME || join(process.env.HOME!, ".config");
|
||||||
const dir = join(configDir, "autostart");
|
const dir = join(configDir, "autostart");
|
||||||
const file = join(dir, "vencord.desktop");
|
const file = join(dir, "vesktop.desktop");
|
||||||
|
|
||||||
|
// IM STUPID
|
||||||
|
const legacyName = join(dir, "vencord.desktop");
|
||||||
|
if (existsSync(legacyName)) renameSync(legacyName, file);
|
||||||
|
|
||||||
|
// "Quoting must be done by enclosing the argument between double quotes and escaping the double quote character,
|
||||||
|
// backtick character ("`"), dollar sign ("$") and backslash character ("\") by preceding it with an additional backslash character"
|
||||||
|
// https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables
|
||||||
|
const commandLine = process.argv.map(arg => '"' + arg.replace(/["$`\\]/g, "\\$&") + '"').join(" ");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isEnabled: () => existsSync(file),
|
isEnabled: () => existsSync(file),
|
||||||
|
@ -25,12 +34,11 @@ function makeAutoStartLinux(): AutoStart {
|
||||||
const desktopFile = `
|
const desktopFile = `
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Version=1.0
|
Name=Vesktop
|
||||||
Name=Vencord
|
Comment=Vesktop autostart script
|
||||||
Comment=Vencord autostart script
|
Exec=${commandLine}
|
||||||
Exec=${process.execPath}
|
|
||||||
Terminal=false
|
|
||||||
StartupNotify=false
|
StartupNotify=false
|
||||||
|
Terminal=false
|
||||||
`.trim();
|
`.trim();
|
||||||
|
|
||||||
mkdirSync(dir, { recursive: true });
|
mkdirSync(dir, { recursive: true });
|
||||||
|
|
|
@ -48,14 +48,14 @@ export const DEFAULT_HEIGHT = 720;
|
||||||
|
|
||||||
export const DISCORD_HOSTNAMES = ["discord.com", "canary.discord.com", "ptb.discord.com"];
|
export const DISCORD_HOSTNAMES = ["discord.com", "canary.discord.com", "ptb.discord.com"];
|
||||||
|
|
||||||
const UserAgents = {
|
const BrowserUserAgents = {
|
||||||
darwin: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
darwin: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
|
||||||
linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
|
||||||
windows:
|
windows:
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserAgent = UserAgents[process.platform] || UserAgents.windows;
|
export const BrowserUserAgent = BrowserUserAgents[process.platform] || BrowserUserAgents.windows;
|
||||||
|
|
||||||
export const enum MessageBoxChoice {
|
export const enum MessageBoxChoice {
|
||||||
Default,
|
Default,
|
||||||
|
|
|
@ -26,13 +26,13 @@ import { ICON_PATH } from "../shared/paths";
|
||||||
import { createAboutWindow } from "./about";
|
import { createAboutWindow } from "./about";
|
||||||
import { initArRPC } from "./arrpc";
|
import { initArRPC } from "./arrpc";
|
||||||
import {
|
import {
|
||||||
|
BrowserUserAgent,
|
||||||
DATA_DIR,
|
DATA_DIR,
|
||||||
DEFAULT_HEIGHT,
|
DEFAULT_HEIGHT,
|
||||||
DEFAULT_WIDTH,
|
DEFAULT_WIDTH,
|
||||||
MessageBoxChoice,
|
MessageBoxChoice,
|
||||||
MIN_HEIGHT,
|
MIN_HEIGHT,
|
||||||
MIN_WIDTH,
|
MIN_WIDTH,
|
||||||
UserAgent,
|
|
||||||
VENCORD_FILES_DIR
|
VENCORD_FILES_DIR
|
||||||
} from "./constants";
|
} from "./constants";
|
||||||
import { Settings, State, VencordSettings } from "./settings";
|
import { Settings, State, VencordSettings } from "./settings";
|
||||||
|
@ -427,7 +427,7 @@ function createMainWindow() {
|
||||||
initSettingsListeners(win);
|
initSettingsListeners(win);
|
||||||
initSpellCheck(win);
|
initSpellCheck(win);
|
||||||
|
|
||||||
win.webContents.setUserAgent(UserAgent);
|
win.webContents.setUserAgent(BrowserUserAgent);
|
||||||
|
|
||||||
const subdomain =
|
const subdomain =
|
||||||
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
||||||
|
|
|
@ -5,41 +5,54 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createWriteStream } from "fs";
|
import { createWriteStream } from "fs";
|
||||||
import type { IncomingMessage } from "http";
|
import { Readable } from "stream";
|
||||||
import { get, RequestOptions } from "https";
|
import { pipeline } from "stream/promises";
|
||||||
import { finished } from "stream/promises";
|
import { setTimeout } from "timers/promises";
|
||||||
|
|
||||||
export async function downloadFile(url: string, file: string, options: RequestOptions = {}) {
|
interface FetchieOptions {
|
||||||
const res = await simpleReq(url, options);
|
retryOnNetworkError?: boolean;
|
||||||
await finished(
|
}
|
||||||
res.pipe(
|
|
||||||
|
export async function downloadFile(url: string, file: string, options: RequestInit = {}, fetchieOpts?: FetchieOptions) {
|
||||||
|
const res = await fetchie(url, options, fetchieOpts);
|
||||||
|
await pipeline(
|
||||||
|
// @ts-expect-error odd type error
|
||||||
|
Readable.fromWeb(res.body!),
|
||||||
createWriteStream(file, {
|
createWriteStream(file, {
|
||||||
autoClose: true
|
autoClose: true
|
||||||
})
|
})
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function simpleReq(url: string, options: RequestOptions = {}) {
|
const ONE_MINUTE_MS = 1000 * 60;
|
||||||
return new Promise<IncomingMessage>((resolve, reject) => {
|
|
||||||
get(url, options, res => {
|
|
||||||
const { statusCode, statusMessage, headers } = res;
|
|
||||||
if (statusCode! >= 400) return void reject(`${statusCode}: ${statusMessage} - ${url}`);
|
|
||||||
if (statusCode! >= 300) return simpleReq(headers.location!, options).then(resolve).catch(reject);
|
|
||||||
|
|
||||||
resolve(res);
|
export async function fetchie(url: string, options?: RequestInit, { retryOnNetworkError }: FetchieOptions = {}) {
|
||||||
});
|
let res: Response | undefined;
|
||||||
});
|
|
||||||
|
try {
|
||||||
|
res = await fetch(url, options);
|
||||||
|
} catch (err) {
|
||||||
|
if (retryOnNetworkError) {
|
||||||
|
console.error("Failed to fetch", url + ".", "Gonna retry with backoff.");
|
||||||
|
|
||||||
|
for (let tries = 0, delayMs = 500; tries < 20; tries++, delayMs = Math.min(2 * delayMs, ONE_MINUTE_MS)) {
|
||||||
|
await setTimeout(delayMs);
|
||||||
|
try {
|
||||||
|
res = await fetch(url, options);
|
||||||
|
break;
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function simpleGet(url: string, options: RequestOptions = {}) {
|
if (!res) throw new Error(`Failed to fetch ${url}\n${err}`);
|
||||||
const res = await simpleReq(url, options);
|
}
|
||||||
|
|
||||||
return new Promise<Buffer>((resolve, reject) => {
|
if (res.ok) return res;
|
||||||
const chunks = [] as Buffer[];
|
|
||||||
|
let msg = `Got non-OK response for ${url}: ${res.status} ${res.statusText}`;
|
||||||
res.once("error", reject);
|
|
||||||
res.on("data", chunk => chunks.push(chunk));
|
const reason = await res.text().catch(() => "");
|
||||||
res.once("end", () => resolve(Buffer.concat(chunks)));
|
if (reason) msg += `\n${reason}`;
|
||||||
});
|
|
||||||
|
throw new Error(msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { existsSync, mkdirSync } from "fs";
|
import { existsSync, mkdirSync } from "fs";
|
||||||
import type { RequestOptions } from "https";
|
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
import { USER_AGENT, VENCORD_FILES_DIR } from "../constants";
|
import { USER_AGENT, VENCORD_FILES_DIR } from "../constants";
|
||||||
import { downloadFile, simpleGet } from "./http";
|
import { downloadFile, fetchie } from "./http";
|
||||||
|
|
||||||
const API_BASE = "https://api.github.com";
|
const API_BASE = "https://api.github.com";
|
||||||
|
|
||||||
|
@ -31,27 +30,29 @@ export interface ReleaseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function githubGet(endpoint: string) {
|
export async function githubGet(endpoint: string) {
|
||||||
const opts: RequestOptions = {
|
const opts: RequestInit = {
|
||||||
headers: {
|
headers: {
|
||||||
Accept: "application/vnd.github+json",
|
Accept: "application/vnd.github+json",
|
||||||
"User-Agent": USER_AGENT
|
"User-Agent": USER_AGENT
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (process.env.GITHUB_TOKEN) opts.headers!.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
if (process.env.GITHUB_TOKEN) (opts.headers! as any).Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
||||||
|
|
||||||
return simpleGet(API_BASE + endpoint, opts);
|
return fetchie(API_BASE + endpoint, opts, { retryOnNetworkError: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadVencordFiles() {
|
export async function downloadVencordFiles() {
|
||||||
const release = await githubGet("/repos/Vendicated/Vencord/releases/latest");
|
const release = await githubGet("/repos/Vendicated/Vencord/releases/latest");
|
||||||
|
|
||||||
const { assets } = JSON.parse(release.toString("utf-8")) as ReleaseData;
|
const { assets }: ReleaseData = await release.json();
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
assets
|
assets
|
||||||
.filter(({ name }) => FILES_TO_DOWNLOAD.some(f => name.startsWith(f)))
|
.filter(({ name }) => FILES_TO_DOWNLOAD.some(f => name.startsWith(f)))
|
||||||
.map(({ name, browser_download_url }) => downloadFile(browser_download_url, join(VENCORD_FILES_DIR, name)))
|
.map(({ name, browser_download_url }) =>
|
||||||
|
downloadFile(browser_download_url, join(VENCORD_FILES_DIR, name), {}, { retryOnNetworkError: true })
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,3 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * as ScreenShare from "./ScreenSharePicker";
|
export * as ScreenShare from "./ScreenSharePicker";
|
||||||
export { default as Settings } from "./Settings";
|
|
||||||
|
|
26
src/renderer/components/settings/AutoStartToggle.tsx
Normal file
26
src/renderer/components/settings/AutoStartToggle.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Switch, useState } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
|
import { SettingsComponent } from "./Settings";
|
||||||
|
|
||||||
|
export const AutoStartToggle: SettingsComponent = () => {
|
||||||
|
const [autoStartEnabled, setAutoStartEnabled] = useState(VesktopNative.autostart.isEnabled());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
value={autoStartEnabled}
|
||||||
|
onChange={async v => {
|
||||||
|
await VesktopNative.autostart[v ? "enable" : "disable"]();
|
||||||
|
setAutoStartEnabled(v);
|
||||||
|
}}
|
||||||
|
note="Automatically start Vesktop on computer start-up"
|
||||||
|
>
|
||||||
|
Start With System
|
||||||
|
</Switch>
|
||||||
|
);
|
||||||
|
};
|
26
src/renderer/components/settings/DiscordBranchPicker.tsx
Normal file
26
src/renderer/components/settings/DiscordBranchPicker.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Select } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
|
import { SettingsComponent } from "./Settings";
|
||||||
|
|
||||||
|
export const DiscordBranchPicker: SettingsComponent = ({ settings }) => {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
placeholder="Stable"
|
||||||
|
options={[
|
||||||
|
{ label: "Stable", value: "stable", default: true },
|
||||||
|
{ label: "Canary", value: "canary" },
|
||||||
|
{ label: "PTB", value: "ptb" }
|
||||||
|
]}
|
||||||
|
closeOnSelect={true}
|
||||||
|
select={v => (settings.discordBranch = v)}
|
||||||
|
isSelected={v => v === settings.discordBranch}
|
||||||
|
serialize={s => s}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
26
src/renderer/components/settings/NotificationBadgeToggle.tsx
Normal file
26
src/renderer/components/settings/NotificationBadgeToggle.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Switch } from "@vencord/types/webpack/common";
|
||||||
|
import { setBadge } from "renderer/appBadge";
|
||||||
|
|
||||||
|
import { SettingsComponent } from "./Settings";
|
||||||
|
|
||||||
|
export const NotificationBadgeToggle: SettingsComponent = ({ settings }) => {
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
value={settings.appBadge ?? true}
|
||||||
|
onChange={v => {
|
||||||
|
settings.appBadge = v;
|
||||||
|
if (v) setBadge();
|
||||||
|
else VesktopNative.app.setBadgeCount(0);
|
||||||
|
}}
|
||||||
|
note="Show mention badge on the app icon"
|
||||||
|
>
|
||||||
|
Notification Badge
|
||||||
|
</Switch>
|
||||||
|
);
|
||||||
|
};
|
172
src/renderer/components/settings/Settings.tsx
Normal file
172
src/renderer/components/settings/Settings.tsx
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./settings.css";
|
||||||
|
|
||||||
|
import { Forms, Switch, Text } from "@vencord/types/webpack/common";
|
||||||
|
import { ComponentType } from "react";
|
||||||
|
import { Settings, useSettings } from "renderer/settings";
|
||||||
|
import { isMac, isWindows } from "renderer/utils";
|
||||||
|
|
||||||
|
import { AutoStartToggle } from "./AutoStartToggle";
|
||||||
|
import { DiscordBranchPicker } from "./DiscordBranchPicker";
|
||||||
|
import { NotificationBadgeToggle } from "./NotificationBadgeToggle";
|
||||||
|
import { VencordLocationPicker } from "./VencordLocationPicker";
|
||||||
|
import { WindowsTransparencyControls } from "./WindowsTransparencyControls";
|
||||||
|
import { WindowZoom } from "./WindowZoom";
|
||||||
|
|
||||||
|
interface BooleanSetting {
|
||||||
|
key: keyof typeof Settings.store;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
defaultValue: boolean;
|
||||||
|
disabled?(): boolean;
|
||||||
|
invisible?(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SettingsComponent = ComponentType<{ settings: typeof Settings.store }>;
|
||||||
|
|
||||||
|
const SettingsOptions: Record<string, Array<BooleanSetting | SettingsComponent>> = {
|
||||||
|
"Discord Branch": [DiscordBranchPicker],
|
||||||
|
"System Startup & Performance": [
|
||||||
|
AutoStartToggle,
|
||||||
|
{
|
||||||
|
key: "hardwareAcceleration",
|
||||||
|
title: "Hardware Acceleration",
|
||||||
|
description: "Enable hardware acceleration",
|
||||||
|
defaultValue: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"User Interface": [
|
||||||
|
{
|
||||||
|
key: "customTitleBar",
|
||||||
|
title: "Discord Titlebar",
|
||||||
|
description: "Use Discord's custom title bar instead of the native system one. Requires a full restart.",
|
||||||
|
defaultValue: isWindows
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "staticTitle",
|
||||||
|
title: "Static Title",
|
||||||
|
description: 'Makes the window title "Vesktop" instead of changing to the current page',
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "enableMenu",
|
||||||
|
title: "Enable Menu Bar",
|
||||||
|
description: "Enables the application menu bar. Press ALT to toggle visibility.",
|
||||||
|
defaultValue: false,
|
||||||
|
disabled: () => Settings.store.customTitleBar ?? isWindows
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "splashTheming",
|
||||||
|
title: "Splash theming",
|
||||||
|
description: "Adapt the splash window colors to your custom theme",
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
WindowsTransparencyControls,
|
||||||
|
WindowZoom
|
||||||
|
],
|
||||||
|
Behaviour: [
|
||||||
|
{
|
||||||
|
key: "tray",
|
||||||
|
title: "Tray Icon",
|
||||||
|
description: "Add a tray icon for Vesktop",
|
||||||
|
defaultValue: true,
|
||||||
|
invisible: () => isMac
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "minimizeToTray",
|
||||||
|
title: "Minimize to tray",
|
||||||
|
description: "Hitting X will make Vesktop minimize to the tray instead of closing",
|
||||||
|
defaultValue: true,
|
||||||
|
invisible: () => isMac,
|
||||||
|
disabled: () => Settings.store.tray === false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "disableMinSize",
|
||||||
|
title: "Disable minimum window size",
|
||||||
|
description: "Allows you to make the window as small as your heart desires",
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "disableSmoothScroll",
|
||||||
|
title: "Disable smooth scrolling",
|
||||||
|
description: "Disables smooth scrolling",
|
||||||
|
defaultValue: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Notifications & Updates": [
|
||||||
|
NotificationBadgeToggle,
|
||||||
|
{
|
||||||
|
key: "checkUpdates",
|
||||||
|
title: "Check for updates",
|
||||||
|
description: "Automatically check for Vesktop updates",
|
||||||
|
defaultValue: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Miscelleanous: [
|
||||||
|
{
|
||||||
|
key: "arRPC",
|
||||||
|
title: "Rich Presence",
|
||||||
|
description: "Enables Rich Presence via arRPC",
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
key: "openLinksWithElectron",
|
||||||
|
title: "Open Links in app (experimental)",
|
||||||
|
description: "Opens links in a new Vesktop window instead of your web browser",
|
||||||
|
defaultValue: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Vencord Location": [VencordLocationPicker]
|
||||||
|
};
|
||||||
|
|
||||||
|
function SettingsSections() {
|
||||||
|
const Settings = useSettings();
|
||||||
|
|
||||||
|
const sections = Object.entries(SettingsOptions).map(([title, settings]) => (
|
||||||
|
<Forms.FormSection
|
||||||
|
title={title}
|
||||||
|
key={title}
|
||||||
|
className="vcd-settings-section"
|
||||||
|
titleClassName="vcd-settings-title"
|
||||||
|
>
|
||||||
|
{settings.map(Setting => {
|
||||||
|
if (typeof Setting === "function") return <Setting settings={Settings} />;
|
||||||
|
|
||||||
|
const { defaultValue, title, description, key, disabled, invisible } = Setting;
|
||||||
|
if (invisible?.()) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
value={Settings[key as any] ?? defaultValue}
|
||||||
|
onChange={v => (Settings[key as any] = v)}
|
||||||
|
note={description}
|
||||||
|
disabled={disabled?.()}
|
||||||
|
key={key}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Switch>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Forms.FormSection>
|
||||||
|
));
|
||||||
|
|
||||||
|
return <>{sections}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SettingsUi() {
|
||||||
|
return (
|
||||||
|
<Forms.FormSection>
|
||||||
|
<Text variant="heading-lg/semibold" style={{ color: "var(--header-primary)" }} tag="h2">
|
||||||
|
Vesktop Settings
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<SettingsSections />
|
||||||
|
</Forms.FormSection>
|
||||||
|
);
|
||||||
|
}
|
62
src/renderer/components/settings/VencordLocationPicker.tsx
Normal file
62
src/renderer/components/settings/VencordLocationPicker.tsx
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Button, Forms, Toasts } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
|
import { SettingsComponent } from "./Settings";
|
||||||
|
|
||||||
|
export const VencordLocationPicker: SettingsComponent = ({ settings }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Forms.FormText>
|
||||||
|
Vencord files are loaded from{" "}
|
||||||
|
{settings.vencordDir ? (
|
||||||
|
<a
|
||||||
|
href="about:blank"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
VesktopNative.fileManager.showItemInFolder(settings.vencordDir!);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{settings.vencordDir}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
"the default location"
|
||||||
|
)}
|
||||||
|
</Forms.FormText>
|
||||||
|
<div className="vcd-location-btns">
|
||||||
|
<Button
|
||||||
|
size={Button.Sizes.SMALL}
|
||||||
|
onClick={async () => {
|
||||||
|
const choice = await VesktopNative.fileManager.selectVencordDir();
|
||||||
|
switch (choice) {
|
||||||
|
case "cancelled":
|
||||||
|
return;
|
||||||
|
case "invalid":
|
||||||
|
Toasts.show({
|
||||||
|
message:
|
||||||
|
"You did not choose a valid Vencord install. Make sure you're selecting the dist dir!",
|
||||||
|
id: Toasts.genId(),
|
||||||
|
type: Toasts.Type.FAILURE
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settings.vencordDir = choice;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Change
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size={Button.Sizes.SMALL}
|
||||||
|
color={Button.Colors.RED}
|
||||||
|
onClick={() => (settings.vencordDir = void 0)}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
48
src/renderer/components/settings/WindowZoom.tsx
Normal file
48
src/renderer/components/settings/WindowZoom.tsx
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Margins } from "@vencord/types/utils";
|
||||||
|
import { Forms, Slider, useEffect, useState } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
|
import { SettingsComponent } from "./Settings";
|
||||||
|
|
||||||
|
export const WindowZoom: SettingsComponent = ({ settings }) => {
|
||||||
|
const [zoomFactor, setZoomFactor] = useState(settings.zoomFactor ?? 1);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleZoomChange = event => {
|
||||||
|
console.log("zoom changed", event.detail);
|
||||||
|
setZoomFactor(event.detail);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("zoomChanged", handleZoomChange);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("zoomChanged", handleZoomChange);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Forms.FormTitle className={Margins.top16 + " " + Margins.bottom8}>Zoom Level</Forms.FormTitle>
|
||||||
|
<Slider
|
||||||
|
className={Margins.top20}
|
||||||
|
initialValue={zoomFactor}
|
||||||
|
defaultValue={1}
|
||||||
|
onValueChange={v => {
|
||||||
|
settings.zoomFactor = v;
|
||||||
|
VesktopNative.win.zoom(v);
|
||||||
|
setZoomFactor(v);
|
||||||
|
}}
|
||||||
|
minValue={0.5}
|
||||||
|
maxValue={2}
|
||||||
|
markers={[0.5, 0.67, 0.75, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2]}
|
||||||
|
stickToMarkers={true}
|
||||||
|
onMarkerRender={v => (v === 1 ? "100" : `${Math.round(v * 100)}`)}
|
||||||
|
></Slider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Margins } from "@vencord/types/utils";
|
||||||
|
import { Forms, Select } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
|
import { SettingsComponent } from "./Settings";
|
||||||
|
|
||||||
|
export const WindowsTransparencyControls: SettingsComponent = ({ settings }) => {
|
||||||
|
if (!VesktopNative.app.supportsWindowsTransparency()) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Forms.FormTitle className={Margins.top16 + " " + Margins.bottom8}>Transparency Options</Forms.FormTitle>
|
||||||
|
<Forms.FormText className={Margins.bottom8}>
|
||||||
|
Requires a full restart. You will need a theme that supports transparency for this to work.
|
||||||
|
</Forms.FormText>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
placeholder="None"
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: "None",
|
||||||
|
value: "none",
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Mica (incorporates system theme + desktop wallpaper to paint the background)",
|
||||||
|
value: "mica"
|
||||||
|
},
|
||||||
|
{ label: "Tabbed (variant of Mica with stronger background tinting)", value: "tabbed" },
|
||||||
|
{
|
||||||
|
label: "Acrylic (blurs the window behind Vesktop for a translucent background)",
|
||||||
|
value: "acrylic"
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
closeOnSelect={true}
|
||||||
|
select={v => (settings.transparencyOption = v)}
|
||||||
|
isSelected={v => v === settings.transparencyOption}
|
||||||
|
serialize={s => s}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Forms.FormDivider className={Margins.top16 + " " + Margins.bottom16} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -4,3 +4,11 @@
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vcd-settings-section {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vcd-settings-title {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ export * as Components from "./components";
|
||||||
import { findByPropsLazy } from "@vencord/types/webpack";
|
import { findByPropsLazy } from "@vencord/types/webpack";
|
||||||
import { FluxDispatcher } from "@vencord/types/webpack/common";
|
import { FluxDispatcher } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
import SettingsUi from "./components/Settings";
|
import SettingsUi from "./components/settings/Settings";
|
||||||
import { Settings } from "./settings";
|
import { Settings } from "./settings";
|
||||||
export { Settings };
|
export { Settings };
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
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 { ContextMenu, FluxDispatcher, Menu } from "@vencord/types/webpack/common";
|
import { FluxDispatcher, Menu, useStateFromStores } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
import { addPatch } from "./shared";
|
import { addPatch } from "./shared";
|
||||||
|
|
||||||
|
@ -46,7 +46,8 @@ addPatch({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addContextMenuPatch("textarea-context", children => () => {
|
addContextMenuPatch("textarea-context", children => {
|
||||||
|
const spellCheckEnabled = useStateFromStores([SpellCheckStore], () => SpellCheckStore.isEnabled());
|
||||||
const hasCorrections = Boolean(word && corrections?.length);
|
const hasCorrections = Boolean(word && corrections?.length);
|
||||||
|
|
||||||
children.push(
|
children.push(
|
||||||
|
@ -71,11 +72,9 @@ addContextMenuPatch("textarea-context", children => () => {
|
||||||
<Menu.MenuCheckboxItem
|
<Menu.MenuCheckboxItem
|
||||||
id="vcd-spellcheck-enabled"
|
id="vcd-spellcheck-enabled"
|
||||||
label="Enable Spellcheck"
|
label="Enable Spellcheck"
|
||||||
checked={SpellCheckStore.isEnabled()}
|
checked={spellCheckEnabled}
|
||||||
action={() => {
|
action={() => {
|
||||||
FluxDispatcher.dispatch({ type: "SPELLCHECK_TOGGLE" });
|
FluxDispatcher.dispatch({ type: "SPELLCHECK_TOGGLE" });
|
||||||
// Haven't found a good way to update state, so just close for now 🤷♀️
|
|
||||||
ContextMenu.close();
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Menu.MenuGroup>
|
</Menu.MenuGroup>
|
||||||
|
|
|
@ -81,7 +81,7 @@ export async function checkUpdates() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const raw = await githubGet("/repos/Vencord/Vesktop/releases/latest");
|
const raw = await githubGet("/repos/Vencord/Vesktop/releases/latest");
|
||||||
const data = JSON.parse(raw.toString("utf-8")) as ReleaseData;
|
const data: ReleaseData = await raw.json();
|
||||||
|
|
||||||
const oldVersion = app.getVersion();
|
const oldVersion = app.getVersion();
|
||||||
const newVersion = data.tag_name.replace(/^v/, "");
|
const newVersion = data.tag_name.replace(/^v/, "");
|
||||||
|
|
Reference in a new issue