11 Commits

Author SHA1 Message Date
V
4c34f10bb2 bump to v.0.2.1 2023-06-21 14:47:25 +02:00
V
684f3330e9 Fix updater file logic 2023-06-21 14:46:40 +02:00
V
178bb0c012 Add first launch tour (#38) 2023-06-21 14:39:41 +02:00
V
39cc30de53 Add arRPC integration 2023-06-09 22:47:59 +02:00
Priultimus
aae4223294 Add MacOs arm64 build (#37) 2023-05-24 03:02:30 +02:00
V
bddfa60f19 Update README.md 2023-05-05 01:30:11 +02:00
V
58b10cfcfe Update README.md 2023-05-05 01:29:24 +02:00
Vendicated
36a751bb7b v0.2.0 2023-05-03 04:14:03 +02:00
Vendicated
6a67f07a9e Add portable target 2023-05-03 04:13:43 +02:00
V
c43871950c Update README.md 2023-04-28 02:38:59 +02:00
Vendicated
fe70701de8 Fix zoom & about menu items; add version to about page 2023-04-27 02:23:17 +02:00
14 changed files with 341 additions and 52 deletions

View File

@@ -1,8 +1,16 @@
# Vencord Desktop
A standalone Electron app that loads Discord & Vencord
Vencord Desktop is a cross platform desktop app aiming to give you a snappier Discord experience with Vencord pre-installed
Vencord Desktop is currently in very early alpha. Bug reports, feature requests & contributions are highly appreciated!!
Vencord Desktop is currently in beta
**Not yet supported**:
- Screensharing
- Global Keybinds
Bug reports, feature requests & contributions are highly appreciated!!
![image](https://user-images.githubusercontent.com/45497981/235024615-94565eaf-f412-4384-a3f5-d8cde7458f6d.png)
## Installing

View File

@@ -1,6 +1,6 @@
{
"name": "VencordDesktop",
"version": "0.1.9",
"version": "0.2.1",
"private": true,
"description": "",
"keywords": [],
@@ -80,11 +80,33 @@
}
},
"mac": {
"target": [
{
"target": "default",
"arch": [
"x64",
"arm64"
]
}
],
"category": "Network"
},
"nsis": {
"include": "build/installer.nsh",
"oneClick": false
},
"win": {
"target": [
"nsis",
"portable"
]
},
"publish": {
"provider": "github",
"releaseType": "release"
}
},
"dependencies": {
"arrpc": "^3.1.0"
}
}

27
pnpm-lock.yaml generated
View File

@@ -1,5 +1,10 @@
lockfileVersion: '6.0'
dependencies:
arrpc:
specifier: ^3.1.0
version: 3.1.0
devDependencies:
'@fal-works/esbuild-plugin-global-externals':
specifier: ^2.1.2
@@ -889,6 +894,15 @@ packages:
es-shim-unscopables: 1.0.0
dev: true
/arrpc@3.1.0:
resolution: {integrity: sha512-QKagtB5fUDqDXT31tTUzcG3+rFxsMlrjKb3iE68/b2NbT1c6+0WYkkrJh4GaVPqH0Tlqy13sEgPW3XJ/VNmBDQ==}
dependencies:
ws: 8.13.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: false
/asar@3.2.0:
resolution: {integrity: sha512-COdw2ZQvKdFGFxXwX3oYh2/sOsJWJegrdJCGxnN4MZ7IULgRBp9P6665aqj9z1v9VwP4oP1hRBojRDQ//IGgAg==}
engines: {node: '>=10.12.0'}
@@ -3785,6 +3799,19 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/ws@8.13.0:
resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: false
/xmlbuilder@15.1.1:
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
engines: {node: '>=8.0'}

View File

@@ -4,7 +4,8 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { BrowserWindow } from "electron";
import { app, BrowserWindow } from "electron";
import { readFileSync } from "fs";
import { join } from "path";
import { ICON_PATH, STATIC_DIR } from "shared/paths";
@@ -19,7 +20,9 @@ export function createAboutWindow() {
makeLinksOpenExternally(about);
about.loadFile(join(STATIC_DIR, "about.html"));
const html = readFileSync(join(STATIC_DIR, "about.html"), "utf-8").replaceAll("%VERSION%", app.getVersion());
about.loadURL("data:text/html;charset=utf-8," + html);
return about;
}

21
src/main/arrpc.ts Normal file
View File

@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import Server from "arrpc";
import { send as sendToBridge } from "arrpc/src/bridge";
import { Settings } from "./settings";
let server: any;
export async function initArRPC() {
if (server || !Settings.store.arRPC) return;
server = await new Server();
server.on("activity", sendToBridge);
}
Settings.addChangeListener("arRPC", initArRPC);

57
src/main/firstLaunch.ts Normal file
View File

@@ -0,0 +1,57 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { app } from "electron";
import { BrowserWindow } from "electron/main";
import { copyFileSync, mkdirSync, readdirSync } from "fs";
import { join } from "path";
import { SplashProps } from "shared/browserWinProperties";
import { STATIC_DIR } from "shared/paths";
import { DATA_DIR } from "./constants";
import { createWindows } from "./mainWindow";
import { Settings } from "./settings";
export function createFirstLaunchTour() {
const win = new BrowserWindow({
...SplashProps,
frame: true,
autoHideMenuBar: true,
height: 320,
width: 550
});
win.loadFile(join(STATIC_DIR, "first-launch.html"));
win.webContents.addListener("console-message", (_e, _l, msg) => {
if (msg === "cancel") return app.exit();
if (!msg.startsWith("form:")) return;
const data = JSON.parse(msg.slice(5));
Settings.store.minimizeToTray = data.minimizeToTray;
Settings.store.discordBranch = data.discordBranch;
Settings.store.firstLaunch = false;
if (data.importSettings) {
const from = join(app.getPath("userData"), "..", "Vencord", "settings");
const to = join(DATA_DIR, "settings");
try {
const files = readdirSync(from);
mkdirSync(to, { recursive: true });
for (const file of files) {
copyFileSync(join(from, file), join(to, file));
}
} catch (e) {
console.error("Failed to import settings:", e);
}
}
win.close();
createWindows();
});
}

View File

@@ -7,16 +7,13 @@
import "./ipc";
import { app, BrowserWindow } from "electron";
import { join } from "path";
import { checkUpdates } from "updater/main";
import { ICON_PATH } from "../shared/paths";
import { once } from "../shared/utils/once";
import { DATA_DIR, VENCORD_FILES_DIR } from "./constants";
import { createMainWindow } from "./mainWindow";
import { DATA_DIR } from "./constants";
import { createFirstLaunchTour } from "./firstLaunch";
import { createWindows, mainWin } from "./mainWindow";
import { Settings } from "./settings";
import { createSplashWindow } from "./splash";
import { ensureVencordFiles } from "./utils/vencordLoader";
if (IS_DEV) {
require("source-map-support").install();
@@ -25,10 +22,6 @@ if (IS_DEV) {
// Make the Vencord files use our DATA_DIR
process.env.VENCORD_USER_DATA_DIR = DATA_DIR;
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
let mainWin: BrowserWindow | null = null;
function init() {
// <-- BEGIN COPY PASTED FROM DISCORD -->
@@ -58,7 +51,7 @@ function init() {
if (process.platform === "win32") app.setAppUserModelId("dev.vencord.desktop");
else if (process.platform === "darwin") app.dock.setIcon(ICON_PATH);
createWindows();
bootstrap();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindows();
@@ -78,22 +71,12 @@ if (!app.requestSingleInstanceLock({ IS_DEV })) {
init();
}
async function createWindows() {
const splash = createSplashWindow();
await ensureVencordFiles();
runVencordMain();
mainWin = createMainWindow();
mainWin.once("ready-to-show", () => {
splash.destroy();
mainWin!.show();
if (Settings.store.maximized) {
mainWin!.maximize();
}
});
async function bootstrap() {
if (!Object.hasOwn(Settings.store, "firstLaunch")) {
createFirstLaunchTour();
} else {
createWindows();
}
}
app.on("window-all-closed", () => {

View File

@@ -6,13 +6,16 @@
import { app, BrowserWindow, BrowserWindowConstructorOptions, Menu, Tray } from "electron";
import { join } from "path";
import { once } from "shared/utils/once";
import { ICON_PATH } from "../shared/paths";
import { createAboutWindow } from "./about";
import { DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH } from "./constants";
import { initArRPC } from "./arrpc";
import { DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH, VENCORD_FILES_DIR } from "./constants";
import { Settings, VencordSettings } from "./settings";
import { createSplashWindow } from "./splash";
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
import { downloadVencordFiles } from "./utils/vencordLoader";
import { downloadVencordFiles, ensureVencordFiles } from "./utils/vencordLoader";
let isQuitting = false;
let tray: Tray;
@@ -88,7 +91,6 @@ function initMenuBar(win: BrowserWindow) {
submenu: [
{
label: "About Vencord Desktop",
role: "about",
click: createAboutWindow
},
{
@@ -125,25 +127,20 @@ function initMenuBar(win: BrowserWindow) {
click() {
app.quit();
}
},
// See https://github.com/electron/electron/issues/14742 and https://github.com/electron/electron/issues/5256
{
label: "Zoom in (hidden, hack for Qwertz and others)",
accelerator: "CmdOrCtrl+=",
role: "zoomIn",
visible: false
}
]
},
{ role: "fileMenu" },
{ role: "editMenu" },
{ role: "viewMenu" },
{ role: "windowMenu" },
{
label: "Zoom",
submenu: [
// See https://github.com/electron/electron/issues/14742 and https://github.com/electron/electron/issues/5256
{
label: "Zoom in",
accelerator: "CmdOrCtrl+=",
role: "zoomIn"
}
],
visible: false
}
{ role: "windowMenu" }
]);
Menu.setApplicationMenu(menu);
@@ -219,7 +216,7 @@ function initSettingsListeners(win: BrowserWindow) {
});
}
export function createMainWindow() {
function createMainWindow() {
const win = (mainWin = new BrowserWindow({
show: false,
autoHideMenuBar: true,
@@ -272,3 +269,25 @@ export function createMainWindow() {
return win;
}
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
export async function createWindows() {
const splash = createSplashWindow();
await ensureVencordFiles();
runVencordMain();
mainWin = createMainWindow();
mainWin.once("ready-to-show", () => {
splash.destroy();
mainWin!.show();
if (Settings.store.maximized) {
mainWin!.maximize();
}
});
initArRPC();
}

View File

@@ -22,6 +22,7 @@ export default function SettingsUi() {
true,
() => Settings.tray ?? true
],
["arRPC", "Rich Presence", "Enables Rich Presence via arRPC", false],
[
"disableMinSize",
"Disable minimum window size",

View File

@@ -9,4 +9,17 @@ import "./fixes";
console.log("read if cute :3");
export * as Components from "./components";
export { Settings } from "./settings";
import { Settings } from "./settings";
export { Settings };
const arRPC = Vencord.Plugins.plugins["WebRichPresence (arRPC)"];
arRPC.required = !!Settings.store.arRPC;
Settings.addChangeListener("arRPC", v => {
arRPC.required = !!v;
if (v && !arRPC.started) Vencord.Plugins.startPlugin(arRPC);
else if (arRPC.started) {
Vencord.Plugins.stopPlugin(arRPC);
}
});

View File

@@ -18,4 +18,7 @@ export interface Settings {
minimizeToTray?: boolean;
skippedUpdate?: string;
staticTitle?: boolean;
arRPC?: boolean;
firstLaunch?: boolean;
}

View File

@@ -22,11 +22,18 @@ let updateData: UpdateData;
ipcMain.handle(IpcEvents.UPDATER_GET_DATA, () => updateData);
ipcMain.handle(IpcEvents.UPDATER_DOWNLOAD, () => {
const portable = !!process.env.PORTABLE_EXECUTABLE_FILE;
const { assets } = updateData.release;
const url = (() => {
switch (process.platform) {
case "win32":
return assets.find(a => a.name.endsWith(".exe"))!.browser_download_url;
return assets.find(a => {
if (!a.name.endsWith(".exe")) return false;
const isSetup = a.name.includes("Setup");
return portable ? !isSetup : isSetup;
})!.browser_download_url;
case "darwin":
return assets.find(a => a.name.endsWith(".dmg"))!.browser_download_url;
case "linux":

View File

@@ -13,7 +13,7 @@
</head>
<body>
<h1>About Vencord Desktop</h1>
<h1>Vencord Desktop %VERSION%</h1>
<p>
Vencord Desktop is a free/libre cross platform desktop app aiming to give you a snappier Discord experience with
Vencord pre-installed

125
static/first-launch.html Normal file
View File

@@ -0,0 +1,125 @@
<head>
<style>
:root {
--bg: white;
--fg: black;
--fg-semi-trans: rgb(0 0 0 / 0.2);
}
@media (prefers-color-scheme: dark) {
:root {
--bg: hsl(223 6.7% 20.6%);
--fg: white;
--fg-semi-trans: rgb(255 255 255 / 0.2);
}
}
body {
height: 100vh;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
"Open Sans", "Helvetica Neue", sans-serif;
margin: 0;
padding: 1.5em;
padding-bottom: 1em;
border: 1px solid var(--fg-semi-trans);
border-top: none;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
body,
select {
background: var(--bg);
color: var(--fg);
}
select {
padding: 0.3em;
margin: -0.3em;
border-radius: 6px;
}
h1 {
margin: 0.4em 0 0;
}
p {
margin: 1em 0 2em;
}
form {
display: grid;
gap: 0.5em;
margin: 0;
}
label {
display: flex;
justify-content: space-between;
}
#buttons {
display: flex;
justify-content: end;
gap: 0.5em;
margin-top: auto;
}
button {
padding: 0.6em;
background: red;
color: white;
border-radius: 6px;
border: none;
cursor: pointer;
}
#submit {
background: green;
}
</style>
</head>
<body>
<h1>Welcome to Vencord Desktop</h1>
<p>Let's customise your experience!</p>
<form>
<label>
Discord Branch
<select name="discordBranch">
<option value="stable">stable</option>
<option value="canary">canary</option>
<option value="ptb">ptb</option>
</select>
</label>
<label>
Import Settings from existing Vencord install (if found)
<input type="checkbox" name="importSettings" checked />
</label>
<label>
Minimise to Tray when closing
<input type="checkbox" name="minimizeToTray" checked />
</label>
</form>
<div id="buttons">
<button id="cancel">Cancel</button>
<button id="submit">Submit</button>
</div>
</body>
<script>
cancel.onclick = () => console.info("cancel");
submit.onclick = e => {
const form = document.querySelector("form");
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
console.info("form:" + JSON.stringify(data));
e.preventDefault();
};
</script>