diff --git a/src/main/firstLaunch.ts b/src/main/firstLaunch.ts new file mode 100644 index 0000000..fcd74a8 --- /dev/null +++ b/src/main/firstLaunch.ts @@ -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(); + }); +} diff --git a/src/main/index.ts b/src/main/index.ts index 4101a96..4730d63 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -7,17 +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 { initArRPC } from "./arrpc"; -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(); @@ -26,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 --> @@ -59,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(); @@ -79,24 +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(); - } - }); - - initArRPC(); +async function bootstrap() { + if (!Object.hasOwn(Settings.store, "firstLaunch")) { + createFirstLaunchTour(); + } else { + createWindows(); + } } app.on("window-all-closed", () => { diff --git a/src/main/mainWindow.ts b/src/main/mainWindow.ts index 35c6297..34a72cd 100644 --- a/src/main/mainWindow.ts +++ b/src/main/mainWindow.ts @@ -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; @@ -213,7 +216,7 @@ function initSettingsListeners(win: BrowserWindow) { }); } -export function createMainWindow() { +function createMainWindow() { const win = (mainWin = new BrowserWindow({ show: false, autoHideMenuBar: true, @@ -266,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(); +} diff --git a/src/shared/settings.d.ts b/src/shared/settings.d.ts index 1b3fb49..623e054 100644 --- a/src/shared/settings.d.ts +++ b/src/shared/settings.d.ts @@ -19,4 +19,6 @@ export interface Settings { skippedUpdate?: string; staticTitle?: boolean; arRPC?: boolean; + + firstLaunch?: boolean; } diff --git a/static/first-launch.html b/static/first-launch.html new file mode 100644 index 0000000..d54f3a9 --- /dev/null +++ b/static/first-launch.html @@ -0,0 +1,125 @@ + + + + + +

Welcome to Vencord Desktop

+

Let's customise your experience!

+ +
+ + + + + +
+
+ + +
+ + +