Files
tasksquire/pages/report.go
Martin Pander 14dbfc406d [WIP] Layout
2024-05-22 16:20:57 +02:00

232 lines
5.5 KiB
Go

package pages
import (
"tasksquire/common"
"tasksquire/taskwarrior"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
type ReportPage struct {
common *common.Common
activeReport *taskwarrior.Report
activeContext *taskwarrior.Context
activeProject string
selectedTask *taskwarrior.Task
tasks taskwarrior.Tasks
taskTable table.Model
tableStyle table.Styles
keymap ReportKeys
subpage tea.Model
subpageActive bool
}
type ReportKeys struct {
Quit key.Binding
Up key.Binding
Down key.Binding
Select key.Binding
ToggleFocus key.Binding
}
func NewReportPage(com *common.Common, report *taskwarrior.Report) *ReportPage {
s := table.DefaultStyles()
s.Header = s.Header.
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(com.Styles.Active.GetForeground()).
BorderBottom(true).
Bold(true)
s.Selected = s.Selected.
Reverse(true).
Bold(true)
keys := ReportKeys{
Quit: key.NewBinding(
key.WithKeys("q", "ctrl+c"),
key.WithHelp("q, ctrl+c", "Quit"),
),
Up: key.NewBinding(
key.WithKeys("k", "up"),
key.WithHelp("↑/k", "Up"),
),
Down: key.NewBinding(
key.WithKeys("j", "down"),
key.WithHelp("↓/j", "Down"),
),
Select: key.NewBinding(
key.WithKeys("enter"),
key.WithHelp("enter", "Select"),
),
ToggleFocus: key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "Toggle focus"),
),
}
return &ReportPage{
common: com,
activeReport: report,
activeContext: com.TW.GetActiveContext(),
activeProject: "",
tableStyle: s,
keymap: keys,
}
}
func (p *ReportPage) SetSize(width int, height int) {
p.common.SetSize(width, height)
p.taskTable.SetWidth(width - 2)
p.taskTable.SetHeight(height - 4)
}
func (p *ReportPage) Init() tea.Cmd {
return p.getTasks()
}
func (p *ReportPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
switch msg := msg.(type) {
case tea.WindowSizeMsg:
p.SetSize(msg.Width, msg.Height)
case BackMsg:
p.subpageActive = false
case TaskMsg:
p.tasks = taskwarrior.Tasks(msg)
p.populateTaskTable(p.tasks)
case UpdateReportMsg:
p.activeReport = msg
cmds = append(cmds, p.getTasks())
case UpdateContextMsg:
p.activeContext = msg
p.common.TW.SetContext(msg)
cmds = append(cmds, p.getTasks())
case UpdateProjectMsg:
p.activeProject = string(msg)
cmds = append(cmds, p.getTasks())
case UpdatedTasksMsg:
cmds = append(cmds, p.getTasks())
case tea.KeyMsg:
switch {
case key.Matches(msg, p.common.Keymap.Quit):
return p, tea.Quit
case key.Matches(msg, p.common.Keymap.SetReport):
p.subpage = NewReportPickerPage(p.common, p.activeReport)
p.subpage.Init()
p.subpageActive = true
p.common.PushPage(p)
return p.subpage, nil
case key.Matches(msg, p.common.Keymap.SetContext):
p.subpage = NewContextPickerPage(p.common)
p.subpage.Init()
p.subpageActive = true
p.common.PushPage(p)
return p.subpage, nil
case key.Matches(msg, p.common.Keymap.Add):
p.subpage = NewTaskEditorPage(p.common, taskwarrior.Task{})
p.subpage.Init()
p.subpageActive = true
p.common.PushPage(p)
return p.subpage, nil
case key.Matches(msg, p.common.Keymap.Edit):
p.subpage = NewTaskEditorPage(p.common, *p.selectedTask)
p.subpage.Init()
p.subpageActive = true
p.common.PushPage(p)
return p.subpage, nil
case key.Matches(msg, p.common.Keymap.SetProject):
p.subpage = NewProjectPickerPage(p.common, p.activeProject)
p.subpage.Init()
p.subpageActive = true
p.common.PushPage(p)
return p.subpage, nil
}
}
var cmd tea.Cmd
p.taskTable, cmd = p.taskTable.Update(msg)
cmds = append(cmds, cmd)
if p.tasks != nil && len(p.tasks) > 0 {
p.selectedTask = (*taskwarrior.Task)(p.tasks[p.taskTable.Cursor()])
} else {
p.selectedTask = nil
}
return p, tea.Batch(cmds...)
}
func (p *ReportPage) View() string {
// return p.common.Styles.Main.Render(p.taskTable.View()) + "\n"
if p.tasks == nil || len(p.tasks) == 0 {
return p.common.Styles.Main.Render("No tasks found")
}
return p.common.Styles.Main.Render(p.taskTable.View())
}
func (p *ReportPage) populateTaskTable(tasks taskwarrior.Tasks) {
nCols := len(p.activeReport.Columns)
columns := make([]table.Column, 0)
columnSizes := make([]int, nCols)
fullRows := make([]table.Row, len(tasks))
rows := make([]table.Row, len(tasks))
for i, task := range tasks {
row := table.Row{}
for i, col := range p.activeReport.Columns {
field := task.GetString(col)
columnSizes[i] = max(columnSizes[i], len(field))
row = append(row, field)
}
fullRows[i] = row
}
for i, r := range fullRows {
row := table.Row{}
for j, size := range columnSizes {
if size == 0 {
continue
}
row = append(row, r[j])
}
rows[i] = row
}
for i, label := range p.activeReport.Labels {
if columnSizes[i] == 0 {
continue
}
columns = append(columns, table.Column{Title: label, Width: max(columnSizes[i], len(label))})
}
p.taskTable = table.New(
table.WithColumns(columns),
table.WithRows(rows),
table.WithFocused(true),
// table.WithHeight(7),
// table.WithWidth(100),
)
p.taskTable.SetStyles(p.tableStyle)
}
func (p *ReportPage) getTasks() tea.Cmd {
return func() tea.Msg {
filters := []string{}
if p.activeProject != "" {
filters = append(filters, "project:"+p.activeProject)
}
tasks := p.common.TW.GetTasks(p.activeReport, filters...)
return TaskMsg(tasks)
}
}
type TaskMsg taskwarrior.Tasks