feat(desktop): Windows taskbar overlay icon for unread badge
Release desktop app / build (, windows-latest) (push) Has been cancelled
Release desktop app / build (--target universal-apple-darwin --bundles app,updater, macos-14) (push) Has been cancelled

Red-dot overlay drawn as raw RGBA (no extra resource bundled).
Shown on Windows when unread count > 0, cleared when 0.
macOS keeps numeric Dock badge; Linux has no cross-DE badge API.

Bumps version 0.10.0 -> 0.10.1.
This commit is contained in:
2026-04-21 17:31:06 +02:00
parent eb452bf57e
commit 5aa39b40ff
5 changed files with 45 additions and 8 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@chat-app/desktop",
"version": "0.10.0",
"version": "0.10.1",
"private": true,
"description": "Tauri v2 desktop client (Windows / macOS / Linux)",
"type": "module",
+1 -1
View File
@@ -726,7 +726,7 @@ dependencies = [
[[package]]
name = "chat-app-desktop"
version = "0.10.0"
version = "0.10.1"
dependencies = [
"base64 0.22.1",
"dryoc",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "chat-app-desktop"
version = "0.10.0"
version = "0.10.1"
description = "ChatApp desktop client"
authors = ["Dennis"]
edition = "2021"
+41 -4
View File
@@ -22,6 +22,33 @@ struct TrayUnreadPayload {
count: u32,
}
// Red-dot overlay icon for the Windows taskbar. Drawn as raw RGBA instead of
// shipping a PNG so we don't add another resource to the bundle. Kept small
// (32x32) since Windows scales the overlay down anyway.
#[cfg(target_os = "windows")]
fn unread_overlay_rgba() -> Vec<u8> {
const SIZE: u32 = 32;
let r = SIZE as f32 / 2.0;
let mut buf = Vec::with_capacity((SIZE * SIZE * 4) as usize);
for y in 0..SIZE {
for x in 0..SIZE {
let dx = x as f32 - r + 0.5;
let dy = y as f32 - r + 0.5;
let d = (dx * dx + dy * dy).sqrt();
let edge = r - 1.0;
if d <= edge {
buf.extend_from_slice(&[0xDC, 0x26, 0x26, 0xFF]);
} else if d <= r {
let alpha = (255.0 * (r - d)).clamp(0.0, 255.0) as u8;
buf.extend_from_slice(&[0xDC, 0x26, 0x26, alpha]);
} else {
buf.extend_from_slice(&[0, 0, 0, 0]);
}
}
}
buf
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
fn show_main_window(app: &AppHandle) {
if let Some(win) = app.get_webview_window("main") {
@@ -171,9 +198,9 @@ pub fn run() {
format!("ChatApp · {} neu", payload.count)
};
let _ = tray_handle.set_tooltip(Some(tooltip));
// Dock/taskbar badge. `set_badge_label` is macOS-only.
// Windows taskbar uses an overlay icon (different API).
// Linux has no cross-DE badge API — skip.
// Dock/taskbar badge. macOS uses a numeric label; Windows uses
// an overlay icon (red dot = unread). Linux has no cross-DE
// badge API — skip.
#[cfg(target_os = "macos")]
if let Some(win) = badge_window.as_ref() {
let badge = if payload.count == 0 {
@@ -183,7 +210,17 @@ pub fn run() {
};
let _ = win.set_badge_label(badge);
}
#[cfg(not(target_os = "macos"))]
#[cfg(target_os = "windows")]
if let Some(win) = badge_window.as_ref() {
if payload.count == 0 {
let _ = win.set_overlay_icon(None);
} else {
let rgba = unread_overlay_rgba();
let img = tauri::image::Image::new_owned(rgba, 32, 32);
let _ = win.set_overlay_icon(Some(img));
}
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
let _ = &badge_window;
});
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "ChatApp",
"version": "0.10.0",
"version": "0.10.1",
"identifier": "com.meinname.chatapp",
"build": {
"beforeDevCommand": "pnpm vite:dev",