add equicord tray menu for desktop discord (#694)
This commit is contained in:
parent
bfc9ecb5e7
commit
d69256fb4d
6 changed files with 146 additions and 2 deletions
|
|
@ -135,4 +135,9 @@ window.VencordNative = {
|
|||
|
||||
pluginHelpers: {} as any,
|
||||
csp: {} as any,
|
||||
tray: {
|
||||
setUpdateState: NOOP,
|
||||
onCheckUpdates: NOOP,
|
||||
onRepair: NOOP,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ import { createAndAppendStyle } from "@utils/css";
|
|||
import { StartAt } from "@utils/types";
|
||||
|
||||
import { get as dsGet } from "./api/DataStore";
|
||||
import { showNotice } from "./api/Notices";
|
||||
import { popNotice, showNotice } from "./api/Notices";
|
||||
import { NotificationData, showNotification } from "./api/Notifications";
|
||||
import { initPluginManager, PMLogger, startAllPlugins } from "./api/PluginManager";
|
||||
import { PlainSettings, Settings, SettingsStore } from "./api/Settings";
|
||||
import { getCloudSettings, putCloudSettings, shouldCloudSync } from "./api/SettingsSync/cloudSync";
|
||||
import { localStorage } from "./utils/localStorage";
|
||||
import { relaunch } from "./utils/native";
|
||||
import { checkForUpdates, update, UpdateLogger } from "./utils/updater";
|
||||
import { checkForUpdates, isOutdated as getIsOutdated, update, UpdateLogger } from "./utils/updater";
|
||||
import { onceReady } from "./webpack";
|
||||
import { openUserSettingsPanel } from "./webpack/common";
|
||||
import { patches } from "./webpack/patchWebpack";
|
||||
|
|
@ -141,6 +141,7 @@ async function runUpdateCheck() {
|
|||
|
||||
try {
|
||||
const isOutdated = await checkForUpdates();
|
||||
if (IS_DISCORD_DESKTOP) VencordNative.tray.setUpdateState(isOutdated);
|
||||
if (!isOutdated) return;
|
||||
|
||||
if (Settings.autoUpdate) {
|
||||
|
|
@ -171,11 +172,45 @@ async function runUpdateCheck() {
|
|||
}
|
||||
}
|
||||
|
||||
function initTrayIpc() {
|
||||
if (IS_WEB || IS_UPDATER_DISABLED) return;
|
||||
|
||||
VencordNative.tray.onCheckUpdates(async () => {
|
||||
try {
|
||||
const isOutdated = await checkForUpdates();
|
||||
VencordNative.tray.setUpdateState(isOutdated);
|
||||
|
||||
if (isOutdated) {
|
||||
showNotice("An Equicord update is available!", "View Update", () => openSettingsTabModal(UpdaterTab!));
|
||||
} else {
|
||||
showNotice("No updates available, you're on the latest version!", "OK", popNotice);
|
||||
}
|
||||
} catch (err) {
|
||||
UpdateLogger.error("Failed to check for updates from tray", err);
|
||||
showNotice("Failed to check for updates, check the console for more info", "OK", popNotice);
|
||||
}
|
||||
});
|
||||
|
||||
VencordNative.tray.onRepair(async () => {
|
||||
try {
|
||||
const res = await VencordNative.updater.rebuild();
|
||||
if (!res.ok) throw res.error;
|
||||
|
||||
showNotice("Equicord has been repaired!", "Restart", relaunch);
|
||||
} catch (err) {
|
||||
UpdateLogger.error("Failed to repair Equicord", err);
|
||||
}
|
||||
});
|
||||
|
||||
VencordNative.tray.setUpdateState(getIsOutdated);
|
||||
}
|
||||
|
||||
async function init() {
|
||||
await onceReady;
|
||||
startAllPlugins(StartAt.WebpackReady);
|
||||
|
||||
syncSettings();
|
||||
initTrayIpc();
|
||||
|
||||
if (!IS_DEV && !IS_WEB && !IS_UPDATER_DISABLED) {
|
||||
runUpdateCheck();
|
||||
|
|
|
|||
|
|
@ -98,5 +98,11 @@ export default {
|
|||
invoke<CspRequestResult>(IpcEvents.CSP_REQUEST_ADD_OVERRIDE, url, directives, callerName),
|
||||
},
|
||||
|
||||
tray: {
|
||||
setUpdateState: (available: boolean) => ipcRenderer.send(IpcEvents.SET_TRAY_UPDATE_STATE, available),
|
||||
onCheckUpdates: (cb: () => void) => { ipcRenderer.on(IpcEvents.TRAY_CHECK_UPDATES, cb); },
|
||||
onRepair: (cb: () => void) => { ipcRenderer.on(IpcEvents.TRAY_REPAIR_EQUICORD, cb); },
|
||||
},
|
||||
|
||||
pluginHelpers: PluginHelpers
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import electron, { app, BrowserWindowConstructorOptions, Menu } from "electron";
|
|||
import { dirname, join } from "path";
|
||||
|
||||
import { RendererSettings } from "./settings";
|
||||
import { patchTrayMenu } from "./trayMenu";
|
||||
import { IS_VANILLA } from "./utils/constants";
|
||||
|
||||
console.log("[Equicord] Starting up...");
|
||||
|
|
@ -40,6 +41,9 @@ app.setAppPath(asarPath);
|
|||
|
||||
if (!IS_VANILLA) {
|
||||
const settings = RendererSettings.store;
|
||||
|
||||
patchTrayMenu();
|
||||
|
||||
// Repatch after host updates on Windows
|
||||
if (process.platform === "win32") {
|
||||
require("./patchWin32Updater");
|
||||
|
|
|
|||
90
src/main/trayMenu.ts
Normal file
90
src/main/trayMenu.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2026 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { IpcEvents } from "@shared/IpcEvents";
|
||||
import { BrowserWindow, ipcMain, Menu, MenuItemConstructorOptions, shell } from "electron";
|
||||
|
||||
import { SETTINGS_DIR } from "./utils/constants";
|
||||
|
||||
let cachedUpdateAvailable = false;
|
||||
|
||||
ipcMain.on(IpcEvents.SET_TRAY_UPDATE_STATE, (_, available: boolean) => {
|
||||
cachedUpdateAvailable = available;
|
||||
});
|
||||
|
||||
function getMainWindow(): BrowserWindow | undefined {
|
||||
return BrowserWindow.getFocusedWindow() ?? BrowserWindow.getAllWindows()[0];
|
||||
}
|
||||
|
||||
function sendToRenderer(event: IpcEvents): void {
|
||||
getMainWindow()?.webContents.send(event);
|
||||
}
|
||||
|
||||
function findInsertIndex(template: MenuItemConstructorOptions[]): number {
|
||||
const openIndex = template.findIndex(item => {
|
||||
const label = item.label?.toLowerCase() ?? "";
|
||||
return label.includes("open") || label.includes("show");
|
||||
});
|
||||
return openIndex !== -1 ? openIndex + 1 : 0;
|
||||
}
|
||||
|
||||
function isTrayMenu(template: MenuItemConstructorOptions[]): boolean {
|
||||
if (!template.length) return false;
|
||||
|
||||
const hasOpenOrShow = template.some(item => {
|
||||
const label = item.label?.toLowerCase() ?? "";
|
||||
return label.includes("open") || label.includes("show");
|
||||
});
|
||||
|
||||
const hasQuit = template.some(item =>
|
||||
item.label?.toLowerCase().includes("quit") || item.role === "quit"
|
||||
);
|
||||
|
||||
const isNotAppMenu = !template.some(item =>
|
||||
item.label === "&File" || item.label === "File" ||
|
||||
item.label === "&Edit" || item.label === "Edit"
|
||||
);
|
||||
|
||||
return hasOpenOrShow && hasQuit && isNotAppMenu;
|
||||
}
|
||||
|
||||
function createEquicordMenuItems(): MenuItemConstructorOptions[] {
|
||||
return [
|
||||
{
|
||||
label: "Equicord",
|
||||
submenu: [
|
||||
{
|
||||
label: cachedUpdateAvailable ? "Update Equicord" : "Check for Updates",
|
||||
click: () => sendToRenderer(IpcEvents.TRAY_CHECK_UPDATES)
|
||||
},
|
||||
{
|
||||
label: "Repair Equicord",
|
||||
click: () => sendToRenderer(IpcEvents.TRAY_REPAIR_EQUICORD)
|
||||
},
|
||||
{ type: "separator" },
|
||||
{
|
||||
label: "Open Settings Folder",
|
||||
click: () => shell.openPath(SETTINGS_DIR)
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: "separator" }
|
||||
];
|
||||
}
|
||||
|
||||
export function patchTrayMenu(): void {
|
||||
const originalBuildFromTemplate = Menu.buildFromTemplate;
|
||||
|
||||
Menu.buildFromTemplate = function (template: MenuItemConstructorOptions[]) {
|
||||
if (isTrayMenu(template)) {
|
||||
const insertIndex = findInsertIndex(template);
|
||||
const equicordItems = createEquicordMenuItems();
|
||||
template.splice(insertIndex, 0, ...equicordItems);
|
||||
}
|
||||
|
||||
return originalBuildFromTemplate.call(this, template);
|
||||
};
|
||||
}
|
||||
|
|
@ -51,4 +51,8 @@ export const enum IpcEvents {
|
|||
GET_RENDERER_CSS = "VencordGetRendererCss",
|
||||
RENDERER_CSS_UPDATE = "VencordRendererCssUpdate",
|
||||
PRELOAD_GET_RENDERER_JS = "VencordPreloadGetRendererJs",
|
||||
|
||||
SET_TRAY_UPDATE_STATE = "EquicordSetTrayUpdateState",
|
||||
TRAY_REPAIR_EQUICORD = "EquicordTrayRepairEquicord",
|
||||
TRAY_CHECK_UPDATES = "EquicordTrayCheckUpdates",
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue