1package tui
2
3import (
4 "strings"
5
6 "charm.land/bubbles/v2/key"
7 tea "charm.land/bubbletea/v2"
8 "charm.land/lipgloss/v2"
9 "github.com/floatpane/matcha/config"
10 "github.com/floatpane/matcha/fetcher"
11)
12
13var (
14 mailboxTabStyle = lipgloss.NewStyle().Padding(0, 3)
15 activeMailboxTabStyle = lipgloss.NewStyle().Padding(0, 3).Foreground(lipgloss.Color("42")).Bold(true).Underline(true)
16 mailboxTabBarStyle = lipgloss.NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).PaddingBottom(1).MarginBottom(1)
17)
18
19// TrashArchive is a combined view for trash and archive emails with a toggle
20type TrashArchive struct {
21 trashInbox *Inbox
22 archiveInbox *Inbox
23 activeView MailboxKind // MailboxTrash or MailboxArchive
24 width int
25 height int
26 accounts []config.Account
27}
28
29// NewTrashArchive creates a new combined trash/archive view
30func NewTrashArchive(trashEmails, archiveEmails []fetcher.Email, accounts []config.Account) *TrashArchive {
31 return &TrashArchive{
32 trashInbox: NewTrashInbox(trashEmails, accounts),
33 archiveInbox: NewArchiveInbox(archiveEmails, accounts),
34 activeView: MailboxTrash,
35 accounts: accounts,
36 }
37}
38
39func (m *TrashArchive) Init() tea.Cmd {
40 return nil
41}
42
43func (m *TrashArchive) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
44 switch msg := msg.(type) {
45 case tea.KeyPressMsg:
46 switch msg.String() {
47 case "tab":
48 // Toggle between trash and archive
49 if m.activeView == MailboxTrash {
50 m.activeView = MailboxArchive
51 } else {
52 m.activeView = MailboxTrash
53 }
54 return m, nil
55 }
56 case tea.WindowSizeMsg:
57 m.width = msg.Width
58 m.height = msg.Height
59 // Pass to both inboxes
60 m.trashInbox.Update(msg)
61 m.archiveInbox.Update(msg)
62 return m, nil
63
64 case FetchingMoreEmailsMsg, EmailsAppendedMsg, RefreshingEmailsMsg, EmailsRefreshedMsg:
65 // Forward to the appropriate inbox based on mailbox
66 if m.activeView == MailboxTrash {
67 m.trashInbox.Update(msg)
68 } else {
69 m.archiveInbox.Update(msg)
70 }
71 return m, nil
72 }
73
74 // Forward other messages to the active inbox
75 var cmd tea.Cmd
76 if m.activeView == MailboxTrash {
77 _, cmd = m.trashInbox.Update(msg)
78 } else {
79 _, cmd = m.archiveInbox.Update(msg)
80 }
81 return m, cmd
82}
83
84func (m *TrashArchive) View() tea.View {
85 var b strings.Builder
86
87 // Render the mailbox toggle tabs
88 var tabViews []string
89 if m.activeView == MailboxTrash {
90 tabViews = append(tabViews, activeMailboxTabStyle.Render("Trash"))
91 tabViews = append(tabViews, mailboxTabStyle.Render("Archive"))
92 } else {
93 tabViews = append(tabViews, mailboxTabStyle.Render("Trash"))
94 tabViews = append(tabViews, activeMailboxTabStyle.Render("Archive"))
95 }
96 tabBar := mailboxTabBarStyle.Render(lipgloss.JoinHorizontal(lipgloss.Top, tabViews...))
97 b.WriteString(tabBar)
98 b.WriteString("\n")
99
100 // Add help text for tab switching
101 helpText := helpStyle.Render("Press tab to switch between Trash and Archive")
102 b.WriteString(helpText)
103 b.WriteString("\n\n")
104
105 // Render the active inbox
106 if m.activeView == MailboxTrash {
107 b.WriteString(m.trashInbox.View().Content)
108 } else {
109 b.WriteString(m.archiveInbox.View().Content)
110 }
111
112 return tea.NewView(b.String())
113}
114
115// GetActiveMailbox returns the currently active mailbox kind
116func (m *TrashArchive) GetActiveMailbox() MailboxKind {
117 return m.activeView
118}
119
120// GetActiveInbox returns the currently active inbox
121func (m *TrashArchive) GetActiveInbox() *Inbox {
122 if m.activeView == MailboxTrash {
123 return m.trashInbox
124 }
125 return m.archiveInbox
126}
127
128// RemoveEmail removes an email from the appropriate inbox
129func (m *TrashArchive) RemoveEmail(uid uint32, accountID string, mailbox MailboxKind) {
130 if mailbox == MailboxTrash {
131 m.trashInbox.RemoveEmail(uid, accountID)
132 } else if mailbox == MailboxArchive {
133 m.archiveInbox.RemoveEmail(uid, accountID)
134 }
135}
136
137// SetTrashEmails updates the trash emails
138func (m *TrashArchive) SetTrashEmails(emails []fetcher.Email, accounts []config.Account) {
139 m.trashInbox.SetEmails(emails, accounts)
140 m.accounts = accounts
141}
142
143// SetArchiveEmails updates the archive emails
144func (m *TrashArchive) SetArchiveEmails(emails []fetcher.Email, accounts []config.Account) {
145 m.archiveInbox.SetEmails(emails, accounts)
146 m.accounts = accounts
147}
148
149// AdditionalShortHelpKeys returns additional help keys for the trash/archive view
150func (m *TrashArchive) AdditionalShortHelpKeys() []key.Binding {
151 return []key.Binding{
152 key.NewBinding(key.WithKeys("tab"), key.WithHelp("tab", "switch view")),
153 }
154}