improved tray icon setting UI

This commit is contained in:
MrGarlic 2024-05-06 03:10:19 -04:00
parent 3e5783e18a
commit 7713a46394
7 changed files with 144 additions and 62 deletions

View file

@ -12,6 +12,7 @@ import { mkdirSync, readFileSync, watch } from "fs";
import { open, readFile } from "fs/promises"; import { open, readFile } from "fs/promises";
import { release } from "os"; import { release } from "os";
import { join } from "path"; import { join } from "path";
import { ICON_PATH } from "shared/paths";
import { debounce } from "shared/utils/debounce"; import { debounce } from "shared/utils/debounce";
import { IpcEvents } from "../shared/IpcEvents"; import { IpcEvents } from "../shared/IpcEvents";
@ -41,6 +42,19 @@ handleSync(
() => process.platform === "win32" && Number(release().split(".").pop()) >= 22621 () => process.platform === "win32" && Number(release().split(".").pop()) >= 22621
); );
handleSync(IpcEvents.GET_TRAY_ICON, () => {
try {
if (!Settings.store.trayIconPath) return nativeImage.createFromPath(ICON_PATH).toDataURL();
const img = nativeImage.createFromPath(Settings.store.trayIconPath).resize({ width: 64, height: 64 });
if (img.isEmpty()) return nativeImage.createFromPath(ICON_PATH).toDataURL();
return img.toDataURL();
} catch (error) {
return "no";
}
});
handleSync(IpcEvents.AUTOSTART_ENABLED, () => autoStart.isEnabled()); handleSync(IpcEvents.AUTOSTART_ENABLED, () => autoStart.isEnabled());
handle(IpcEvents.ENABLE_AUTOSTART, autoStart.enable); handle(IpcEvents.ENABLE_AUTOSTART, autoStart.enable);
handle(IpcEvents.DISABLE_AUTOSTART, autoStart.disable); handle(IpcEvents.DISABLE_AUTOSTART, autoStart.disable);
@ -124,13 +138,13 @@ handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
handle(IpcEvents.SELECT_TRAY_ICON, async () => { handle(IpcEvents.SELECT_TRAY_ICON, async () => {
const res = await dialog.showOpenDialog(mainWin!, { const res = await dialog.showOpenDialog(mainWin!, {
properties: ["openFile"], properties: ["openFile"],
filters: [{name: "Image", extensions: ["png", "jpg"]}] filters: [{ name: "Image", extensions: ["png", "jpg"] }]
}); });
if (!res.filePaths.length) return "cancelled"; if (!res.filePaths.length) return "cancelled";
const dir = res.filePaths[0]; const dir = res.filePaths[0];
const image = nativeImage.createFromPath(dir); const image = nativeImage.createFromPath(dir);
if(image.isEmpty()) return "invalid"; if (image.isEmpty()) return "invalid";
return dir; return dir;
}); });

View file

