diff --git a/main.go b/main.go index 406397a53ac273b95e1e4b09eca16a2507088ef2..07db2972f1f6a1640c0b50a0db01f090e4d08e92 100644 --- a/main.go +++ b/main.go @@ -242,27 +242,46 @@ func waitForLogEntry(ch <-chan logging.Entry) tea.Cmd { } } -func (m *mainModel) syncUnreadBadge() { - if runtime.GOOS != goosDarwin { - return - } +func unreadBadgeCount(emailsByAcct, folderEmails map[string][]fetcher.Email) int { count := 0 + seen := make(map[string]struct{}) + + countUnread := func(e fetcher.Email) { + if e.IsRead { + return + } + key := fmt.Sprintf("%s:%d", e.AccountID, e.UID) + if _, ok := seen[key]; ok { + return + } + seen[key] = struct{}{} + count++ + } + // Count unread across all accounts (cached/loaded emails) - for _, emails := range m.emailsByAcct { + for _, emails := range emailsByAcct { for _, e := range emails { - if !e.IsRead { - count++ - } + countUnread(e) } } // Also check folderEmails for unread status - for _, emails := range m.folderEmails { + for _, emails := range folderEmails { for _, e := range emails { - if !e.IsRead { - count++ - } + countUnread(e) } } + return count +} + +func (m *mainModel) syncUnreadBadge() { + if runtime.GOOS != goosDarwin && loglevel.Get() < loglevel.LevelDebug { + return + } + count := unreadBadgeCount(m.emailsByAcct, m.folderEmails) + loglevel.Debugf("unread badge count: %d", count) + if runtime.GOOS != goosDarwin { + return + } _ = macos.SetBadge(count) } diff --git a/main_test.go b/main_test.go index 6484635ced0bfcc079a463bacc6360c2e81433c6..a7ab18261fbc51a4c19a1bbba5033f517a1c59f3 100644 --- a/main_test.go +++ b/main_test.go @@ -5,6 +5,8 @@ import ( "strings" "testing" "unicode/utf8" + + "github.com/floatpane/matcha/fetcher" ) func TestSanitizeFilenameTruncatesCJKOnUTF8Boundary(t *testing.T) { @@ -58,3 +60,19 @@ func TestParseGlobalFlagsDoesNotConsumeSubcommandFlags(t *testing.T) { t.Fatalf("args = %q, want %q", got, "matcha send --logs") } } + +func TestUnreadBadgeCountDeduplicatesOverlappingStores(t *testing.T) { + email := fetcher.Email{UID: 42, AccountID: "acct-a"} + got := unreadBadgeCount( + map[string][]fetcher.Email{ + "acct-a": {email}, + }, + map[string][]fetcher.Email{ + folderInbox: {email}, + }, + ) + + if got != 1 { + t.Fatalf("unreadBadgeCount() = %d, want 1", got) + } +}