Add first launch tour (#38)
This commit is contained in:
		
							parent
							
								
									39cc30de53
								
							
						
					
					
						commit
						178bb0c012
					
				
					 5 changed files with 222 additions and 33 deletions
				
			
		
							
								
								
									
										57
									
								
								src/main/firstLaunch.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/main/firstLaunch.ts
									
									
									
									
									
										Normal 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(); | ||||
|     }); | ||||
| } | ||||
|  | @ -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", () => { | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										2
									
								
								src/shared/settings.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/shared/settings.d.ts
									
									
									
									
										vendored
									
									
								
							|  | @ -19,4 +19,6 @@ export interface Settings { | |||
|     skippedUpdate?: string; | ||||
|     staticTitle?: boolean; | ||||
|     arRPC?: boolean; | ||||
| 
 | ||||
|     firstLaunch?: boolean; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										125
									
								
								static/first-launch.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								static/first-launch.html
									
									
									
									
									
										Normal 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> | ||||
		Loading…
	
		Reference in a new issue
	
	 V
						V