@ -11,8 +11,8 @@ import {
dialog, dialog,
Menu, Menu,
MenuItemConstructorOptions, MenuItemConstructorOptions,
nativeTheme,
nativeImage, nativeImage,
nativeTheme,
Tray Tray
} from "electron"; } from "electron";
import { rm } from "fs/promises"; import { rm } from "fs/promises";
@ -21,6 +21,7 @@ import { IpcEvents } from "shared/IpcEvents";
import { isTruthy } from "shared/utils/guards"; import { isTruthy } from "shared/utils/guards";
import { once } from "shared/utils/once"; import { once } from "shared/utils/once";
import type { SettingsStore } from "shared/utils/SettingsStore"; import type { SettingsStore } from "shared/utils/SettingsStore";
import { ICON_PATH } from "../shared/paths"; import { ICON_PATH } from "../shared/paths";
import { createAboutWindow } from "./about"; import { createAboutWindow } from "./about";
import { initArRPC } from "./arrpc"; import { initArRPC } from "./arrpc";
@ -123,7 +124,7 @@ function initTray(win: BrowserWindow) {
tray = new Tray(ICON_PATH); tray = new Tray(ICON_PATH);
if (Settings.store.trayIconPath) { if (Settings.store.trayIconPath) {
const trayImage = nativeImage.createFromPath(Settings.store.trayIconPath); const trayImage = nativeImage.createFromPath(Settings.store.trayIconPath);
if (!trayImage.isEmpty()) tray.setImage(trayImage.resize({width: 32, height: 32})); if (!trayImage.isEmpty()) tray.setImage(trayImage.resize({ width: 32, height: 32 }));
} }
tray.setToolTip("Vesktop"); tray.setToolTip("Vesktop");

View file

@ -57,6 +57,9 @@ export const VesktopNative = {
minimize: () => invoke<void>(IpcEvents.MINIMIZE), minimize: () => invoke<void>(IpcEvents.MINIMIZE),
maximize: () => invoke<void>(IpcEvents.MAXIMIZE) maximize: () => invoke<void>(IpcEvents.MAXIMIZE)
}, },
tray: {
getTrayIcon: () => sendSync<string>(IpcEvents.GET_TRAY_ICON)
},
capturer: { capturer: {
getLargeThumbnail: (id: string) => invoke<string>(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, id) getLargeThumbnail: (id: string) => invoke<string>(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, id)
}, },

View file

