package main
import (
"context"
"fmt"
"strings"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/bubbles/list"
)
type listItem struct {
title string
desc string
id int64
started bool
}
func (item listItem) Title() string {
return item.title
}
func (item listItem) Description() string {
return item.desc
}
func (item listItem) FilterValue() string {
return item.title
}
type selectorItemsMsg = []list.Item
type selectedItemMsg = int64
func (model selector) changeItem(item list.Item) tea.Cmd {
if i, ok := item.(listItem); ok {
return func() tea.Msg {
return selectedItemMsg(i.id)
}
}
return nil
}
func (model selector) fetchScheduledTasks() tea.Msg {
row, err := model.config.queries.ScheduledTasks(context.Background())
if err != nil {
return errMsg{err}
}
items := make([]list.Item, len(row))
for i, e := range row {
var desc strings.Builder
desc.WriteString(fmt.Sprintf("Project: %s", e.ProjectName))
if e.DueAt.Valid {
desc.WriteString(fmt.Sprintf("\nDue: %s", e.DueAt.Time.Format("2006/02/01")))
}
items[i] = listItem{
title: e.Name,
desc: desc.String(),
id: e.ID,
started: e.StartAt.Valid,
}
}
return selectorItemsMsg(items)
}
type selector struct {
config *config
list list.Model
fetchFunc tea.Cmd
err error
width int
height int
}
func (model selector) Init() tea.Cmd {
return tea.Batch(model.fetchFunc, model.list.StartSpinner())
}
func (model selector) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
model.width = msg.Width
model.height = msg.Height
model.list.SetSize(model.width, model.height)
return model, nil
case selectorItemsMsg:
model.list.SetItems(msg)
model.list.StopSpinner()
if len(msg) > 0 {
if i, ok := msg[0].(listItem); ok {
return model, func () tea.Msg {
return selectedItemMsg(i.id)
}
}
}
return model, nil
case errMsg:
model.err = msg.err
model.list.StopSpinner()
return model, nil
case startedTaskMsg:
return model, tea.Batch(model.fetchFunc, model.list.StartSpinner())
}
var cmds []tea.Cmd
prevItem := model.list.SelectedItem()
newList, cmd := model.list.Update(msg)
cmds = append(cmds, cmd)
model.list = newList
if model.list.SelectedItem() != nil && model.list.FilterState() != list.Filtering && prevItem != model.list.SelectedItem() {
cmds = append(cmds, model.changeItem(model.list.SelectedItem()))
}
return model, tea.Batch(cmds...)
}
func (model selector) View() string {
if model.err != nil {
return lipgloss.PlaceHorizontal(model.width, lipgloss.Center, model.err.Error())
}
if len(model.list.Items()) < 1 {
model.list.SetShowStatusBar(false)
}
return lipgloss.NewStyle().Height(model.height).Width(model.width).Render(model.list.View())
}