notification.go

 1package notification
 2
 3import (
 4	"log/slog"
 5	"sync"
 6
 7	"github.com/gen2brain/beeep"
 8)
 9
10var (
11	isFocused      = true
12	supportsFocus  = false
13	focusStateLock sync.RWMutex
14)
15
16// SetFocusSupport sets whether the terminal supports focus reporting.
17func SetFocusSupport(supported bool) {
18	focusStateLock.Lock()
19	defer focusStateLock.Unlock()
20	supportsFocus = supported
21}
22
23// SetFocused sets whether the terminal window is currently focused.
24func SetFocused(focused bool) {
25	focusStateLock.Lock()
26	defer focusStateLock.Unlock()
27	isFocused = focused
28}
29
30// IsFocused returns whether the terminal window is currently focused.
31func IsFocused() bool {
32	focusStateLock.RLock()
33	defer focusStateLock.RUnlock()
34	return isFocused
35}
36
37// Send sends a desktop notification with the given title and message.
38// Notifications are only sent when the terminal window is not focused.
39// On darwin (macOS), icons are omitted due to platform limitations.
40func Send(title, message string) error {
41	focusStateLock.RLock()
42	focused := isFocused
43	supported := supportsFocus
44	focusStateLock.RUnlock()
45
46	slog.Debug("notification.Send called", "title", title, "message", message, "focused", focused, "supported", supported)
47
48	// Only skip notification if we know the window is focused.
49	// Send by default if focus reporting is not supported.
50	if supported && focused {
51		slog.Debug("skipping notification: window is focused")
52		return nil
53	}
54
55	beeep.AppName = "Crush"
56
57	err := beeep.Notify(title, message, notificationIcon)
58
59	if err != nil {
60		slog.Error("failed to send notification", "error", err)
61	} else {
62		slog.Debug("notification sent successfully")
63	}
64
65	return err
66}