@ -14,8 +14,8 @@ import { isMac, isWindows } from "renderer/utils";
import { AutoStartToggle } from "./AutoStartToggle"; import { AutoStartToggle } from "./AutoStartToggle";
import { DiscordBranchPicker } from "./DiscordBranchPicker"; import { DiscordBranchPicker } from "./DiscordBranchPicker";
import { NotificationBadgeToggle } from "./NotificationBadgeToggle"; import { NotificationBadgeToggle } from "./NotificationBadgeToggle";
import { VencordLocationPicker } from "./VencordLocationPicker";
import { TrayIconImagePicker } from "./TrayIconImagePicker"; import { TrayIconImagePicker } from "./TrayIconImagePicker";
import { VencordLocationPicker } from "./VencordLocationPicker";
import { WindowsTransparencyControls } from "./WindowsTransparencyControls"; import { WindowsTransparencyControls } from "./WindowsTransparencyControls";
interface BooleanSetting { interface BooleanSetting {
@ -69,13 +69,6 @@ const SettingsOptions: Record<string, Array<BooleanSetting | SettingsComponent>>
WindowsTransparencyControls WindowsTransparencyControls
], ],
Behaviour: [ Behaviour: [
{
key: "tray",
title: "Tray Icon",
description: "Add a tray icon for Vesktop",
defaultValue: true,
invisible: () => isMac
},
{ {
key: "minimizeToTray", key: "minimizeToTray",
title: "Minimize to tray", title: "Minimize to tray",
@ -128,7 +121,7 @@ const SettingsOptions: Record<string, Array<BooleanSetting | SettingsComponent>>
} }
], ],
"Tray Icon Image": [TrayIconImagePicker], "Tray Icon Image": [TrayIconImagePicker],
"Vencord Location": [VencordLocationPicker], "Vencord Location": [VencordLocationPicker]
}; };
function SettingsSections() { function SettingsSections() {

View file

@ -4,58 +4,69 @@
* Copyright (c) 2023 Vendicated and Vencord contributors * Copyright (c) 2023 Vendicated and Vencord contributors
*/ */
import { Button, Forms, Toasts } from "@vencord/types/webpack/common"; import { Forms, Switch, Toasts } from "@vencord/types/webpack/common";
import { Settings } from "renderer/settings";
import { SettingsComponent } from "./Settings"; import { SettingsComponent } from "./Settings";
export const TrayIconImagePicker: SettingsComponent = ({ settings }) => { export const TrayIconImagePicker: SettingsComponent = ({ settings }) => {
return ( return (
<> <>
<Forms.FormText> <div id="tray-setting">
Tray icon is currently {" "} <div id="colLeft">
{settings.trayIconPath ? ( <Switch
<a key="tray"
href="about:blank" value={Settings.store.tray ?? false}
onClick={e => { onChange={v => (Settings.store.tray = v)}
e.preventDefault(); note={"Add a tray icon for Vesktop"}
VesktopNative.fileManager.showItemInFolder(settings.trayIconPath!);
}}
> >
{settings.trayIconPath} {"Tray Icon"}
</a> </Switch>
) : ( </div>
"the default location" <div id="colMiddle">
)} <Forms.FormText>
</Forms.FormText> <a
<div className="vcd-location-btns"> href="about:blank"
<Button onClick={e => {
size={Button.Sizes.SMALL} e.preventDefault();
onClick={async () => { settings.trayIconPath = void 0;
const choice = await VesktopNative.fileManager.selectTrayIcon(); }}
switch (choice) { >
case "cancelled": Reset
return; </a>
case "invalid": </Forms.FormText>
Toasts.show({ </div>
message: <div id="colRight">
"Please select a valid .png or .jpg image!", <div className="tray-icon-wrap">
id: Toasts.genId(), <img
type: Toasts.Type.FAILURE className="tray-icon-image"
}); src={VesktopNative.tray.getTrayIcon()}
return; alt="hello"
} width="48"
settings.trayIconPath = choice; height="48"
}} ></img>
> <input
Change className="edit-button"
</Button> type="image"
<Button src="https://cdn.discordapp.com/attachments/895550066453012480/1236925384482619433/I1oxwE7.png?ex=6639c808&is=66387688&hm=5c5f47a0c06b2e0580fd5494386bfbeebc001c20e3fd64f26783f360b12162ed&"
size={Button.Sizes.SMALL} onClick={async () => {
color={Button.Colors.RED} const choice = await VesktopNative.fileManager.selectTrayIcon();
onClick={() => (settings.trayIconPath = void 0)} switch (choice) {
> case "cancelled":
Reset return;
</Button> case "invalid":
Toasts.show({
message: "Please select a valid .png or .jpg image!",
id: Toasts.genId(),
type: Toasts.Type.FAILURE
});
return;
}
settings.trayIconPath = choice;
}}
/>
</div>
</div>
</div> </div>
</> </>
); );

View file

@ -12,3 +12,61 @@
.vcd-settings-title { .vcd-settings-title {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.tray-icon-wrap {
position: relative;
top: 0;
right: 0;
}
.tray-icon-image {
border-radius: 50%;
position: relative;
top: 0;
right: 0;
}
.edit-button {
visibility: visible;
display: block;
opacity: 0;
position: absolute;
top: 4px;
left: 4px;
}
.tray-icon-wrap:hover .tray-icon-image {
transition: 0.3s ease;
background-color: rgb(0, 0, 0) no-repeat;
opacity: 0.25;
}
.tray-icon-wrap:hover .edit-button {
transition: 0.3s ease;
visibility: visible;
opacity: 1;
}
#tray-setting {
height: 48px;
position: relative;
}
#colLeft {
height: 48px;
display: inline-block;
width: 40%;
}
#colMiddle {
height: 48px;
float: center;
display: inline;
position: relative;
left: 45%;
}
#colRight {
height: 48px;
display: inline;
float: right;
position: absolute;
top: -12px;
right: 0;
}

View file

@ -24,7 +24,9 @@ export const enum IpcEvents {
SET_SETTINGS = "VCD_SET_SETTINGS", SET_SETTINGS = "VCD_SET_SETTINGS",
SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR", SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR",
SELECT_TRAY_ICON = "VCD_SELECT_TRAY_ICON", SELECT_TRAY_ICON = "VCD_SELECT_TRAY_ICON",
GET_TRAY_ICON = "VCD_GET_TRAY_ICON",
UPDATER_GET_DATA = "VCD_UPDATER_GET_DATA", UPDATER_GET_DATA = "VCD_UPDATER_GET_DATA",
UPDATER_DOWNLOAD = "VCD_UPDATER_DOWNLOAD", UPDATER_DOWNLOAD = "VCD_UPDATER_DOWNLOAD",