Files
mail/inbox/model.go
Z.To 7ab9f00c4f Fearure:
- 增加收件箱功能(有BUG)
- 增加已发送|草稿箱|发送历史 本地记录
2026-04-09 21:48:21 +08:00

190 lines
3.9 KiB
Go

package inbox
import (
"fmt"
"io"
"time"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
type EmailItem struct {
UID uint32
From string
FromName string
Subject string
Date time.Time
Preview string
Account string
AccountID string
}
func (e EmailItem) FilterValue() string {
return fmt.Sprintf("%s %s %s %s", e.Account, e.FromName, e.From, e.Subject)
}
func (e EmailItem) Title() string {
return fmt.Sprintf("%s · %s - %s", e.Account, e.FromName, e.Subject)
}
func (e EmailItem) Description() string {
return e.Preview
}
func formatTimeAgo(d time.Duration) string {
if d < time.Minute {
return "刚刚"
}
if d < time.Hour {
mins := int(d.Minutes())
return fmt.Sprintf("%d分钟前", mins)
}
if d < 24*time.Hour {
hours := int(d.Hours())
return fmt.Sprintf("%d小时前", hours)
}
if d < 7*24*time.Hour {
days := int(d.Hours() / 24)
return fmt.Sprintf("%d天前", days)
}
return d.Truncate(24 * time.Hour).String()
}
type InboxModel struct {
list list.Model
emails []EmailItem
loading bool
err error
selectedEmail *EmailItem
}
func NewInboxModel() *InboxModel {
l := list.New(nil, emailDelegate{}, 0, 10)
l.Title = "收件箱"
l.Styles.Title = inboxTitleStyle
l.Styles.NoItems = inboxNoItemsStyle
l.SetShowHelp(true)
l.SetShowPagination(false)
return &InboxModel{
list: l,
emails: []EmailItem{},
}
}
func (m *InboxModel) SetEmails(emails []EmailItem) {
m.emails = emails
items := make([]list.Item, len(emails))
for i, e := range emails {
items[i] = e
}
m.list.SetItems(items)
m.list.Title = fmt.Sprintf("收件箱 (%d 封新邮件)", len(items))
}
func (m InboxModel) Init() tea.Cmd {
return nil
}
func (m *InboxModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
if msg.String() == "ctrl+c" {
return m, tea.Quit
}
case tea.WindowSizeMsg:
m.list.SetWidth(msg.Width)
}
var cmd tea.Cmd
m.list, cmd = m.list.Update(msg)
return m, cmd
}
func (m InboxModel) View() string {
if m.loading {
return loadingStyle.Render("正在加载邮件...")
}
if m.err != nil {
return errorStyle.Render(fmt.Sprintf("错误: %v", m.err))
}
return m.list.View()
}
func (m *InboxModel) SetLoading(loading bool) {
m.loading = loading
}
func (m *InboxModel) SetError(err error) {
m.err = err
}
func (m InboxModel) SelectedEmail() *EmailItem {
idx := m.list.Index()
if idx >= 0 && idx < len(m.emails) {
return &m.emails[idx]
}
return nil
}
var (
inboxTitleStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("86")).
Bold(true)
inboxNoItemsStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("241")).
Padding(1, 2)
loadingStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("86")).
Padding(1, 2)
errorStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("196")).
Padding(1, 2)
)
type emailDelegate struct{}
func (d emailDelegate) Height() int { return 1 }
func (d emailDelegate) Spacing() int { return 0 }
func (d emailDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
return nil
}
func (d emailDelegate) Render(w io.Writer, m list.Model, index int, item list.Item) {
email, ok := item.(EmailItem)
if !ok {
return
}
isSelected := index == m.Index()
titleStyle := emailTitleStyle
descStyle := emailDescStyle
if isSelected {
titleStyle = emailTitleStyleSelected
descStyle = emailDescStyleSelected
}
fmt.Fprintf(w, "%s\n%s", titleStyle.Render(email.Title()), descStyle.Render(email.Description()))
}
var (
emailTitleStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("255"))
emailTitleStyleSelected = lipgloss.NewStyle().
Foreground(lipgloss.Color("255")).
Background(lipgloss.Color("68"))
emailDescStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("241"))
emailDescStyleSelected = lipgloss.NewStyle().
Foreground(lipgloss.Color("186")).
Background(lipgloss.Color("68"))
)