main.go

  1package main
  2
  3import (
  4	"fmt"
  5	"log"
  6	"os"
  7	"time"
  8
  9	"github.com/andrinoff/email-cli/config"
 10	"github.com/andrinoff/email-cli/fetcher"
 11	"github.com/andrinoff/email-cli/sender"
 12	"github.com/andrinoff/email-cli/tui"
 13	tea "github.com/charmbracelet/bubbletea"
 14)
 15
 16// mainModel now holds the state for the entire application.
 17type mainModel struct {
 18	current tea.Model
 19	config  *config.Config
 20	emails  []fetcher.Email
 21	width   int
 22	height  int
 23	err     error
 24}
 25
 26// newInitialModel now returns a pointer, which is crucial for state management.
 27func newInitialModel(cfg *config.Config) *mainModel {
 28	return &mainModel{
 29		current: tui.NewChoice(),
 30		config:  cfg,
 31	}
 32}
 33
 34func (m *mainModel) Init() tea.Cmd {
 35	return m.current.Init()
 36}
 37
 38func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 39	var cmd tea.Cmd
 40	var cmds []tea.Cmd
 41
 42	switch msg := msg.(type) {
 43	case tea.WindowSizeMsg:
 44		m.width = msg.Width
 45		m.height = msg.Height
 46		// Pass the window size message to the current view
 47		m.current, cmd = m.current.Update(msg)
 48		cmds = append(cmds, cmd)
 49		return m, tea.Batch(cmds...)
 50
 51	case tea.KeyMsg:
 52		if msg.String() == "ctrl+c" {
 53			return m, tea.Quit
 54		}
 55		// Allow ESC to go back to the main menu
 56		if msg.String() == "esc" {
 57			if _, ok := m.current.(*tui.Choice); !ok {
 58				m.current = tui.NewChoice()
 59				return m, m.current.Init()
 60			}
 61		}
 62
 63	// --- Custom Messages for switching views ---
 64	case tui.GoToInboxMsg:
 65		m.current = tui.NewStatus("Fetching emails...")
 66		return m, tea.Batch(m.current.Init(), fetchEmails(m.config))
 67
 68	case tui.EmailsFetchedMsg:
 69		m.emails = msg.Emails
 70		m.current = tui.NewInbox(m.emails)
 71		// Manually set the size of the new view
 72		m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height})
 73		cmds = append(cmds, m.current.Init())
 74
 75	case tui.GoToSendMsg:
 76		m.current = tui.NewComposer(m.config.Email)
 77		m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height})
 78		cmds = append(cmds, m.current.Init())
 79
 80	case tui.ViewEmailMsg:
 81		m.current = tui.NewEmailView(m.emails[msg.Index], m.width, m.height)
 82		cmds = append(cmds, m.current.Init())
 83
 84	case tui.SendEmailMsg:
 85		m.current = tui.NewStatus("Sending email...")
 86		cmds = append(cmds, m.current.Init(), sendEmail(m.config, msg))
 87
 88	case tui.EmailResultMsg:
 89		m.current = tui.NewChoice()
 90		cmds = append(cmds, m.current.Init())
 91	}
 92
 93	// Pass all other messages to the current view
 94	m.current, cmd = m.current.Update(msg)
 95	cmds = append(cmds, cmd)
 96
 97	return m, tea.Batch(cmds...)
 98}
 99
100func (m *mainModel) View() string {
101	return m.current.View()
102}
103
104// sendEmail is a command that sends an email in the background.
105func sendEmail(cfg *config.Config, msg tui.SendEmailMsg) tea.Cmd {
106	return func() tea.Msg {
107		recipients := []string{msg.To}
108		err := sender.SendEmail(cfg, recipients, msg.Subject, msg.Body)
109		if err != nil {
110			log.Printf("Failed to send email: %v", err) // Log error
111			return tui.EmailResultMsg{Err: err}
112		}
113		time.Sleep(1 * time.Second) // Give user time to see the "Sending" message
114		return tui.EmailResultMsg{}
115	}
116}
117
118func fetchEmails(cfg *config.Config) tea.Cmd {
119	return func() tea.Msg {
120		emails, err := fetcher.FetchEmails(cfg)
121		if err != nil {
122			return tui.FetchErr(err)
123		}
124		return tui.EmailsFetchedMsg{Emails: emails}
125	}
126}
127
128func main() {
129	cfg, err := config.LoadConfig()
130	if err != nil {
131		// If the config doesn't exist, we can guide the user to create one.
132		// For now, we'll just log a fatal error.
133		log.Fatalf("could not load config: %v", err)
134	}
135
136	p := tea.NewProgram(newInitialModel(cfg), tea.WithAltScreen())
137
138	if _, err := p.Run(); err != nil {
139		fmt.Printf("Alas, there's been an error: %v", err)
140		os.Exit(1)
141	}
142}