feat: save icons into vesktop cache
This commit is contained in:
parent
1e5d25c943
commit
74e3902545
6 changed files with 74 additions and 28 deletions
|
@ -28,7 +28,7 @@ import { IpcEvents } from "../shared/IpcEvents";
|
||||||
import { setBadgeCount } from "./appBadge";
|
import { setBadgeCount } from "./appBadge";
|
||||||
import { autoStart } from "./autoStart";
|
import { autoStart } from "./autoStart";
|
||||||
import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE, VENCORD_THEMES_DIR } from "./constants";
|
import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE, VENCORD_THEMES_DIR } from "./constants";
|
||||||
import { getTrayIconFile, mainWin, setTrayIcon } from "./mainWindow";
|
import { createTrayIcon, generateTrayIcons, getTrayIconFile, mainWin, setTrayIcon } from "./mainWindow";
|
||||||
import { Settings } from "./settings";
|
import { Settings } from "./settings";
|
||||||
import { handle, handleSync } from "./utils/ipcWrappers";
|
import { handle, handleSync } from "./utils/ipcWrappers";
|
||||||
import { PopoutWindows } from "./utils/popout";
|
import { PopoutWindows } from "./utils/popout";
|
||||||
|
@ -163,3 +163,5 @@ watch(
|
||||||
handle(IpcEvents.SET_TRAY_ICON, (_, iconURI) => setTrayIcon(iconURI));
|
handle(IpcEvents.SET_TRAY_ICON, (_, iconURI) => setTrayIcon(iconURI));
|
||||||
handle(IpcEvents.GET_TRAY_ICON, (_, iconName) => getTrayIconFile(iconName));
|
handle(IpcEvents.GET_TRAY_ICON, (_, iconName) => getTrayIconFile(iconName));
|
||||||
handle(IpcEvents.GET_SYSTEM_ACCENT_COLOR, () => `#${systemPreferences.getAccentColor?.() || ""}`);
|
handle(IpcEvents.GET_SYSTEM_ACCENT_COLOR, () => `#${systemPreferences.getAccentColor?.() || ""}`);
|
||||||
|
handle(IpcEvents.CREATE_TRAY_ICON_RESPONSE, (_, iconName, dataURL) => createTrayIcon(iconName, dataURL));
|
||||||
|
handle(IpcEvents.GENERATE_TRAY_ICONS, () => generateTrayIcons());
|
||||||
|
|
|
@ -11,12 +11,12 @@ import {
|
||||||
dialog,
|
dialog,
|
||||||
Menu,
|
Menu,
|
||||||
MenuItemConstructorOptions,
|
MenuItemConstructorOptions,
|
||||||
nativeImage,
|
|
||||||
nativeTheme,
|
nativeTheme,
|
||||||
screen,
|
screen,
|
||||||
session,
|
session,
|
||||||
Tray
|
Tray
|
||||||
} from "electron";
|
} from "electron";
|
||||||
|
import { mkdirSync, writeFileSync } from "fs";
|
||||||
import { readFile, rm } from "fs/promises";
|
import { readFile, rm } from "fs/promises";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { IpcEvents } from "shared/IpcEvents";
|
import { IpcEvents } from "shared/IpcEvents";
|
||||||
|
@ -503,10 +503,10 @@ export async function createWindows() {
|
||||||
initArRPC();
|
initArRPC();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setTrayIcon(iconURI: string) {
|
export async function setTrayIcon(iconName: string) {
|
||||||
if (!tray || tray.isDestroyed()) return;
|
if (!tray || tray.isDestroyed()) return;
|
||||||
if (iconURI !== "" && iconURI !== "icon") {
|
if (iconName !== "icon") {
|
||||||
tray.setImage(nativeImage.createFromDataURL(iconURI));
|
tray.setImage(join(DATA_DIR, "TrayIcons", iconName + ".png"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tray.setImage(join(STATIC_DIR, "icon.png"));
|
tray.setImage(join(STATIC_DIR, "icon.png"));
|
||||||
|
@ -514,10 +514,31 @@ export async function setTrayIcon(iconURI: string) {
|
||||||
|
|
||||||
export async function getTrayIconFile(iconName: string) {
|
export async function getTrayIconFile(iconName: string) {
|
||||||
const Icons = new Set(["speaking", "muted", "deafened", "idle"]);
|
const Icons = new Set(["speaking", "muted", "deafened", "idle"]);
|
||||||
|
// add here checks for user-defined icons
|
||||||
if (!Icons.has(iconName)) {
|
if (!Icons.has(iconName)) {
|
||||||
iconName = "icon";
|
iconName = "icon";
|
||||||
return readFile(join(STATIC_DIR, "icon.png"));
|
return readFile(join(STATIC_DIR, "icon.png"));
|
||||||
}
|
}
|
||||||
return readFile(join(STATIC_DIR, iconName + ".svg"), "utf8");
|
return readFile(join(STATIC_DIR, iconName + ".svg"), "utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createTrayIcon(iconName: string, iconDataURL: string) {
|
||||||
|
iconDataURL = iconDataURL.replace(/^data:image\/png;base64,/, "");
|
||||||
|
writeFileSync(join(DATA_DIR, "TrayIcons", iconName + ".png"), iconDataURL, "base64");
|
||||||
|
mainWin.webContents.send(IpcEvents.SET_CURRENT_VOICE_TRAY_ICON);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateTrayIcons() {
|
||||||
|
// this function generates tray icons as .png's in Vesktop cache for future use
|
||||||
|
mkdirSync(join(DATA_DIR, "TrayIcons"), { recursive: true });
|
||||||
|
const trayIconsColor = Settings.store.trayColor ?? "#3DB77F";
|
||||||
|
const userDefinedIcons = false;
|
||||||
|
if (userDefinedIcons) {
|
||||||
|
} else {
|
||||||
|
const Icons = ["speaking", "muted", "deafened", "idle"];
|
||||||
|
for (const icon of Icons) {
|
||||||
|
mainWin.webContents.send(IpcEvents.CREATE_TRAY_ICON_REQUEST, icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mainWin.webContents.send(IpcEvents.SET_CURRENT_VOICE_TRAY_ICON);
|
||||||
|
}
|
||||||
|
|
|
@ -26,8 +26,6 @@ export const VesktopNative = {
|
||||||
getVersion: () => sendSync<void>(IpcEvents.GET_VERSION),
|
getVersion: () => sendSync<void>(IpcEvents.GET_VERSION),
|
||||||
setBadgeCount: (count: number) => invoke<void>(IpcEvents.SET_BADGE_COUNT, count),
|
setBadgeCount: (count: number) => invoke<void>(IpcEvents.SET_BADGE_COUNT, count),
|
||||||
supportsWindowsTransparency: () => sendSync<boolean>(IpcEvents.SUPPORTS_WINDOWS_TRANSPARENCY),
|
supportsWindowsTransparency: () => sendSync<boolean>(IpcEvents.SUPPORTS_WINDOWS_TRANSPARENCY),
|
||||||
setTrayIcon: (iconURI: string) => invoke<void>(IpcEvents.SET_TRAY_ICON, iconURI),
|
|
||||||
getTrayIcon: (iconName: string) => invoke<string>(IpcEvents.GET_TRAY_ICON, iconName),
|
|
||||||
getAccentColor: () => invoke<string>(IpcEvents.GET_SYSTEM_ACCENT_COLOR)
|
getAccentColor: () => invoke<string>(IpcEvents.GET_SYSTEM_ACCENT_COLOR)
|
||||||
},
|
},
|
||||||
autostart: {
|
autostart: {
|
||||||
|
@ -81,5 +79,18 @@ export const VesktopNative = {
|
||||||
clipboard: {
|
clipboard: {
|
||||||
copyImage: (imageBuffer: Uint8Array, imageSrc: string) =>
|
copyImage: (imageBuffer: Uint8Array, imageSrc: string) =>
|
||||||
invoke<void>(IpcEvents.CLIPBOARD_COPY_IMAGE, imageBuffer, imageSrc)
|
invoke<void>(IpcEvents.CLIPBOARD_COPY_IMAGE, imageBuffer, imageSrc)
|
||||||
|
},
|
||||||
|
tray: {
|
||||||
|
setIcon: (iconURI: string) => invoke<void>(IpcEvents.SET_TRAY_ICON, iconURI),
|
||||||
|
getIcon: (iconName: string) => invoke<string>(IpcEvents.GET_TRAY_ICON, iconName),
|
||||||
|
createIconResponse: (iconName: string, iconDataURL: string) =>
|
||||||
|
invoke<void>(IpcEvents.CREATE_TRAY_ICON_RESPONSE, iconName, iconDataURL),
|
||||||
|
createIconRequest: (listener: (iconName: string) => void) => {
|
||||||
|
ipcRenderer.on(IpcEvents.CREATE_TRAY_ICON_REQUEST, (_, iconName: string) => listener(iconName));
|
||||||
|
},
|
||||||
|
generateTrayIcons: () => invoke<void>(IpcEvents.GENERATE_TRAY_ICONS),
|
||||||
|
setCurrentVoiceIcon: (listener: (...args: any[]) => void) => {
|
||||||
|
ipcRenderer.on(IpcEvents.SET_CURRENT_VOICE_TRAY_ICON, listener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ import "./traySetting.css";
|
||||||
import { Margins } from "@vencord/types/utils";
|
import { Margins } from "@vencord/types/utils";
|
||||||
import { findByCodeLazy } from "@vencord/types/webpack";
|
import { findByCodeLazy } from "@vencord/types/webpack";
|
||||||
import { Forms, Select, Switch } from "@vencord/types/webpack/common";
|
import { Forms, Select, Switch } from "@vencord/types/webpack/common";
|
||||||
import { isInCall, setCurrentTrayIcon } from "renderer/patches/tray";
|
import { setCurrentTrayIcon } from "renderer/patches/tray";
|
||||||
import { isLinux, isMac } from "renderer/utils";
|
import { isLinux, isMac } from "renderer/utils";
|
||||||
|
|
||||||
import { SettingsComponent } from "./Settings";
|
import { SettingsComponent } from "./Settings";
|
||||||
|
@ -40,7 +40,7 @@ export const TraySwitch: SettingsComponent = ({ settings }) => {
|
||||||
value={settings.tray ?? true}
|
value={settings.tray ?? true}
|
||||||
onChange={async v => {
|
onChange={async v => {
|
||||||
settings.tray = v;
|
settings.tray = v;
|
||||||
if (isInCall) setCurrentTrayIcon();
|
setCurrentTrayIcon();
|
||||||
}}
|
}}
|
||||||
note="Add a tray icon for Vesktop"
|
note="Add a tray icon for Vesktop"
|
||||||
>
|
>
|
||||||
|
@ -63,7 +63,7 @@ export const TrayIconPicker: SettingsComponent = ({ settings }) => {
|
||||||
onChange={newColor => {
|
onChange={newColor => {
|
||||||
const hexColor = newColor.toString(16).padStart(6, "0");
|
const hexColor = newColor.toString(16).padStart(6, "0");
|
||||||
settings.trayColor = hexColor;
|
settings.trayColor = hexColor;
|
||||||
if (isInCall) setCurrentTrayIcon();
|
VesktopNative.tray.generateTrayIcons();
|
||||||
}}
|
}}
|
||||||
showEyeDropper={false}
|
showEyeDropper={false}
|
||||||
suggestedColors={presets}
|
suggestedColors={presets}
|
||||||
|
@ -75,6 +75,7 @@ export const TrayIconPicker: SettingsComponent = ({ settings }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TrayFillColorSwitch: SettingsComponent = ({ settings }) => {
|
export const TrayFillColorSwitch: SettingsComponent = ({ settings }) => {
|
||||||
|
if (!settings.tray) return null;
|
||||||
return (
|
return (
|
||||||
<div className="vcd-tray-settings">
|
<div className="vcd-tray-settings">
|
||||||
<div className="vcd-tray-container">
|
<div className="vcd-tray-container">
|
||||||
|
@ -93,7 +94,7 @@ export const TrayFillColorSwitch: SettingsComponent = ({ settings }) => {
|
||||||
closeOnSelect={true}
|
closeOnSelect={true}
|
||||||
select={v => {
|
select={v => {
|
||||||
settings.trayAutoFill = v;
|
settings.trayAutoFill = v;
|
||||||
if (isInCall) setCurrentTrayIcon();
|
VesktopNative.tray.generateTrayIcons();
|
||||||
}}
|
}}
|
||||||
isSelected={v => v === settings.trayAutoFill}
|
isSelected={v => v === settings.trayAutoFill}
|
||||||
serialize={s => s}
|
serialize={s => s}
|
||||||
|
|
|
@ -10,15 +10,27 @@ import { FluxDispatcher, UserStore } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
const voiceActions = findByPropsLazy("isSelfMute");
|
const voiceActions = findByPropsLazy("isSelfMute");
|
||||||
|
|
||||||
export var isInCall = false;
|
var isInCall = false;
|
||||||
const logger = new Logger("VesktopTrayIcon");
|
const logger = new Logger("VesktopTrayIcon");
|
||||||
|
|
||||||
async function changeIconColor(iconName: string) {
|
export function setCurrentTrayIcon() {
|
||||||
|
if (isInCall) {
|
||||||
|
if (voiceActions.isSelfDeaf()) {
|
||||||
|
VesktopNative.tray.setIcon("deafened");
|
||||||
|
} else if (voiceActions.isSelfMute()) {
|
||||||
|
VesktopNative.tray.setIcon("muted");
|
||||||
|
} else {
|
||||||
|
VesktopNative.tray.setIcon("idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VesktopNative.tray.createIconRequest(async (iconName: string) => {
|
||||||
const pickedColor = VesktopNative.settings.get().trayColor;
|
const pickedColor = VesktopNative.settings.get().trayColor;
|
||||||
const fillColor = VesktopNative.settings.get().trayAutoFill ?? "auto";
|
const fillColor = VesktopNative.settings.get().trayAutoFill ?? "auto";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var svg = await VesktopNative.app.getTrayIcon(iconName);
|
var svg = await VesktopNative.tray.getIcon(iconName);
|
||||||
svg = svg.replace(/#f6bfac/gim, "#" + (pickedColor ?? "3DB77F"));
|
svg = svg.replace(/#f6bfac/gim, "#" + (pickedColor ?? "3DB77F"));
|
||||||
if (fillColor !== "auto") {
|
if (fillColor !== "auto") {
|
||||||
svg = svg.replace(/black/gim, fillColor);
|
svg = svg.replace(/black/gim, fillColor);
|
||||||
|
@ -35,32 +47,27 @@ async function changeIconColor(iconName: string) {
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
const dataURL = canvas.toDataURL("image/png");
|
const dataURL = canvas.toDataURL("image/png");
|
||||||
VesktopNative.app.setTrayIcon(dataURL);
|
VesktopNative.tray.createIconResponse(iconName, dataURL);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("Error: ", error);
|
logger.error("Error: ", error);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
export function setCurrentTrayIcon() {
|
VesktopNative.tray.setCurrentVoiceIcon(() => {
|
||||||
if (voiceActions.isSelfDeaf()) {
|
setCurrentTrayIcon();
|
||||||
changeIconColor("deafened");
|
});
|
||||||
} else if (voiceActions.isSelfMute()) {
|
|
||||||
changeIconColor("muted");
|
|
||||||
} else {
|
|
||||||
changeIconColor("idle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onceReady.then(() => {
|
onceReady.then(() => {
|
||||||
|
VesktopNative.tray.generateTrayIcons();
|
||||||
const userID = UserStore.getCurrentUser().id;
|
const userID = UserStore.getCurrentUser().id;
|
||||||
|
|
||||||
FluxDispatcher.subscribe("SPEAKING", params => {
|
FluxDispatcher.subscribe("SPEAKING", params => {
|
||||||
if (params.userId === userID) {
|
if (params.userId === userID) {
|
||||||
if (params.speakingFlags) {
|
if (params.speakingFlags) {
|
||||||
changeIconColor("speaking");
|
VesktopNative.tray.setIcon("speaking");
|
||||||
} else {
|
} else {
|
||||||
setCurrentTrayIcon();
|
setCurrentTrayIcon();
|
||||||
}
|
}
|
||||||
|
@ -80,7 +87,7 @@ onceReady.then(() => {
|
||||||
isInCall = true;
|
isInCall = true;
|
||||||
setCurrentTrayIcon();
|
setCurrentTrayIcon();
|
||||||
} else if (params.state === "RTC_DISCONNECTED") {
|
} else if (params.state === "RTC_DISCONNECTED") {
|
||||||
VesktopNative.app.setTrayIcon("icon");
|
VesktopNative.tray.setIcon("icon");
|
||||||
isInCall = false;
|
isInCall = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,5 +53,9 @@ export const enum IpcEvents {
|
||||||
|
|
||||||
SET_TRAY_ICON = "VCD_SET_TRAY_ICON",
|
SET_TRAY_ICON = "VCD_SET_TRAY_ICON",
|
||||||
GET_TRAY_ICON = "VCD_GET_TRAY_ICON",
|
GET_TRAY_ICON = "VCD_GET_TRAY_ICON",
|
||||||
|
CREATE_TRAY_ICON_REQUEST = "VCD_CREATE_TRAY_ICON_REQUEST",
|
||||||
|
CREATE_TRAY_ICON_RESPONSE = "VCD_CREATE_TRAY_ICON_RESPONSE",
|
||||||
|
GENERATE_TRAY_ICONS = "VCD_GENERATE_TRAY_ICONS",
|
||||||
|
SET_CURRENT_VOICE_TRAY_ICON = "VCD_SET_CURRENT_VOICE_ICON",
|
||||||
GET_SYSTEM_ACCENT_COLOR = "VCD_GET_ACCENT_COLOR"
|
GET_SYSTEM_ACCENT_COLOR = "VCD_GET_ACCENT_COLOR"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue