package pages import ( "log/slog" "slices" "tasksquire/common" "tasksquire/components/picker" "tasksquire/taskwarrior" "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) type ReportPickerPage struct { common *common.Common reports taskwarrior.Reports picker *picker.Picker } func NewReportPickerPage(common *common.Common, activeReport *taskwarrior.Report) *ReportPickerPage { p := &ReportPickerPage{ common: common, reports: common.TW.GetReports(), } itemProvider := func() []list.Item { options := make([]string, 0) for _, r := range p.reports { options = append(options, r.Name) } slices.Sort(options) items := []list.Item{} for _, opt := range options { items = append(items, picker.NewItem(opt)) } return items } onSelect := func(item list.Item) tea.Cmd { return func() tea.Msg { return reportSelectedMsg{item: item} } } p.picker = picker.New(common, "Reports", itemProvider, onSelect) if activeReport != nil { p.picker.SelectItemByFilterValue(activeReport.Name) } p.SetSize(common.Width(), common.Height()) return p } func (p *ReportPickerPage) SetSize(width, height int) { p.common.SetSize(width, height) // Set list size with some padding/limits to look like a picker listWidth := width - 4 if listWidth > 40 { listWidth = 40 } listHeight := height - 6 if listHeight > 20 { listHeight = 20 } p.picker.SetSize(listWidth, listHeight) } func (p *ReportPickerPage) Init() tea.Cmd { return p.picker.Init() } type reportSelectedMsg struct { item list.Item } func (p *ReportPickerPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd switch msg := msg.(type) { case tea.WindowSizeMsg: p.SetSize(msg.Width, msg.Height) case reportSelectedMsg: reportName := msg.item.FilterValue() report := p.common.TW.GetReport(reportName) model, err := p.common.PopPage() if err != nil { slog.Error("page stack empty") return nil, tea.Quit } return model, func() tea.Msg { return UpdateReportMsg(report) } case tea.KeyMsg: if !p.picker.IsFiltering() { switch { case key.Matches(msg, p.common.Keymap.Back): model, err := p.common.PopPage() if err != nil { slog.Error("page stack empty") return nil, tea.Quit } return model, BackCmd } } } _, cmd = p.picker.Update(msg) return p, cmd } func (p *ReportPickerPage) View() string { width := p.common.Width() - 4 if width > 40 { width = 40 } content := p.picker.View() styledContent := lipgloss.NewStyle().Width(width).Render(content) return lipgloss.Place( p.common.Width(), p.common.Height(), lipgloss.Center, lipgloss.Center, p.common.Styles.Base.Render(styledContent), ) } type UpdateReportMsg *taskwarrior.Report