feat: custom badges colors

This commit is contained in:
Oleh Polisan 2024-06-21 17:36:19 +03:00
parent c725352bef
commit d47582b7ee
35 changed files with 92 additions and 17 deletions

View file

@ -12,11 +12,11 @@ import { BADGE_DIR } from "shared/paths";
import { mainWin } from "./mainWindow";
const imgCache = new Map<number, NativeImage>();
export function loadBadge(index: number) {
function loadBadge(index: number) {
const cached = imgCache.get(index);
if (cached) return cached;
const img = nativeImage.createFromPath(join(BADGE_DIR, `${index}.png`));
const img = nativeImage.createFromPath(join(BADGE_DIR, "ico", `${index}.ico`));
imgCache.set(index, img);
return img;

View file

@ -5,13 +5,13 @@
*/
import { dialog, NativeImage, nativeImage } from "electron";
import { mkdirSync, writeFileSync } from "fs";
import { mkdirSync, readFileSync, writeFileSync } from "fs";
import { readFile } from "fs/promises";
import { join } from "path";
import { IpcEvents } from "shared/IpcEvents";
import { ICONS_DIR, STATIC_DIR } from "shared/paths";
import { BADGE_DIR, ICONS_DIR, STATIC_DIR } from "shared/paths";
import { lastBadgeCount, loadBadge } from "./appBadge";
import { lastBadgeCount } from "./appBadge";
import { mainWin, tray } from "./mainWindow";
import { Settings } from "./settings";
@ -44,9 +44,10 @@ export async function setTrayIcon(iconName: string) {
trayImage = nativeImage.createFromPath(join(ICONS_DIR, "icon.png"));
}
const badgeImg = loadBadge(lastBadgeCount);
const badge = lastBadgeCount > 9 ? 10 : lastBadgeCount;
const badgeSvg = readFileSync(join(BADGE_DIR, "svg", `${badge}.svg`), "utf8");
// and send IPC call to renderer to add to image
mainWin.webContents.send(IpcEvents.ADD_BADGE_TO_ICON, trayImage.toDataURL(), badgeImg.toDataURL());
mainWin.webContents.send(IpcEvents.ADD_BADGE_TO_ICON, trayImage.toDataURL(), badgeSvg);
return;
}

View file

@ -27,17 +27,35 @@ export function setCurrentTrayIcon() {
}
}
VesktopNative.tray.createIconRequest(async (iconName: string) => {
const pickedColor = VesktopNative.settings.get().trayColor;
const fillColor = VesktopNative.settings.get().trayAutoFill ?? "auto";
function backgroundTooBright(color: string) {
// calculate relative luminance
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
if (!result) {
return false;
}
const normalizedR = parseInt(result[1], 16) / 255;
const normalizedG = parseInt(result[2], 16) / 255;
const normalizedB = parseInt(result[3], 16) / 255;
const lumR = normalizedR <= 0.03928 ? normalizedR / 12.92 : Math.pow((normalizedR + 0.055) / 1.055, 2.4);
const lumG = normalizedG <= 0.03928 ? normalizedG / 12.92 : Math.pow((normalizedG + 0.055) / 1.055, 2.4);
const lumB = normalizedB <= 0.03928 ? normalizedB / 12.92 : Math.pow((normalizedB + 0.055) / 1.055, 2.4);
return 0.2126 * lumR + 0.7152 * lumG + 0.0722 * lumB > 0.5;
}
function changeColorsInSvg(svg: string, stockColor: string, isBadge: boolean = false) {
const pickedColor = VesktopNative.settings.get().trayColor;
const reg = new RegExp(stockColor, "gim");
svg = svg.replace(reg, "#" + (pickedColor ?? stockColor));
if (backgroundTooBright(pickedColor ?? stockColor)) svg = svg.replace(/white/gim, "black");
return svg;
}
VesktopNative.tray.createIconRequest(async (iconName: string) => {
try {
var svg = await VesktopNative.tray.getIcon(iconName);
svg = svg.replace(/#f6bfac/gim, "#" + (pickedColor ?? "3DB77F"));
if (fillColor !== "auto") {
svg = svg.replace(/black/gim, fillColor);
svg = svg.replace(/white/gim, fillColor);
}
svg = changeColorsInSvg(svg, "#f6bfac");
const canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 128;
@ -58,7 +76,12 @@ VesktopNative.tray.createIconRequest(async (iconName: string) => {
}
});
VesktopNative.tray.addBadgeToIcon(async (iconDataURL: string, badgeDataURL: string) => {
VesktopNative.tray.addBadgeToIcon(async (iconDataURL: string, badgeDataSVG: string) => {
const pickedColor = VesktopNative.settings.get().trayColor;
const fillColor = VesktopNative.settings.get().trayAutoFill ?? "white";
badgeDataSVG = changeColorsInSvg(badgeDataSVG, "#F35959");
if (fillColor !== "auto") badgeDataSVG = badgeDataSVG.replace(/white/gim, fillColor);
const canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 128;
@ -81,7 +104,7 @@ VesktopNative.tray.addBadgeToIcon(async (iconDataURL: string, badgeDataURL: stri
VesktopNative.tray.returnIconWithBadge(canvas.toDataURL());
};
iconImg.src = badgeDataURL;
iconImg.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(badgeDataSVG)}`;
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/badges/ico/1.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/10.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/11.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/3.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/4.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/5.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/6.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/7.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/8.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/badges/ico/9.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

5
static/badges/svg/1.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path d="M 585,850 H 499 V 351 q 0,-43 1,-69 1,-26 3,-54 -16,16 -29,27 -13,11 -33,28 l -76,62 -46,-59 193,-150 h 73 z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 327 B

5
static/badges/svg/10.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<circle cx="500" cy="500" r="200" stroke="#F35959" stroke-width="50" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 277 B

5
static/badges/svg/2.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path fill="white" d="M 725.85937,755.29297 V 830 h -455.5664 v -62.01172 q 24.90234,-57.12891 60.05859,-101.07422 35.64453,-43.94531 75.6836,-79.10156 40.03906,-35.15625 79.10156,-65.42969 19.53125,-15.13672 36.62109,-30.27344 17.57813,-15.13671 33.20313,-30.27343 31.25,-30.27344 50.29297,-63.47657 19.53125,-33.20312 19.53125,-75.19531 0,-56.64062 -33.20313,-87.89062 -33.20312,-31.25 -92.28516,-31.25 -56.15234,0 -92.77343,30.76172 -36.13282,30.27343 -42.48047,85.44921 l -89.84375,-8.30078 q 9.76562,-82.51953 69.82422,-131.34765 60.54687,-48.82813 155.27343,-48.82813 104.00391,0 159.66797,49.31641 56.15235,48.82812 56.15235,139.16015 0,79.10157 -72.75391,158.69141 -35.15625,39.0625 -138.18359,122.55859 -109.375,89.35547 -137.20703,153.8086 z"/>
</svg>

After

Width:  |  Height:  |  Size: 948 B

5
static/badges/svg/3.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path fill="white" d="m 732.20703,650.05859 q 0,95.21485 -60.54687,147.46094 -60.54688,52.24609 -172.85157,52.24609 -104.49218,0 -166.99218,-46.875 -62.01172,-47.36328 -73.73047,-139.64843 l 90.82031,-8.30078 q 17.57812,122.07031 149.90234,122.07031 66.40625,0 104.00391,-32.71485 38.08594,-32.71484 38.08594,-97.16796 0,-56.15235 -43.45703,-87.40235 -42.96875,-31.73828 -124.51172,-31.73828 H 423.125 v -76.17187 h 47.85156 q 72.26563,0 111.81641,-31.25 40.03906,-31.73829 40.03906,-87.40235 0,-55.17578 -32.71484,-86.91406 -32.22657,-32.22656 -96.19141,-32.22656 -58.10547,0 -94.23828,29.78515 -35.64453,29.78516 -41.50391,83.98438 l -88.3789,-6.83594 q 9.76562,-84.47266 69.82422,-131.83594 60.54687,-47.36328 155.27343,-47.36328 103.51563,0 160.64453,48.33985 57.61719,47.85156 57.61719,133.78906 0,65.91797 -37.10937,107.42187 -36.6211,41.01563 -106.9336,55.66407 v 1.95312 q 77.14844,8.30078 120.11719,51.75781 42.96875,43.45703 42.96875,109.375 z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

5
static/badges/svg/4.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path fill="white" d="M 630.17578,684.23828 V 840 H 547.16797 V 684.23828 H 222.94922 v -68.35937 l 314.9414,-463.86719 h 92.28516 v 462.89062 h 96.67969 v 69.33594 z M 304.00391,614.90234 H 547.16797 V 340.48828 q 0,-22.46094 0,-44.43359 0.48828,-22.46094 1.95312,-44.92188 -11.23047,21.48438 -19.53125,35.15625 -8.30078,13.1836 -15.13672,22.94922 z"/>
</svg>

After

Width:  |  Height:  |  Size: 547 B

5
static/badges/svg/5.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path fill="white" d="m 734.16016,615.87891 q 0,108.88671 -64.94141,171.38671 -64.45313,62.5 -179.19922,62.5 -96.19141,0 -155.27344,-41.99218 -59.08203,-41.99219 -74.70703,-121.58203 l 88.86719,-10.25391 q 27.83203,102.05078 143.06641,102.05078 70.80078,0 110.83984,-42.48047 40.03906,-42.96875 40.03906,-117.67578 0,-64.94141 -40.52734,-104.98047 -40.03906,-40.03906 -108.39844,-40.03906 -35.64453,0 -66.40625,11.23047 -30.76172,11.23047 -61.52344,38.08594 h -85.9375 l 22.94922,-370.11719 h 391.11328 v 74.70703 H 383.08594 l -13.1836,218.26172 q 57.12891,-43.94531 142.08985,-43.94531 67.87109,0 117.67578,27.34375 49.80469,26.85546 77.14844,75.19531 27.34375,48.33984 27.34375,112.30469 z"/>
</svg>

After

Width:  |  Height:  |  Size: 889 B

6
static/badges/svg/6.svg Executable file
View file

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path fill="white" d="m 722.20703,614.90234 q 0,108.88672 -59.08203,171.875 -59.08203,62.98828 -163.08594,62.98828 -116.21094,0 -177.73437,-86.42578 -61.52344,-86.42578 -61.52344,-251.46484 0,-178.71094 63.96484,-274.41406 63.96485,-95.70313 182.12891,-95.70313 155.76172,0 196.28906,140.13672 l -83.98437,15.13672 q -25.39063,-83.98438 -113.28125,-83.98438 -75.19532,0 -116.69922,70.3125 -41.01563,69.82422 -41.01563,202.63672 23.92578,-44.43359 67.38282,-67.38281 43.45703,-23.4375 99.60937,-23.4375 95.21484,0 150.87891,59.57031 56.15234,59.57032 56.15234,160.15625 z m -89.35547,3.90625 q 0,-74.70703 -36.62109,-115.23437 -36.6211,-40.52735 -102.05078,-40.52735 -61.52344,0 -99.60938,36.13282 -37.59765,35.64453 -37.59765,98.63281 0,52.73437 18.0664,93.75 18.06641,41.01562 49.31641,64.45312 31.73828,22.94922 72.7539,22.94922 63.47657,0 99.60938,-42.48047 36.13281,-42.96875 36.13281,-117.67578 z"/>
<text x="210" y="840" font-size="1000" fill="white" font-family="Arial">6</text>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

5
static/badges/svg/7.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path fill="white" d="M 725.85937,243.30078 Q 673.125,323.86719 635.52734,386.85547 598.41797,449.84375 576.93359,495.74219 533.47656,587.05078 511.50391,675.91797 490.01953,764.78516 490.01953,860 h -91.79687 q 0,-68.35938 14.16015,-138.67188 14.16016,-70.80078 45.41016,-148.4375 58.59375,-145.01953 183.10547,-326.17187 H 271.26953 v -74.70703 h 454.58984 z"/>
</svg>

After

Width:  |  Height:  |  Size: 557 B

5
static/badges/svg/8.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path fill="white" d="m 732.69531,648.10547 q 0,95.21484 -60.54687,148.4375 -60.54688,53.22265 -173.82813,53.22265 -110.35156,0 -172.85156,-52.24609 -62.01172,-52.24609 -62.01172,-148.4375 0,-67.38281 38.57422,-113.28125 38.57422,-45.89844 98.63281,-55.66406 v -1.95313 Q 344.51172,465 311.79687,421.05469 279.57031,377.10937 279.57031,318.02734 q 0,-78.61328 58.59375,-127.4414 59.08203,-48.82813 158.20313,-48.82813 101.5625,0 160.15625,47.85156 59.08203,47.85157 59.08203,129.39454 0,59.08203 -32.71485,103.02734 -32.71484,43.94531 -89.35546,55.17578 v 1.95313 q 65.91796,10.74218 102.53906,56.15234 36.62109,44.92187 36.62109,112.79297 z M 624.29687,323.88672 q 0,-116.69922 -127.92968,-116.69922 -126.95313,0 -126.95313,116.69922 0,59.08203 33.20313,90.33203 33.6914,30.76172 94.72656,30.76172 62.01172,0 94.23828,-28.32031 32.71484,-28.8086 32.71484,-92.77344 z m 17.08985,315.91797 q 0,-63.96485 -38.08594,-96.19141 -38.08594,-32.71484 -106.93359,-32.71484 -66.89453,0 -104.49219,35.15625 -37.59766,34.66797 -37.59766,95.70312 0,142.08985 145.01953,142.08985 71.77735,0 106.9336,-34.17969 Q 641.38672,715 641.38672,639.80469 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

5
static/badges/svg/9.svg Executable file
View file

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<circle cx="500" cy="500" r="400" stroke="#F35959" stroke-width="50" fill="#F35959"/>
<path fill="white" d="m 738.78906,482.08984 q 0,177.2461 -64.9414,272.46094 -64.45313,95.21484 -184.08204,95.21484 -80.5664,0 -129.39453,-33.6914 -48.33984,-34.17969 -69.33593,-109.86328 l 83.98437,-13.1836 q 26.36719,85.9375 116.21094,85.9375 75.68359,0 117.1875,-70.3125 41.5039,-70.3125 43.45703,-200.68359 -19.53125,43.94531 -66.89453,70.80078 -47.36328,26.36719 -104.00391,26.36719 -61.52344,0 -107.42187,-28.8086 -45.89844,-28.80859 -71.28907,-81.05468 -25.39062,-52.2461 -25.39062,-122.07032 0,-107.91015 60.54687,-169.43359 60.54688,-62.01172 168.45704,-62.01172 114.74609,0 173.82812,84.96094 59.08203,84.96094 59.08203,255.37109 z m -95.70312,-84.96093 q 0,-83.00782 -38.08594,-133.30079 -38.08594,-50.78125 -102.05078,-50.78125 -63.47656,0 -100.09766,43.45704 -36.62109,42.96875 -36.62109,116.69921 0,75.19532 36.62109,119.14063 36.6211,43.45703 99.1211,43.45703 38.08593,0 69.82421,-17.57812 32.22657,-17.57813 51.75782,-48.82813 19.53125,-31.73828 19.53125,-72.26562 z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB