diff --git a/apps/twig/src/main/services/notification/service.ts b/apps/twig/src/main/services/notification/service.ts index bf58068ab..4f2bb6ab0 100644 --- a/apps/twig/src/main/services/notification/service.ts +++ b/apps/twig/src/main/services/notification/service.ts @@ -35,6 +35,13 @@ export class NotificationService { log.info("Dock badge shown"); } + bounceDock(): void { + if (process.platform === "darwin") { + app.dock?.bounce("informational"); + log.info("Dock bounce triggered"); + } + } + private clearDockBadge(): void { if (!this.hasBadge) return; diff --git a/apps/twig/src/main/trpc/routers/notification.ts b/apps/twig/src/main/trpc/routers/notification.ts index abb279525..bc8292570 100644 --- a/apps/twig/src/main/trpc/routers/notification.ts +++ b/apps/twig/src/main/trpc/routers/notification.ts @@ -20,4 +20,5 @@ export const notificationRouter = router({ getService().send(input.title, input.body, input.silent), ), showDockBadge: publicProcedure.mutation(() => getService().showDockBadge()), + bounceDock: publicProcedure.mutation(() => getService().bounceDock()), }); diff --git a/apps/twig/src/renderer/features/settings/components/sections/ChatSettings.tsx b/apps/twig/src/renderer/features/settings/components/sections/ChatSettings.tsx index 19e072c32..3e3506e11 100644 --- a/apps/twig/src/renderer/features/settings/components/sections/ChatSettings.tsx +++ b/apps/twig/src/renderer/features/settings/components/sections/ChatSettings.tsx @@ -14,12 +14,14 @@ export function ChatSettings() { const { desktopNotifications, dockBadgeNotifications, + dockBounceNotifications, completionSound, completionVolume, autoConvertLongText, sendMessagesWith, setDesktopNotifications, setDockBadgeNotifications, + setDockBounceNotifications, setCompletionSound, setCompletionVolume, setAutoConvertLongText, @@ -90,6 +92,17 @@ export function ChatSettings() { /> + + + + void; setDesktopNotifications: (enabled: boolean) => void; setDockBadgeNotifications: (enabled: boolean) => void; + setDockBounceNotifications: (enabled: boolean) => void; setCursorGlow: (enabled: boolean) => void; setAutoConvertLongText: (enabled: boolean) => void; setSendMessagesWith: (mode: SendMessagesWith) => void; @@ -54,6 +56,7 @@ export const useSettingsStore = create()( lastUsedModel: null, desktopNotifications: true, dockBadgeNotifications: true, + dockBounceNotifications: false, completionSound: "none", completionVolume: 80, cursorGlow: false, @@ -75,6 +78,8 @@ export const useSettingsStore = create()( set({ desktopNotifications: enabled }), setDockBadgeNotifications: (enabled) => set({ dockBadgeNotifications: enabled }), + setDockBounceNotifications: (enabled) => + set({ dockBounceNotifications: enabled }), setCursorGlow: (enabled) => set({ cursorGlow: enabled }), setAutoConvertLongText: (enabled) => set({ autoConvertLongText: enabled }), @@ -96,6 +101,7 @@ export const useSettingsStore = create()( lastUsedModel: state.lastUsedModel, desktopNotifications: state.desktopNotifications, dockBadgeNotifications: state.dockBadgeNotifications, + dockBounceNotifications: state.dockBounceNotifications, cursorGlow: state.cursorGlow, autoConvertLongText: state.autoConvertLongText, completionSound: state.completionSound, diff --git a/apps/twig/src/renderer/lib/notifications.ts b/apps/twig/src/renderer/lib/notifications.ts index 9458223a9..12497250e 100644 --- a/apps/twig/src/renderer/lib/notifications.ts +++ b/apps/twig/src/renderer/lib/notifications.ts @@ -28,6 +28,12 @@ function showDockBadge(): void { }); } +function bounceDock(): void { + trpcVanilla.notification.bounceDock.mutate().catch((err) => { + log.error("Failed to bounce dock", err); + }); +} + export function notifyPromptComplete( taskTitle: string, stopReason: string, @@ -39,6 +45,7 @@ export function notifyPromptComplete( completionVolume, desktopNotifications, dockBadgeNotifications, + dockBounceNotifications, } = useSettingsStore.getState(); const isWindowFocused = document.hasFocus(); @@ -57,6 +64,9 @@ export function notifyPromptComplete( if (dockBadgeNotifications) { showDockBadge(); } + if (dockBounceNotifications) { + bounceDock(); + } } export function notifyPermissionRequest(taskTitle: string): void { @@ -65,6 +75,7 @@ export function notifyPermissionRequest(taskTitle: string): void { completionVolume, desktopNotifications, dockBadgeNotifications, + dockBounceNotifications, } = useSettingsStore.getState(); const isWindowFocused = document.hasFocus(); @@ -82,5 +93,8 @@ export function notifyPermissionRequest(taskTitle: string): void { if (dockBadgeNotifications) { showDockBadge(); } + if (dockBounceNotifications) { + bounceDock(); + } } }