Skip to content

Commit

Permalink
added icon badge for unread chats + count next to tab title
Browse files Browse the repository at this point in the history
  • Loading branch information
amanharwara committed Apr 2, 2024
1 parent e387512 commit 2a8ed55
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "altus",
"productName": "Altus",
"version": "5.0.2",
"version": "5.1.0",
"description": "Desktop client for WhatsApp Web with themes & multiple account support.",
"main": ".vite/build/main.js",
"build": {
Expand Down
File renamed without changes
13 changes: 13 additions & 0 deletions src/components/TabsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ interface TabComponentProps {
}

const TabComponent: Component<TabComponentProps> = (props) => {
const [messageCount, setMessageCount] = createSignal(0);

window.electronIPCHandlers.onMessageCount(({ messageCount, tabId }) => {
if (tabId === props.tab.id) {
setMessageCount(messageCount);
}
});

return (
<div
class="group flex flex-shrink-0 items-center gap-1.5 bg-zinc-800 px-3 py-1.5 text-white text-sm leading-4 ui-selected:bg-zinc-700 hover:bg-zinc-600 select-none"
Expand All @@ -36,6 +44,11 @@ const TabComponent: Component<TabComponentProps> = (props) => {
onClick={() => setTabActive(props.tab.id)}
data-selected={props.tab.id === tabStore.selectedTabId ? "" : undefined}
>
{!!messageCount() && (
<div class="flex items-center justify-center leading-none w-[4ch] h-5 bg-red-600 text-white rounded-full text-[length:0.65rem] mr-0.5">
{messageCount() > 99 ? "99+" : messageCount()}
</div>
)}
<span>{props.tab.name}</span>
<button
class="flex items-center justify-center ml-0.5 w-6 h-6 hover:bg-zinc-800/50 rounded group-data-[selected]:hover:bg-zinc-800/50"
Expand Down
7 changes: 7 additions & 0 deletions src/components/WebView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ const WebView: Component<{ tab: Tab }> = (props) => {
window.toggleNotifications(tab.config.notifications, `persist:${tab.id}`);
});

createEffect(() => {
if (!webviewRef) return;
if (!didStopLoading()) return;

webviewRef.send("set-id", tab.id);
});

onMount(() => {
const webview = webviewRef;

Expand Down
3 changes: 3 additions & 0 deletions src/contextBridge.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ declare global {
onReloadTranslations: (callback: () => void) => Electron.IpcRenderer;
onNewChat: (callback: () => void) => Electron.IpcRenderer;
onOpenThemeManager: (callback: () => void) => Electron.IpcRenderer;
onMessageCount: (
callback: (detail: { messageCount: number; tabId: string }) => void
) => Electron.IpcRenderer;
};
windowActions: {
minimize: () => Promise<void>;
Expand Down
37 changes: 37 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,18 @@ const mainIcon = nativeImage.createFromPath(
path.join(iconsPath, process.platform === "win32" ? "icon.ico" : "icon.png")
);

const mainNotificationIcon = nativeImage.createFromPath(
path.join(iconsPath, "icon-notification.png")
);

const trayIcon = nativeImage.createFromPath(
path.join(iconsPath, process.platform === "win32" ? "icon.ico" : "tray.png")
);

const trayNotificationIcon = nativeImage.createFromPath(
path.join(iconsPath, "tray-notification.png")
);

const createWindow = () => {
const useCustomTitlebar =
process.platform !== "darwin" && getSettingWithDefault("customTitlebar");
Expand Down Expand Up @@ -503,6 +511,35 @@ function addIPCHandlers(mainWindow: BrowserWindow) {
break;
}
});

ipcMain.on("message-count", (_, detail) => {
mainWindow.webContents.send("message-count", detail);
if (!getSettingWithDefault("notificationBadge")) {
return;
}
const messageCount = detail.messageCount;
if (messageCount) {
switch (process.platform) {
case "darwin":
app.dock.setBadge("·");
break;
default:
if (tray) tray.setImage(trayNotificationIcon);
mainWindow.setOverlayIcon(mainNotificationIcon, "Notification badge");
break;
}
} else {
switch (process.platform) {
case "darwin":
app.dock.setBadge("");
break;
default:
if (tray) tray.setImage(trayIcon);
mainWindow.setOverlayIcon(null, "Notification badge empty");
break;
}
}
});
}

type CloneableMenuItem = Omit<MenuItem, "menu" | "submenu" | "click"> & {
Expand Down
3 changes: 3 additions & 0 deletions src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ contextBridge.exposeInMainWorld("electronIPCHandlers", {
onNewChat: (callback: () => void) => ipcRenderer.on("new-chat", callback),
onOpenThemeManager: (callback: () => void) =>
ipcRenderer.on("open-theme-manager", callback),
onMessageCount: (
callback: (detail: { messageCount: number; tabId: string }) => void
) => ipcRenderer.on("message-count", (_, count) => callback(count)),
});

contextBridge.exposeInMainWorld(
Expand Down
51 changes: 51 additions & 0 deletions src/whatsapp.preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { ipcRenderer } from "electron";
import { Theme } from "./stores/themes/common";
import { formatSelectedText } from "./utils/webview/formatSelectedText";

let titleElement: HTMLTitleElement;

window.onload = () => {
titleElement = document.querySelector("title") as HTMLTitleElement;

// Reset initial theme
document.body.querySelectorAll("script").forEach((script) => {
if (script.innerHTML.includes("systemThemeDark")) {
Expand Down Expand Up @@ -51,8 +55,41 @@ window.onload = () => {
ipcRenderer.send("open-link", event.target.href);
}
});

registerTitleElementObserver();
};

function getMessageCountFromTitle(title: string) {
const title_regex = /([0-9]+)/;
const exec = title_regex.exec(title);
if (!exec) return 0;

return parseInt(exec[0], 10);
}

function registerTitleElementObserver() {
new MutationObserver(function () {
const title = titleElement.textContent;
if (!title) return;

try {
const messageCount = getMessageCountFromTitle(title);
const tabId = document.body.dataset.tabId;

ipcRenderer.send("message-count", {
messageCount,
tabId,
});
} catch (error) {
console.error(error);
}
}).observe(titleElement, {
subtree: true,
childList: true,
characterData: true,
});
}

function setThemeCSS(css: string) {
const existingStyle = document.getElementById("altus-style");
if (existingStyle) {
Expand Down Expand Up @@ -140,3 +177,17 @@ ipcRenderer.on("set-theme", (event, theme: Theme) => {
ipcRenderer.on("format-text", (e, wrapper) => {
formatSelectedText(wrapper);
});

ipcRenderer.on("set-id", (e, id) => {
if (!document.body.dataset.tabId) {
// send back initial message count
ipcRenderer.send("message-count", {
messageCount: getMessageCountFromTitle(
titleElement.textContent as string
),
tabId: id,
});
}

document.body.dataset.tabId = id;
});

0 comments on commit 2a8ed55

Please sign in to comment.