/* * 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 { Margins } from "@vencord/types/utils"; import { Button, Forms, Select, Switch, Text, Toasts, useState } from "@vencord/types/webpack/common"; import { setBadge } from "renderer/appBadge"; import { useSettings } from "renderer/settings"; import { isMac, isWindows } from "renderer/utils"; import { isTruthy } from "shared/utils/guards"; export default function SettingsUi() { const Settings = useSettings(); const supportsWindowsTransparency = VesktopNative.app.supportsWindowsTransparency(); const { autostart } = VesktopNative; const [autoStartEnabled, setAutoStartEnabled] = useState(autostart.isEnabled()); const allSwitches: Array< false | [keyof typeof Settings, string, string, boolean?, (() => boolean)?, ((value: boolean) => void)?] > = [ isWindows && [ "discordWindowsTitleBar", "Discord Titlebar", "Use Discord's custom title bar instead of the Windows one. Requires a full restart." ], ["arRPC", "Rich Presence", "Enables Rich Presence via arRPC", false], [ "disableMinSize", "Disable minimum window size", "Allows you to make the window as small as your heart desires" ], ["staticTitle", "Static Title", 'Makes the window title "Vesktop" instead of changing to the current page'], ["enableMenu", "Enable Menu Bar", "Enables the application menu bar. Press ALT to toggle visibility."], ["disableSmoothScroll", "Disable smooth scrolling", "Disables smooth scrolling in Vesktop", false], ["hardwareAcceleration", "Hardware Acceleration", "Enable hardware acceleration", true], ["splashTheming", "Splash theming", "Adapt the splash window colors to your custom theme", false], [ "openLinksWithElectron", "Open Links in app (experimental)", "Opens links in a new Vesktop window instead of your web browser" ], ["checkUpdates", "Check for updates", "Automatically check for Vesktop updates", true] ]; const switches = allSwitches.filter(isTruthy); return ( <Forms.FormSection> <Text variant="heading-lg/semibold" style={{ color: "var(--header-primary)" }} tag="h2"> Vesktop Settings </Text> <Forms.FormTitle className={Margins.top16 + " " + Margins.bottom8}>Discord Branch</Forms.FormTitle> <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} /> <Forms.FormDivider className={Margins.top16 + " " + Margins.bottom16} /> <Switch value={autoStartEnabled} onChange={async v => { await autostart[v ? "enable" : "disable"](); setAutoStartEnabled(v); }} note="Automatically start Vesktop on computer start-up" > Start With System </Switch> <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 (taskbar/panel) icon" > Notification Badge </Switch> {!isMac && ( <> <Switch value={Settings.tray ?? true} onChange={v => { Settings.tray = v; if (v && Settings.trayBadge) setBadge(); }} note="Add a tray icon for Vesktop" key="tray" > Tray Icon </Switch> <Switch value={Settings.minimizeToTray ?? true} onChange={v => (Settings.minimizeToTray = v)} disabled={!(Settings.tray ?? true)} note="Hitting X will make Vesktop minimize to the tray instead of closing" key="minimizeToTray" > Minimize to Tray </Switch> <Switch value={Settings.trayBadge ?? true} onChange={v => { Settings.trayBadge = v; if (v) setBadge(); else VesktopNative.app.setBadgeCount(0); }} disabled={!(Settings.tray ?? true)} note="Show mention badge on the tray icon" key="trayBadge" > Tray Notification Badge </Switch> </> )} {switches.map(([key, text, note, def, predicate]) => ( <Switch value={(Settings[key as any] ?? def ?? false) && predicate?.() !== false} disabled={predicate && !predicate()} onChange={v => (Settings[key as any] = v)} note={note} key={key} > {text} </Switch> ))} {supportsWindowsTransparency && ( <> <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} /> </> )} <Forms.FormTitle>Vencord Location</Forms.FormTitle> <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> </Forms.FormSection> ); }