Detailed changes
@@ -18,6 +18,7 @@ type mainModel struct {
current tea.Model
config *config.Config
emails []fetcher.Email
+ inbox *tui.Inbox
width int
height int
err error
@@ -58,10 +59,15 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if msg.String() == "ctrl+c" {
return m, tea.Quit
}
- // Allow ESC to go back to the main menu
+ // Allow ESC to go back
if msg.String() == "esc" {
- if _, ok := m.current.(*tui.Choice); !ok {
- m.current = tui.NewChoice()
+ // Check the type of the current view to decide where to go.
+ switch m.current.(type) {
+ case *tui.EmailView:
+ m.current = m.inbox // Go back to the cached inbox
+ return m, nil
+ case *tui.Inbox, *tui.Composer:
+ m.current = tui.NewChoice() // Go back to the main menu
return m, m.current.Init()
}
}
@@ -89,18 +95,21 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case tui.EmailsFetchedMsg:
m.emails = msg.Emails
- m.current = tui.NewInbox(m.emails)
+ m.inbox = tui.NewInbox(m.emails)
+ m.current = m.inbox
// Manually set the size of the new view
m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height})
cmds = append(cmds, m.current.Init())
case tui.GoToSendMsg:
+ // NewComposer now returns *Composer, so we assign it directly.
m.current = tui.NewComposer(m.config.Email)
m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height})
cmds = append(cmds, m.current.Init())
case tui.ViewEmailMsg:
- m.current = tui.NewEmailView(m.emails[msg.Index], m.width, m.height)
+ emailView := tui.NewEmailView(m.emails[msg.Index], m.width, m.height)
+ m.current = emailView
cmds = append(cmds, m.current.Init())
case tui.SendEmailMsg:
@@ -20,16 +20,16 @@ var (
// Composer model holds the state of the email composition UI.
type Composer struct {
- focusIndex int
- toInput textinput.Model
+ focusIndex int
+ toInput textinput.Model
subjectInput textinput.Model
- bodyInput textarea.Model
- fromAddr string
+ bodyInput textarea.Model
+ fromAddr string
}
// NewComposer initializes a new composer model.
-func NewComposer(from string) Composer {
- m := Composer{fromAddr: from}
+func NewComposer(from string) *Composer {
+ m := &Composer{fromAddr: from}
m.toInput = textinput.New()
m.toInput.Cursor.Style = cursorStyle
@@ -54,18 +54,19 @@ func NewComposer(from string) Composer {
return m
}
-func (m Composer) Init() tea.Cmd {
+func (m *Composer) Init() tea.Cmd {
return textinput.Blink
}
-func (m Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (m *Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.Type {
- case tea.KeyCtrlC, tea.KeyEsc:
+ // IMPORTANT: Removed tea.KeyEsc from this case
+ case tea.KeyCtrlC:
return m, tea.Quit
// Handle Tab and Shift+Tab to cycle focus between inputs.
@@ -82,7 +83,7 @@ func (m Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} else if m.focusIndex < 0 {
m.focusIndex = 3
}
-
+
// Blur all inputs
m.toInput.Blur()
m.subjectInput.Blur()
@@ -91,11 +92,11 @@ func (m Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Focus the correct input
switch m.focusIndex {
case 0:
- m.toInput.Focus()
+ cmds = append(cmds, m.toInput.Focus())
case 1:
- m.subjectInput.Focus()
+ cmds = append(cmds, m.subjectInput.Focus())
case 2:
- m.bodyInput.Focus()
+ cmds = append(cmds, m.bodyInput.Focus())
}
return m, tea.Batch(cmds...)
@@ -131,7 +132,7 @@ func (m Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
// View renders the UI.
-func (m Composer) View() string {
+func (m *Composer) View() string {
button := &blurredButton
if m.focusIndex == 3 {
button = &focusedButton
@@ -144,6 +145,6 @@ func (m Composer) View() string {
m.subjectInput.View(),
m.bodyInput.View(),
*button,
- helpStyle.Render("tab: next field • esc: quit"),
+ helpStyle.Render("tab: next field • esc: back to menu"),
)
}
@@ -19,29 +19,29 @@ func TestComposerUpdate(t *testing.T) {
}
// Simulate pressing Tab to move to the 'Subject' field.
- model, _ := composer.Update(tea.KeyMsg{Type: tea.KeyTab})
- composer = model.(Composer)
+ model, _ := composer.Update(tea.KeyMsg{Type: tea.KeyTab}) // model is tea.Model
+ composer = model.(*Composer) // Cast to *Composer
if composer.focusIndex != 1 {
t.Errorf("After one Tab, focusIndex should be 1, got %d", composer.focusIndex)
}
// Simulate pressing Tab again to move to the 'Body' field.
- model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab})
- composer = model.(Composer)
+ model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) // model is tea.Model
+ composer = model.(*Composer) // Cast to *Composer
if composer.focusIndex != 2 {
t.Errorf("After two Tabs, focusIndex should be 2, got %d", composer.focusIndex)
}
// Simulate pressing Tab again to move to the 'Send' button.
- model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab})
- composer = model.(Composer)
+ model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) // model is tea.Model
+ composer = model.(*Composer) // Cast to *Composer
if composer.focusIndex != 3 {
t.Errorf("After three Tabs, focusIndex should be 3 (Send), got %d", composer.focusIndex)
}
// Simulate one more Tab to wrap around to the 'To' field.
- model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab})
- composer = model.(Composer)
+ model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) // model is tea.Model
+ composer = model.(*Composer) // Cast to *Composer
if composer.focusIndex != 0 {
t.Errorf("After four Tabs, focusIndex should wrap to 0, got %d", composer.focusIndex)
}
@@ -11,8 +11,8 @@ import (
)
var (
- paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
- inboxHelpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
+ paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
+ inboxHelpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
)
type item struct {
@@ -50,7 +50,7 @@ type Inbox struct {
list list.Model
}
-func NewInbox(emails []fetcher.Email) Inbox {
+func NewInbox(emails []fetcher.Email) *Inbox {
items := make([]list.Item, len(emails))
for i, email := range emails {
items[i] = item{
@@ -67,14 +67,14 @@ func NewInbox(emails []fetcher.Email) Inbox {
l.Styles.PaginationStyle = paginationStyle
l.Styles.HelpStyle = inboxHelpStyle
- return Inbox{list: l}
+ return &Inbox{list: l}
}
-func (m Inbox) Init() tea.Cmd {
+func (m *Inbox) Init() tea.Cmd {
return nil
}
-func (m Inbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (m *Inbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
if msg.String() == "enter" {
@@ -92,10 +92,12 @@ func (m Inbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
var cmd tea.Cmd
- m.list, cmd = m.list.Update(msg)
+ var newModel list.Model
+ newModel, cmd = m.list.Update(msg)
+ m.list = newModel
return m, cmd
}
-func (m Inbox) View() string {
+func (m *Inbox) View() string {
return "\n" + m.list.View()
}
@@ -40,6 +40,9 @@ func ProcessBody(rawBody string) (string, error) {
return "", fmt.Errorf("could not parse email body: %w", err)
}
+ // Remove style and script tags to clean up the view
+ doc.Find("style, script").Remove()
+
// Add newlines after block elements for better spacing
doc.Find("p, div, h1, h2, h3, h4, h5, h6").Each(func(i int, s *goquery.Selection) {
s.After("\n\n")