tui: cleanup conversations data model

This commit is contained in:
Matt Low 2024-04-01 21:26:45 +00:00
parent 1404cae6a7
commit 0e68e22efa
1 changed files with 59 additions and 74 deletions

View File

@ -13,18 +13,22 @@ import (
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
) )
type loadedConversation struct {
conv models.Conversation
lastReply models.Message
}
type ( type (
// send when conversation list is loaded // sent when conversation list is loaded
msgConversationsLoaded []models.Conversation msgConversationsLoaded ([]loadedConversation)
// sent when each coversation's 'last reply' is loaded
) )
type conversationsModel struct { type conversationsModel struct {
basemodel basemodel
conversations []models.Conversation conversations []loadedConversation
lastReplies []models.Message content viewport.Model
content viewport.Model
} }
func newConversationsModel(tui *model) conversationsModel { func newConversationsModel(tui *model) conversationsModel {
@ -102,24 +106,29 @@ func (m conversationsModel) Update(msg tea.Msg) (conversationsModel, tea.Cmd) {
func (m *conversationsModel) loadConversations() tea.Cmd { func (m *conversationsModel) loadConversations() tea.Cmd {
return func() tea.Msg { return func() tea.Msg {
c, err := m.ctx.Store.Conversations() conversations, err := m.ctx.Store.Conversations()
if err != nil { if err != nil {
return msgError(fmt.Errorf("Could not load conversations: %v", err)) return msgError(fmt.Errorf("Could not load conversations: %v", err))
} }
return msgConversationsLoaded(c)
loaded := make([]loadedConversation, len(conversations))
for i, c := range conversations {
lastMessage, err := m.ctx.Store.LastMessage(&c)
if err != nil {
return msgError(err)
}
loaded[i].conv = c
loaded[i].lastReply = *lastMessage
}
slices.SortFunc(loaded, func(a, b loadedConversation) int {
return b.lastReply.CreatedAt.Compare(a.lastReply.CreatedAt)
})
return msgConversationsLoaded(loaded)
} }
} }
//func (m *conversationsModel) loadConversationLastestReplies(conversations []models.Conversation) tea.Cmd {
// return func() tea.Msg {
// //lastMessage, err := m.ctx.Store.LastMessage(&conversation)
// return nil
// }
//}
//func (m *conversationsModel) setConversations(conversations []models.Conversation) {
//}
func (m *conversationsModel) headerView() string { func (m *conversationsModel) headerView() string {
titleStyle := lipgloss.NewStyle().Bold(true) titleStyle := lipgloss.NewStyle().Bold(true)
header := titleStyle.Render("Conversations") header := titleStyle.Render("Conversations")
@ -127,13 +136,12 @@ func (m *conversationsModel) headerView() string {
} }
func (m *conversationsModel) renderConversationList() string { func (m *conversationsModel) renderConversationList() string {
sb := &strings.Builder{} type timeCategory struct {
type AgeGroup struct {
name string name string
cutoff time.Duration cutoff time.Duration
} }
type ConversationLine struct { type listItem struct {
id uint id uint
short string short string
title string title string
@ -142,11 +150,10 @@ func (m *conversationsModel) renderConversationList() string {
} }
now := time.Now() now := time.Now()
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
dayOfWeek := int(now.Weekday()) dayOfWeek := int(now.Weekday())
categories := []AgeGroup{ categories := []timeCategory{
{"Today", now.Sub(midnight)}, {"Today", now.Sub(midnight)},
{"Yesterday", now.Sub(midnight.AddDate(0, 0, -1))}, {"Yesterday", now.Sub(midnight.AddDate(0, 0, -1))},
{"This week", now.Sub(midnight.AddDate(0, 0, -dayOfWeek))}, {"This week", now.Sub(midnight.AddDate(0, 0, -dayOfWeek))},
@ -160,32 +167,6 @@ func (m *conversationsModel) renderConversationList() string {
{"6 Months ago", now.Sub(monthStart.AddDate(0, -6, 0))}, {"6 Months ago", now.Sub(monthStart.AddDate(0, -6, 0))},
{"Older", now.Sub(time.Time{})}, {"Older", now.Sub(time.Time{})},
} }
categorized := map[string][]ConversationLine{}
for _, conversation := range m.conversations {
lastMessage, err := m.ctx.Store.LastMessage(&conversation)
if lastMessage == nil || err != nil {
continue
}
messageAge := now.Sub(lastMessage.CreatedAt)
var category string
for _, c := range categories {
if messageAge < c.cutoff {
category = c.name
break
}
}
categorized[category] = append(
categorized[category],
ConversationLine{
id: conversation.ID,
title: conversation.Title,
short: conversation.ShortName.String,
lastReplyAge: messageAge,
},
)
}
// TODO: pick nice color // TODO: pick nice color
categoryStyle := lipgloss.NewStyle(). categoryStyle := lipgloss.NewStyle().
@ -198,35 +179,39 @@ func (m *conversationsModel) renderConversationList() string {
MarginBottom(1). MarginBottom(1).
PaddingLeft(2) PaddingLeft(2)
for _, category := range categories { ageStyle := lipgloss.NewStyle().Faint(true)
conversationLines, ok := categorized[category.name] titleStyle := lipgloss.NewStyle().Bold(true)
if !ok { untitledStyle := titleStyle.Copy().Italic(true).Faint(true).SetString("(untitled)")
continue
}
slices.SortFunc(conversationLines, func(a, b ConversationLine) int { var currentCategory string
return int(a.lastReplyAge - b.lastReplyAge) sb := &strings.Builder{}
}) for _, c := range m.conversations {
lastReplyAge := now.Sub(c.lastReply.CreatedAt)
ageStyle := lipgloss.NewStyle().Faint(true) var category string
titleStyle := lipgloss.NewStyle().Bold(true) for _, g := range categories {
untitledStyle := titleStyle.Copy().Italic(true).SetString("(untitled)") if lastReplyAge < g.cutoff {
category = g.name
fmt.Fprintf(sb, "%s\n", categoryStyle.Render(category.name)) break
for _, c := range conversationLines {
tstyle := titleStyle
if c.title == "" {
tstyle = untitledStyle
} }
heading := fmt.Sprintf(
"%s\n%s",
tstyle.Render(c.title),
ageStyle.Render(util.HumanTimeElapsedSince(c.lastReplyAge)),
)
sb.WriteString(conversationHeadingStyle.Render(heading))
sb.WriteRune('\n')
} }
}
if category != currentCategory {
currentCategory = category
fmt.Fprintf(sb, "%s\n", categoryStyle.Render(currentCategory))
}
tstyle := titleStyle
if c.conv.Title == "" {
tstyle = untitledStyle
}
heading := fmt.Sprintf(
"%s\n%s",
tstyle.Render(c.conv.Title),
ageStyle.Render(util.HumanTimeElapsedSince(lastReplyAge)),
)
sb.WriteString(conversationHeadingStyle.Render(heading))
sb.WriteRune('\n')
}
return sb.String() return sb.String()
} }