mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Compute Tray Icon on the fly instead of at build (#5157)
This commit is contained in:
1 parent
51a93b8cc0
commit
8ada3c7505
11 files changed
+84
-77
No files matched your search
@@ -48,6 +48,17 @@ export function getOrInsertWith<K, V>(map: Map<K, V>, key: K, builder: () => V):
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link getOrInsertWith} but the builder is async and will be awaited before inserting into the map
|
||||
*/
|
||||
export async function getOrInsertWithAsync<K, V>(map: Map<K, V>, key: K, asyncBuilder: () => Promise<V>): Promise<V> {
|
||||
if (!map.has(key)) {
|
||||
map.set(key, await asyncBuilder());
|
||||
}
|
||||
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value associated with `key` iff there was not a previous value
|
||||
* @param map The map to interact with
|
||||
|
||||
+1
-1
@@ -305,7 +305,7 @@ async function main(di: DiContainer) {
|
||||
|
||||
onQuitCleanup.push(
|
||||
initMenu(applicationMenuItems),
|
||||
initTray(windowManager, trayMenuItems, navigateToPreferences),
|
||||
await initTray(windowManager, trayMenuItems, navigateToPreferences),
|
||||
() => ShellSession.cleanup(),
|
||||
);
|
||||
|
||||
|
||||
+68
-20
@@ -3,19 +3,23 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import path from "path";
|
||||
import packageInfo from "../../../package.json";
|
||||
import { Menu, Tray } from "electron";
|
||||
import type { NativeImage } from "electron";
|
||||
import { Menu, nativeImage, nativeTheme, Tray } from "electron";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { autorun } from "mobx";
|
||||
import { showAbout } from "../menu/menu";
|
||||
import { checkForUpdates, isAutoUpdateEnabled } from "../app-updater";
|
||||
import type { WindowManager } from "../window-manager";
|
||||
import logger from "../logger";
|
||||
import { isDevelopment, isWindows, productName, staticFilesDirectory } from "../../common/vars";
|
||||
import { isWindows, productName } from "../../common/vars";
|
||||
import { exitApp } from "../exit-app";
|
||||
import { toJS } from "../../common/utils";
|
||||
import type { Disposer } from "../../common/utils";
|
||||
import { base64, disposer, getOrInsertWithAsync, toJS } from "../../common/utils";
|
||||
import type { TrayMenuRegistration } from "./tray-menu-registration";
|
||||
import sharp from "sharp";
|
||||
import LogoLens from "../../renderer/components/icon/logo-lens.svg";
|
||||
import { JSDOM } from "jsdom";
|
||||
|
||||
|
||||
const TRAY_LOG_PREFIX = "[TRAY]";
|
||||
@@ -23,25 +27,69 @@ const TRAY_LOG_PREFIX = "[TRAY]";
|
||||
// note: instance of Tray should be saved somewhere, otherwise it disappears
|
||||
export let tray: Tray;
|
||||
|
||||
export function getTrayIcon(): string {
|
||||
return path.resolve(
|
||||
staticFilesDirectory,
|
||||
isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras
|
||||
"trayIconTemplate.png",
|
||||
);
|
||||
interface CreateTrayIconArgs {
|
||||
shouldUseDarkColors: boolean;
|
||||
size: number;
|
||||
sourceSvg: string;
|
||||
}
|
||||
|
||||
export function initTray(
|
||||
const trayIcons = new Map<boolean, NativeImage>();
|
||||
|
||||
async function createTrayIcon({ shouldUseDarkColors, size, sourceSvg }: CreateTrayIconArgs): Promise<NativeImage> {
|
||||
return getOrInsertWithAsync(trayIcons, shouldUseDarkColors, async () => {
|
||||
const trayIconColor = shouldUseDarkColors ? "white" : "black"; // Invert to show contrast
|
||||
const parsedSvg = base64.decode(sourceSvg.split("base64,")[1]);
|
||||
const svgDom = new JSDOM(`<body>${parsedSvg}</body>`);
|
||||
const svgRoot = svgDom.window.document.body.getElementsByTagName("svg")[0];
|
||||
|
||||
svgRoot.innerHTML += `<style>* {fill: ${trayIconColor} !important;}</style>`;
|
||||
|
||||
const iconBuffer = await sharp(Buffer.from(svgRoot.outerHTML))
|
||||
.resize({ width: size, height: size })
|
||||
.png()
|
||||
.toBuffer();
|
||||
|
||||
return nativeImage.createFromBuffer(iconBuffer);
|
||||
});
|
||||
}
|
||||
|
||||
function createCurrentTrayIcon() {
|
||||
return createTrayIcon({
|
||||
shouldUseDarkColors: nativeTheme.shouldUseDarkColors,
|
||||
size: 16,
|
||||
sourceSvg: LogoLens,
|
||||
});
|
||||
}
|
||||
|
||||
function watchShouldUseDarkColors(tray: Tray): Disposer {
|
||||
let prevShouldUseDarkColors = nativeTheme.shouldUseDarkColors;
|
||||
const onUpdated = () => {
|
||||
if (prevShouldUseDarkColors !== nativeTheme.shouldUseDarkColors) {
|
||||
prevShouldUseDarkColors = nativeTheme.shouldUseDarkColors;
|
||||
createCurrentTrayIcon()
|
||||
.then(img => tray.setImage(img));
|
||||
}
|
||||
};
|
||||
|
||||
nativeTheme.on("updated", onUpdated);
|
||||
|
||||
return () => nativeTheme.off("updated", onUpdated);
|
||||
}
|
||||
|
||||
export async function initTray(
|
||||
windowManager: WindowManager,
|
||||
trayMenuItems: IComputedValue<TrayMenuRegistration[]>,
|
||||
navigateToPreferences: () => void,
|
||||
) {
|
||||
const icon = getTrayIcon();
|
||||
): Promise<Disposer> {
|
||||
const icon = await createCurrentTrayIcon();
|
||||
const dispose = disposer();
|
||||
|
||||
tray = new Tray(icon);
|
||||
tray.setToolTip(packageInfo.description);
|
||||
tray.setIgnoreDoubleClickEvents(true);
|
||||
|
||||
dispose.push(watchShouldUseDarkColors(tray));
|
||||
|
||||
if (isWindows) {
|
||||
tray.on("click", () => {
|
||||
windowManager
|
||||
@@ -50,7 +98,7 @@ export function initTray(
|
||||
});
|
||||
}
|
||||
|
||||
const disposers = [
|
||||
dispose.push(
|
||||
autorun(() => {
|
||||
try {
|
||||
const menu = createTrayMenu(windowManager, toJS(trayMenuItems.get()), navigateToPreferences);
|
||||
@@ -60,13 +108,13 @@ export function initTray(
|
||||
logger.error(`${TRAY_LOG_PREFIX}: building failed`, { error });
|
||||
}
|
||||
}),
|
||||
];
|
||||
() => {
|
||||
tray?.destroy();
|
||||
tray = null;
|
||||
},
|
||||
);
|
||||
|
||||
return () => {
|
||||
disposers.forEach(disposer => disposer());
|
||||
tray?.destroy();
|
||||
tray = null;
|
||||
};
|
||||
return dispose;
|
||||
}
|
||||
|
||||
function getMenuItemConstructorOptions(trayItem: TrayMenuRegistration): Electron.MenuItemConstructorOptions {
|
||||
|
||||
Reference in new issue
Block a user