1package tui
2
3import (
4 "fmt"
5 "io"
6
7 "github.com/andrinoff/email-cli/fetcher"
8 "github.com/charmbracelet/bubbles/key"
9 "github.com/charmbracelet/bubbles/list"
10 tea "github.com/charmbracelet/bubbletea"
11 "github.com/charmbracelet/lipgloss"
12)
13
14var (
15 paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
16 inboxHelpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
17)
18
19type item struct {
20 title, desc string
21 originalIndex int
22 uid uint32 // Added UID to item
23}
24
25func (i item) Title() string { return i.title }
26func (i item) Description() string { return i.desc }
27func (i item) FilterValue() string { return i.title + " " + i.desc }
28
29type itemDelegate struct{}
30
31func (d itemDelegate) Height() int { return 1 }
32func (d itemDelegate) Spacing() int { return 0 }
33func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
34func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
35 i, ok := listItem.(item)
36 if !ok {
37 return
38 }
39
40 str := fmt.Sprintf("%d. %s", index+1, i.title)
41
42 fn := itemStyle.Render
43 if index == m.Index() {
44 fn = func(s ...string) string {
45 return selectedItemStyle.Render("> " + s[0])
46 }
47 }
48
49 fmt.Fprint(w, fn(str))
50}
51
52type Inbox struct {
53 list list.Model
54 isFetching bool
55 emailsCount int
56}
57
58func NewInbox(emails []fetcher.Email) *Inbox {
59 items := make([]list.Item, len(emails))
60 for i, email := range emails {
61 items[i] = item{
62 title: email.Subject,
63 desc: email.From,
64 originalIndex: i,
65 uid: email.UID, // Store UID
66 }
67 }
68
69 l := list.New(items, itemDelegate{}, 20, 14)
70 l.Title = "Inbox"
71 l.SetShowStatusBar(true)
72 l.SetFilteringEnabled(true)
73 l.Styles.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("205")).Bold(true)
74 l.Styles.PaginationStyle = paginationStyle
75 l.Styles.HelpStyle = inboxHelpStyle
76 l.SetStatusBarItemName("email", "emails")
77 l.AdditionalShortHelpKeys = func() []key.Binding {
78 return []key.Binding{
79 key.NewBinding(key.WithKeys("d"), key.WithHelp("d", "delete")),
80 key.NewBinding(key.WithKeys("a"), key.WithHelp("a", "archive")),
81 }
82 }
83
84 return &Inbox{
85 list: l,
86 isFetching: false,
87 emailsCount: len(emails),
88 }
89}
90
91func (m *Inbox) Init() tea.Cmd {
92 return nil
93}
94
95func (m *Inbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
96 var cmds []tea.Cmd
97
98 switch msg := msg.(type) {
99 case tea.KeyMsg:
100 if m.list.FilterState() == list.Filtering {
101 break
102 }
103 switch keypress := msg.String(); keypress {
104 case "d":
105 selectedItem, ok := m.list.SelectedItem().(item)
106 if ok {
107 return m, func() tea.Msg {
108 return DeleteEmailMsg{UID: selectedItem.uid}
109 }
110 }
111 case "a":
112 selectedItem, ok := m.list.SelectedItem().(item)
113 if ok {
114 return m, func() tea.Msg {
115 return ArchiveEmailMsg{UID: selectedItem.uid}
116 }
117 }
118 case "enter":
119 selectedItem, ok := m.list.SelectedItem().(item)
120 if ok {
121 return m, func() tea.Msg {
122 return ViewEmailMsg{Index: selectedItem.originalIndex}
123 }
124 }
125 }
126 case tea.WindowSizeMsg:
127 m.list.SetWidth(msg.Width)
128 return m, nil
129
130 case FetchingMoreEmailsMsg:
131 m.isFetching = true
132 m.list.Title = "Fetching more emails..."
133 return m, nil
134
135 case EmailsAppendedMsg:
136 m.isFetching = false
137 m.list.Title = "Inbox"
138 newItems := make([]list.Item, len(msg.Emails))
139 for i, email := range msg.Emails {
140 newItems[i] = item{
141 title: email.Subject,
142 desc: email.From,
143 originalIndex: m.emailsCount + i,
144 uid: email.UID,
145 }
146 }
147 currentItems := m.list.Items()
148 allItems := append(currentItems, newItems...)
149 cmd := m.list.SetItems(allItems)
150 m.emailsCount += len(msg.Emails)
151 cmds = append(cmds, cmd)
152 return m, tea.Batch(cmds...)
153 }
154
155 if !m.isFetching && len(m.list.Items()) > 0 && m.list.Index() >= len(m.list.Items())-5 {
156 cmds = append(cmds, func() tea.Msg {
157 return FetchMoreEmailsMsg{Offset: uint32(m.emailsCount)}
158 })
159 }
160
161 var cmd tea.Cmd
162 m.list, cmd = m.list.Update(msg)
163 cmds = append(cmds, cmd)
164 return m, tea.Batch(cmds...)
165}
166
167func (m *Inbox) View() string {
168 return "\n" + m.list.View()
169}