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