notification.go

 1package notification
 2
 3import (
 4	"log/slog"
 5	"sync"
 6
 7	"git.secluded.site/crush/internal/config"
 8	"github.com/gen2brain/beeep"
 9)
10
11var (
12	isFocused      = true
13	supportsFocus  = false
14	focusStateLock sync.RWMutex
15
16	// notifyFunc is the function used to send notifications.
17	// It can be swapped for testing.
18	notifyFunc = beeep.Notify
19)
20
21// SetFocusSupport sets whether the terminal supports focus reporting.
22func SetFocusSupport(supported bool) {
23	focusStateLock.Lock()
24	defer focusStateLock.Unlock()
25	supportsFocus = supported
26}
27
28// SetFocused sets whether the terminal window is currently focused.
29func SetFocused(focused bool) {
30	focusStateLock.Lock()
31	defer focusStateLock.Unlock()
32	isFocused = focused
33}
34
35// IsFocused returns whether the terminal window is currently focused.
36func IsFocused() bool {
37	focusStateLock.RLock()
38	defer focusStateLock.RUnlock()
39	return isFocused
40}
41
42// Send sends a desktop notification with the given title and message.
43// Notifications are only sent when focus reporting is supported, the terminal window is not focused, and notifications are not disabled in config.
44// On darwin (macOS), icons are omitted due to platform limitations.
45func Send(title, message string) error {
46	// Check if notifications are disabled in config
47	cfg := config.Get()
48	if cfg != nil && cfg.Options != nil && cfg.Options.DisableNotifications {
49		slog.Debug("skipping notification: disabled in config")
50		return nil
51	}
52
53	focusStateLock.RLock()
54	focused := isFocused
55	supported := supportsFocus
56	focusStateLock.RUnlock()
57
58	slog.Debug("notification.Send called", "title", title, "message", message, "focused", focused, "supported", supported)
59
60	// Only send notifications if focus reporting is supported and window is not focused.
61	if !supported || focused {
62		slog.Debug("skipping notification: focus not supported or window is focused")
63		return nil
64	}
65
66	beeep.AppName = "Crush"
67
68	err := notifyFunc(title, message, notificationIcon)
69
70	if err != nil {
71		slog.Error("failed to send notification", "error", err)
72	} else {
73		slog.Debug("notification sent successfully")
74	}
75
76	return err
77}