Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ func (c *Client) DeleteEmail(id string) error {
return err
}

// ArchiveEmail removes the INBOX label, effectively archiving the email.
func (c *Client) ArchiveEmail(id string) error {
mod := &gmail.ModifyMessageRequest{
RemoveLabelIds: []string{"INBOX"},
}
_, err := c.srv.Users.Messages.Modify("me", id, mod).Do()
if err == nil {
c.cache.Delete(id)
}
return err
}

// ToggleRead flips the UNREAD label. Returns the new isUnread state.
func (c *Client) ToggleRead(id string, currentlyUnread bool) (newUnread bool, err error) {
mod := &gmail.ModifyMessageRequest{}
Expand Down
10 changes: 10 additions & 0 deletions ui/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type inboxLoadedMsg struct{ emails []api.Email }
type emailOpenedMsg struct{ email *api.Email }
type emailSentMsg struct{}
type emailDeletedMsg struct{ id string }
type emailArchivedMsg struct{ id string }
type readToggledMsg struct {
id string
isUnread bool
Expand Down Expand Up @@ -72,6 +73,15 @@ func deleteEmailCmd(client *api.Client, id string) tea.Cmd {
}
}

func archiveEmailCmd(client *api.Client, id string) tea.Cmd {
return func() tea.Msg {
if err := client.ArchiveEmail(id); err != nil {
return errMsg{err: err}
}
return emailArchivedMsg{id: id}
}
}

func toggleReadCmd(client *api.Client, id string, currentlyUnread bool) tea.Cmd {
return func() tea.Msg {
newUnread, err := client.ToggleRead(id, currentlyUnread)
Expand Down
4 changes: 3 additions & 1 deletion ui/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type keyMap struct {
Back key.Binding
Reply key.Binding
Compose key.Binding
Archive key.Binding
Delete key.Binding
Search key.Binding
Labels key.Binding
Expand All @@ -32,7 +33,7 @@ func (k keyMap) ShortHelp() []key.Binding {
func (k keyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{k.Compose, k.Reply, k.Search, k.Labels},
{k.Delete, k.ToggleRead, k.Back, k.Quit},
{k.Archive, k.Delete, k.ToggleRead, k.Back, k.Quit},
{k.Send, k.NextInput, k.PrevInput},
{k.AddAttachment, k.RemoveAttachment, k.DownloadAttachment},
}
Expand All @@ -44,6 +45,7 @@ var keys = keyMap{
Back: key.NewBinding(key.WithKeys("b", "esc"), key.WithHelp("b/esc", "back")),
Reply: key.NewBinding(key.WithKeys("r"), key.WithHelp("r", "reply")),
Compose: key.NewBinding(key.WithKeys("c"), key.WithHelp("c", "compose")),
Archive: key.NewBinding(key.WithKeys("a"), key.WithHelp("a", "archive")),
Delete: key.NewBinding(key.WithKeys("d"), key.WithHelp("d", "delete")),
Search: key.NewBinding(key.WithKeys("/"), key.WithHelp("/", "search")),
Labels: key.NewBinding(key.WithKeys("l"), key.WithHelp("l", "labels")),
Expand Down
29 changes: 23 additions & 6 deletions ui/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.statusMessage = "Email sent!"
return m, tea.Batch(m.spinner.Tick, fetchInbox(m.client), clearStatusAfter(3*time.Second))

case emailArchivedMsg:
items := m.emailList.Items()
for i, item := range items {
if ei, ok := item.(emailItem); ok && ei.email.ID == msg.id {
m.emailList.RemoveItem(i)
break
}
}
if m.state == stateViewing {
m.state = stateInbox
}
m.statusMessage = "Email archived"
return m, clearStatusAfter(3 * time.Second)

case emailDeletedMsg:
items := m.emailList.Items()
for i, item := range items {
Expand Down Expand Up @@ -190,15 +204,13 @@ func (m Model) updateInbox(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return m, tea.Batch(m.spinner.Tick, openEmail(m.client, ei.email.ID))
}

case key.Matches(msg, keys.Delete):
case key.Matches(msg, keys.Archive):
if ei, ok := m.emailList.SelectedItem().(emailItem); ok {
m.confirmDelete = true
m.deleteTargetID = ei.email.ID
m.deleteSubject = ei.email.Subject
m.statusMessage = fmt.Sprintf("Delete \"%s\"? [y/n]", truncate(ei.email.Subject, 40))
return m, nil
return m, archiveEmailCmd(m.client, ei.email.ID)
}

case key.Matches(msg, keys.Delete):

case key.Matches(msg, keys.ToggleRead):
if ei, ok := m.emailList.SelectedItem().(emailItem); ok {
return m, toggleReadCmd(m.client, ei.email.ID, ei.email.IsUnread)
Expand Down Expand Up @@ -226,6 +238,11 @@ func (m Model) updateViewing(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
m.replyBody.Focus()
return m, nil

case key.Matches(msg, keys.Archive):
if m.currentEmail != nil {
return m, archiveEmailCmd(m.client, m.currentEmail.ID)
}

case key.Matches(msg, keys.Delete):
m.confirmDelete = true
m.deleteTargetID = m.currentEmail.ID
Expand Down
4 changes: 2 additions & 2 deletions ui/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (m Model) loadingView() string {
}

func (m Model) inboxView() string {
help := "\n[c] compose • [d] delete • [m] mark read/unread • [l] labels • [/] search • [?] help • [q] quit\n"
help := "\n[c] compose • [a] archive • [d] delete • [m] mark read/unread • [l] labels • [/] search • [?] help • [q] quit\n"
return m.emailList.View() + m.statusBar() + help
}

Expand Down Expand Up @@ -99,7 +99,7 @@ func (m Model) emailView() string {
}

b.WriteString(m.statusBar())
b.WriteString("\n[esc] back • [r] reply • [d] delete • [m] mark read/unread • [ctrl+d] download attachment • [q] quit\n")
b.WriteString("\n[esc] back • [r] reply • [a] archive • [d] delete • [m] mark read/unread • [ctrl+d] download attachment • [q] quit\n")
return b.String()
}

Expand Down