913 lines
20 KiB
Go
913 lines
20 KiB
Go
package pages
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"slices"
|
|
"strings"
|
|
"tasksquire/common"
|
|
|
|
"tasksquire/taskwarrior"
|
|
|
|
"github.com/charmbracelet/bubbles/key"
|
|
"github.com/charmbracelet/bubbles/list"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/huh"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
type mode int
|
|
|
|
const (
|
|
modeNormal mode = iota
|
|
modeInsert
|
|
)
|
|
|
|
type TaskEditorPage struct {
|
|
common *common.Common
|
|
task taskwarrior.Task
|
|
|
|
mode mode
|
|
|
|
columnCursor int
|
|
|
|
area area
|
|
areaPicker *areaPicker
|
|
areas map[area]tea.Model
|
|
}
|
|
|
|
func NewTaskEditorPage(com *common.Common, task taskwarrior.Task) *TaskEditorPage {
|
|
p := TaskEditorPage{
|
|
common: com,
|
|
task: task,
|
|
}
|
|
|
|
if p.task.Priority == "" {
|
|
p.task.Priority = "(none)"
|
|
}
|
|
if p.task.Project == "" {
|
|
p.task.Project = "(none)"
|
|
}
|
|
|
|
priorityOptions := append([]string{"(none)"}, p.common.TW.GetPriorities()...)
|
|
projectOptions := append([]string{"(none)"}, p.common.TW.GetProjects()...)
|
|
tagOptions := p.common.TW.GetTags()
|
|
tagOptions = append(tagOptions, strings.Split(p.common.TW.GetConfig().Get("uda.tasksquire.tags.default"), ",")...)
|
|
slices.Sort(tagOptions)
|
|
|
|
p.areas = map[area]tea.Model{
|
|
areaTask: NewTaskEdit(p.common, &p.task.Description, &p.task.Priority, &p.task.Project, priorityOptions, projectOptions),
|
|
areaTags: NewTagEdit(p.common, &p.task.Tags, tagOptions),
|
|
areaTime: NewTimeEdit(p.common, &p.task.Due, &p.task.Scheduled, &p.task.Wait, &p.task.Until),
|
|
}
|
|
|
|
// p.areaList = NewAreaList(common, areaItems)
|
|
// p.selectedArea = areaTask
|
|
// p.columns = append([]tea.Model{p.areaList}, p.areas[p.selectedArea]...)
|
|
|
|
p.areaPicker = NewAreaPicker(com, []string{"Task", "Tags", "Dates"})
|
|
|
|
p.columnCursor = 1
|
|
if p.task.Uuid == "" {
|
|
// p.mode = modeInsert
|
|
p.mode = modeInsert
|
|
} else {
|
|
p.mode = modeNormal
|
|
}
|
|
|
|
return &p
|
|
}
|
|
|
|
func (p *TaskEditorPage) SetSize(width, height int) {
|
|
p.common.SetSize(width, height)
|
|
}
|
|
|
|
func (p *TaskEditorPage) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
func (p *TaskEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case changeAreaMsg:
|
|
p.area = area(msg)
|
|
case changeModeMsg:
|
|
p.mode = mode(msg)
|
|
case prevColumnMsg:
|
|
p.columnCursor--
|
|
if p.columnCursor < 0 {
|
|
p.columnCursor = len(p.areas) - 1
|
|
}
|
|
case nextColumnMsg:
|
|
p.columnCursor++
|
|
if p.columnCursor > len(p.areas)-1 {
|
|
p.columnCursor = 0
|
|
}
|
|
case prevAreaMsg:
|
|
p.area--
|
|
if p.area < 0 {
|
|
p.area = 2
|
|
}
|
|
case nextAreaMsg:
|
|
p.area++
|
|
if p.area > 2 {
|
|
p.area = 0
|
|
}
|
|
}
|
|
|
|
switch p.mode {
|
|
case modeNormal:
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
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
|
|
case key.Matches(msg, p.common.Keymap.Insert):
|
|
return p, changeMode(modeInsert)
|
|
case key.Matches(msg, p.common.Keymap.Ok):
|
|
model, err := p.common.PopPage()
|
|
if err != nil {
|
|
slog.Error("page stack empty")
|
|
return nil, tea.Quit
|
|
}
|
|
return model, p.updateTasksCmd
|
|
case key.Matches(msg, p.common.Keymap.Left):
|
|
return p, prevColumn()
|
|
case key.Matches(msg, p.common.Keymap.Right):
|
|
return p, nextColumn()
|
|
case key.Matches(msg, p.common.Keymap.Up):
|
|
var cmd tea.Cmd
|
|
if p.columnCursor == 0 {
|
|
picker, cmd := p.areaPicker.Update(msg)
|
|
p.areaPicker = picker.(*areaPicker)
|
|
return p, cmd
|
|
} else {
|
|
p.areas[p.area], cmd = p.areas[p.area].Update(prevFieldMsg{})
|
|
return p, cmd
|
|
}
|
|
case key.Matches(msg, p.common.Keymap.Down):
|
|
var cmd tea.Cmd
|
|
if p.columnCursor == 0 {
|
|
picker, cmd := p.areaPicker.Update(msg)
|
|
p.areaPicker = picker.(*areaPicker)
|
|
return p, cmd
|
|
} else {
|
|
p.areas[p.area], cmd = p.areas[p.area].Update(nextFieldMsg{})
|
|
return p, cmd
|
|
}
|
|
}
|
|
}
|
|
|
|
// var cmd tea.Cmd
|
|
// if p.columnCursor == 0 {
|
|
// p., cmd = p.areaList.Update(msg)
|
|
// p.selectedArea = p.areaList.(areaList).Area()
|
|
// cmds = append(cmds, cmd)
|
|
// } else {
|
|
// p.areas[p.selectedArea][p.columnCursor-1], cmd = p.areas[p.selectedArea][p.columnCursor-1].Update(msg)
|
|
// cmds = append(cmds, cmd)
|
|
// }
|
|
case modeInsert:
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
switch {
|
|
case key.Matches(msg, p.common.Keymap.Back):
|
|
return p, changeMode(modeNormal)
|
|
case key.Matches(msg, p.common.Keymap.Ok):
|
|
area, cmd := p.areas[p.area].Update(msg)
|
|
p.areas[p.area] = area
|
|
return p, tea.Batch(cmd, nextField())
|
|
}
|
|
}
|
|
|
|
var cmd tea.Cmd
|
|
if p.columnCursor == 0 {
|
|
picker, cmd := p.areaPicker.Update(msg)
|
|
p.areaPicker = picker.(*areaPicker)
|
|
return p, cmd
|
|
} else {
|
|
p.areas[p.area], cmd = p.areas[p.area].Update(msg)
|
|
return p, cmd
|
|
}
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
func (p *TaskEditorPage) View() string {
|
|
var focusStyle lipgloss.Style
|
|
if p.mode == modeInsert {
|
|
focusStyle = p.common.Styles.ColumnInsert
|
|
} else {
|
|
focusStyle = p.common.Styles.ColumnFocused
|
|
}
|
|
var picker, area string
|
|
if p.columnCursor == 0 {
|
|
picker = focusStyle.Render(p.areaPicker.View())
|
|
area = p.common.Styles.ColumnBlurred.Render(p.areas[p.area].View())
|
|
} else {
|
|
picker = p.common.Styles.ColumnBlurred.Render(p.areaPicker.View())
|
|
area = focusStyle.Render(p.areas[p.area].View())
|
|
|
|
}
|
|
return lipgloss.JoinHorizontal(
|
|
lipgloss.Left,
|
|
picker,
|
|
area,
|
|
)
|
|
}
|
|
|
|
// import (
|
|
// "fmt"
|
|
// "io"
|
|
// "log/slog"
|
|
// "strings"
|
|
// "tasksquire/common"
|
|
// "tasksquire/taskwarrior"
|
|
// "time"
|
|
|
|
// "github.com/charmbracelet/bubbles/list"
|
|
// "github.com/charmbracelet/bubbles/textinput"
|
|
// tea "github.com/charmbracelet/bubbletea"
|
|
// "github.com/charmbracelet/huh"
|
|
// "github.com/charmbracelet/lipgloss"
|
|
// )
|
|
|
|
// type Field int
|
|
|
|
// const (
|
|
// FieldDescription Field = iota
|
|
// FieldPriority
|
|
// FieldProject
|
|
// FieldNewProject
|
|
// FieldTags
|
|
// FieldNewTags
|
|
// FieldDue
|
|
// FieldScheduled
|
|
// FieldWait
|
|
// FieldUntil
|
|
// )
|
|
|
|
// type column int
|
|
|
|
// const (
|
|
// column1 column = iota
|
|
// column2
|
|
// column3
|
|
// )
|
|
|
|
// func changeColumn(c column) tea.Cmd {
|
|
// return func() tea.Msg {
|
|
// return changeColumnMsg(c)
|
|
// }
|
|
// }
|
|
|
|
// type changeColumnMsg column
|
|
|
|
// type mode int
|
|
|
|
// const (
|
|
// modeNormal mode = iota
|
|
// modeInsert
|
|
// modeAddTag
|
|
// modeAddProject
|
|
// )
|
|
|
|
// type TaskEditorPage struct {
|
|
// common *common.Common
|
|
// task taskwarrior.Task
|
|
// areaList tea.Model
|
|
// mode mode
|
|
// statusline tea.Model
|
|
|
|
// // TODO: rework support for adding tags and projects
|
|
// additionalTags string
|
|
// additionalProject string
|
|
|
|
// columnCursor int
|
|
// columns []tea.Model
|
|
|
|
// areas map[area][]tea.Model
|
|
// selectedArea area
|
|
// }
|
|
|
|
// type TaskEditorKeys struct {
|
|
// Quit key.Binding
|
|
// Up key.Binding
|
|
// Down key.Binding
|
|
// Select key.Binding
|
|
// ToggleFocus key.Binding
|
|
// }
|
|
|
|
// func NewTaskEditorPage(common *common.Common, task taskwarrior.Task) *TaskEditorPage {
|
|
// p := &TaskEditorPage{
|
|
// common: common,
|
|
// task: task,
|
|
// }
|
|
|
|
// if p.task.Uuid == "" {
|
|
// p.mode = modeInsert
|
|
// } else {
|
|
// p.mode = modeNormal
|
|
// }
|
|
|
|
// areaItems := []list.Item{
|
|
// item("Task"),
|
|
// item("Tags"),
|
|
// item("Time"),
|
|
// }
|
|
|
|
// }
|
|
|
|
// p.statusline = NewStatusLine(common, p.mode)
|
|
|
|
// return p
|
|
// }
|
|
|
|
type area int
|
|
|
|
const (
|
|
areaTask area = iota
|
|
areaTags
|
|
areaTime
|
|
)
|
|
|
|
type areaPicker struct {
|
|
common *common.Common
|
|
list list.Model
|
|
}
|
|
|
|
type item string
|
|
|
|
func (i item) Title() string { return string(i) }
|
|
func (i item) Description() string { return "test" }
|
|
func (i item) FilterValue() string { return "" }
|
|
|
|
func NewAreaPicker(common *common.Common, items []string) *areaPicker {
|
|
listItems := make([]list.Item, len(items))
|
|
for i, itm := range items {
|
|
listItems[i] = item(itm)
|
|
}
|
|
|
|
list := list.New(listItems, list.DefaultDelegate{}, 20, 50)
|
|
list.SetFilteringEnabled(false)
|
|
list.SetShowStatusBar(false)
|
|
|
|
return &areaPicker{
|
|
common: common,
|
|
list: list,
|
|
}
|
|
}
|
|
|
|
func (a *areaPicker) Area() area {
|
|
switch a.list.SelectedItem() {
|
|
case item("Task"):
|
|
return areaTask
|
|
case item("Tags"):
|
|
return areaTags
|
|
case item("Dates"):
|
|
return areaTime
|
|
default:
|
|
return areaTask
|
|
}
|
|
}
|
|
|
|
func (a *areaPicker) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
func (a *areaPicker) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
var cmds []tea.Cmd
|
|
var cmd tea.Cmd
|
|
cursor := a.list.Cursor()
|
|
// switch msg.(type) {
|
|
// case nextFieldMsg:
|
|
// a.list, cmd = a.list.Update(a.list.KeyMap.CursorDown)
|
|
// case prevFieldMsg:
|
|
// a.list, cmd = a.list.Update(a.list.KeyMap.CursorUp)
|
|
// }
|
|
a.list, cmd = a.list.Update(msg)
|
|
cmds = append(cmds, cmd)
|
|
if cursor != a.list.Cursor() {
|
|
cmds = append(cmds, changeArea(a.Area()))
|
|
}
|
|
|
|
return a, tea.Batch(cmds...)
|
|
}
|
|
|
|
func (a *areaPicker) View() string {
|
|
return a.list.View()
|
|
}
|
|
|
|
type taskEdit struct {
|
|
common *common.Common
|
|
fields []huh.Field
|
|
cursor int
|
|
|
|
newProjectName *string
|
|
}
|
|
|
|
func NewTaskEdit(common *common.Common, description *string, priority *string, project *string, priorityOptions []string, projectOptions []string) *taskEdit {
|
|
newProject := ""
|
|
|
|
defaultKeymap := huh.NewDefaultKeyMap()
|
|
|
|
t := taskEdit{
|
|
common: common,
|
|
fields: []huh.Field{
|
|
huh.NewInput().
|
|
Title("Task").
|
|
Value(description).
|
|
Validate(func(desc string) error {
|
|
if desc == "" {
|
|
return fmt.Errorf("task description is required")
|
|
}
|
|
return nil
|
|
}).
|
|
Inline(true).
|
|
WithTheme(common.Styles.Form),
|
|
|
|
huh.NewSelect[string]().
|
|
Options(huh.NewOptions(priorityOptions...)...).
|
|
Title("Priority").
|
|
Key("priority").
|
|
Value(priority).
|
|
WithKeyMap(defaultKeymap).
|
|
WithTheme(common.Styles.Form),
|
|
|
|
huh.NewSelect[string]().
|
|
Options(huh.NewOptions(projectOptions...)...).
|
|
Title("Project").
|
|
Value(project).
|
|
WithKeyMap(defaultKeymap).
|
|
WithTheme(common.Styles.Form),
|
|
|
|
huh.NewInput().
|
|
Title("New Project").
|
|
Value(&newProject).
|
|
WithTheme(common.Styles.Form),
|
|
},
|
|
|
|
newProjectName: &newProject,
|
|
}
|
|
|
|
t.fields[0].Focus()
|
|
|
|
return &t
|
|
}
|
|
|
|
func (t taskEdit) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
func (t taskEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg.(type) {
|
|
case nextFieldMsg:
|
|
if t.cursor == len(t.fields)-1 {
|
|
t.fields[t.cursor].Blur()
|
|
return t, nextArea()
|
|
}
|
|
t.fields[t.cursor].Blur()
|
|
t.cursor++
|
|
t.fields[t.cursor].Focus()
|
|
case prevFieldMsg:
|
|
if t.cursor == 0 {
|
|
t.fields[t.cursor].Blur()
|
|
return t, prevArea()
|
|
}
|
|
t.fields[t.cursor].Blur()
|
|
t.cursor--
|
|
t.fields[t.cursor].Focus()
|
|
default:
|
|
field, cmd := t.fields[t.cursor].Update(msg)
|
|
t.fields[t.cursor] = field.(huh.Field)
|
|
return t, cmd
|
|
}
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func (t taskEdit) View() string {
|
|
views := make([]string, len(t.fields))
|
|
for i, field := range t.fields {
|
|
views[i] = field.View()
|
|
}
|
|
return lipgloss.JoinVertical(
|
|
lipgloss.Left,
|
|
views...,
|
|
)
|
|
}
|
|
|
|
type tagEdit struct {
|
|
common *common.Common
|
|
fields []huh.Field
|
|
|
|
cursor int
|
|
|
|
newTagsValue *string
|
|
}
|
|
|
|
func NewTagEdit(common *common.Common, selected *[]string, options []string) *tagEdit {
|
|
newTags := ""
|
|
|
|
defaultKeymap := huh.NewDefaultKeyMap()
|
|
|
|
t := tagEdit{
|
|
common: common,
|
|
fields: []huh.Field{
|
|
huh.NewMultiSelect[string]().
|
|
Options(huh.NewOptions(options...)...).
|
|
// Key("tags").
|
|
Title("Tags").
|
|
Value(selected).
|
|
Filterable(true).
|
|
WithKeyMap(defaultKeymap).
|
|
WithTheme(common.Styles.Form),
|
|
huh.NewInput().
|
|
Title("New Tags").
|
|
Value(&newTags).
|
|
Inline(true).
|
|
WithTheme(common.Styles.Form),
|
|
},
|
|
newTagsValue: &newTags,
|
|
}
|
|
|
|
t.fields[0].Focus()
|
|
|
|
return &t
|
|
}
|
|
|
|
func (t tagEdit) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
func (t tagEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg.(type) {
|
|
case nextFieldMsg:
|
|
if t.cursor == len(t.fields)-1 {
|
|
t.fields[t.cursor].Blur()
|
|
return t, nextArea()
|
|
}
|
|
t.fields[t.cursor].Blur()
|
|
t.cursor++
|
|
t.fields[t.cursor].Focus()
|
|
case prevFieldMsg:
|
|
if t.cursor == 0 {
|
|
t.fields[t.cursor].Blur()
|
|
return t, prevArea()
|
|
}
|
|
t.fields[t.cursor].Blur()
|
|
t.cursor--
|
|
t.fields[t.cursor].Focus()
|
|
default:
|
|
field, cmd := t.fields[t.cursor].Update(msg)
|
|
t.fields[t.cursor] = field.(huh.Field)
|
|
return t, cmd
|
|
}
|
|
return t, nil
|
|
}
|
|
|
|
func (t tagEdit) View() string {
|
|
views := make([]string, len(t.fields))
|
|
for i, field := range t.fields {
|
|
views[i] = field.View()
|
|
}
|
|
return lipgloss.JoinVertical(
|
|
lipgloss.Left,
|
|
views...,
|
|
)
|
|
}
|
|
|
|
type timeEdit struct {
|
|
common *common.Common
|
|
fields []huh.Field
|
|
|
|
cursor int
|
|
}
|
|
|
|
func NewTimeEdit(common *common.Common, due *string, scheduled *string, wait *string, until *string) *timeEdit {
|
|
// defaultKeymap := huh.NewDefaultKeyMap()
|
|
t := timeEdit{
|
|
common: common,
|
|
fields: []huh.Field{
|
|
huh.NewInput().
|
|
Title("Due").
|
|
Value(due).
|
|
Validate(taskwarrior.ValidateDate).
|
|
Inline(true).
|
|
WithTheme(common.Styles.Form),
|
|
huh.NewInput().
|
|
Title("Scheduled").
|
|
Value(scheduled).
|
|
Validate(taskwarrior.ValidateDate).
|
|
Inline(true).
|
|
WithTheme(common.Styles.Form),
|
|
huh.NewInput().
|
|
Title("Wait").
|
|
Value(wait).
|
|
Validate(taskwarrior.ValidateDate).
|
|
Inline(true).
|
|
WithTheme(common.Styles.Form),
|
|
huh.NewInput().
|
|
Title("Until").
|
|
Value(until).
|
|
Validate(taskwarrior.ValidateDate).
|
|
Inline(true).
|
|
WithTheme(common.Styles.Form),
|
|
},
|
|
}
|
|
|
|
t.fields[0].Focus()
|
|
|
|
return &t
|
|
}
|
|
|
|
func (t timeEdit) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
func (t timeEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg.(type) {
|
|
case nextFieldMsg:
|
|
if t.cursor == len(t.fields)-1 {
|
|
t.fields[t.cursor].Blur()
|
|
return t, nextArea()
|
|
}
|
|
t.fields[t.cursor].Blur()
|
|
t.cursor++
|
|
t.fields[t.cursor].Focus()
|
|
case prevFieldMsg:
|
|
if t.cursor == 0 {
|
|
t.fields[t.cursor].Blur()
|
|
return t, prevArea()
|
|
}
|
|
t.fields[t.cursor].Blur()
|
|
t.cursor--
|
|
t.fields[t.cursor].Focus()
|
|
default:
|
|
field, cmd := t.fields[t.cursor].Update(msg)
|
|
t.fields[t.cursor] = field.(huh.Field)
|
|
return t, cmd
|
|
}
|
|
return t, nil
|
|
}
|
|
|
|
func (t timeEdit) View() string {
|
|
views := make([]string, len(t.fields))
|
|
for i, field := range t.fields {
|
|
views[i] = field.View()
|
|
}
|
|
return lipgloss.JoinVertical(
|
|
lipgloss.Left,
|
|
views...,
|
|
)
|
|
}
|
|
|
|
// func (p *TaskEditorPage) SetSize(width, height int) {
|
|
// p.common.SetSize(width, height)
|
|
// }
|
|
|
|
// func (p *TaskEditorPage) Init() tea.Cmd {
|
|
// // return p.form.Init()
|
|
// return nil
|
|
// }
|
|
|
|
// func (p *TaskEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
// var cmds []tea.Cmd
|
|
|
|
// switch msg := msg.(type) {
|
|
// case SwitchModeMsg:
|
|
// switch mode(msg) {
|
|
// case modeNormal:
|
|
// p.mode = modeNormal
|
|
// case modeInsert:
|
|
// p.mode = modeInsert
|
|
// }
|
|
// case changeAreaMsg:
|
|
// p.selectedArea = area(msg)
|
|
// p.columns = append([]tea.Model{p.areaList}, p.areas[p.selectedArea]...)
|
|
// case nextColumnMsg:
|
|
// p.columnCursor++
|
|
// if p.columnCursor > len(p.columns)-1 {
|
|
// p.columnCursor = 0
|
|
// }
|
|
// case prevColumnMsg:
|
|
// p.columnCursor--
|
|
// if p.columnCursor < 0 {
|
|
// p.columnCursor = len(p.columns) - 1
|
|
// }
|
|
// }
|
|
|
|
// switch p.mode {
|
|
// case modeNormal:
|
|
// switch msg := msg.(type) {
|
|
// case tea.KeyMsg:
|
|
// 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
|
|
// case key.Matches(msg, p.common.Keymap.Insert):
|
|
// return p, p.switchModeCmd(modeInsert)
|
|
// // case key.Matches(msg, p.common.Keymap.Ok):
|
|
// // p.form.State = huh.StateCompleted
|
|
// case key.Matches(msg, p.common.Keymap.Left):
|
|
// return p, prevColumn()
|
|
// case key.Matches(msg, p.common.Keymap.Right):
|
|
// return p, nextColumn()
|
|
// }
|
|
// }
|
|
// case modeInsert:
|
|
// switch msg := msg.(type) {
|
|
// case tea.KeyMsg:
|
|
// switch {
|
|
// case key.Matches(msg, p.common.Keymap.Back):
|
|
// return p, p.switchModeCmd(modeNormal)
|
|
// }
|
|
// }
|
|
|
|
// var cmd tea.Cmd
|
|
// if p.columnCursor == 0 {
|
|
// p.areaList, cmd = p.areaList.Update(msg)
|
|
// p.selectedArea = p.areaList.(areaList).Area()
|
|
// cmds = append(cmds, cmd)
|
|
// } else {
|
|
// p.areas[p.selectedArea][p.columnCursor-1], cmd = p.areas[p.selectedArea][p.columnCursor-1].Update(msg)
|
|
// cmds = append(cmds, cmd)
|
|
// }
|
|
|
|
// }
|
|
|
|
// var cmd tea.Cmd
|
|
// if p.columnCursor == 0 {
|
|
// p.areaList, cmd = p.areaList.Update(msg)
|
|
// p.selectedArea = p.areaList.(areaList).Area()
|
|
// cmds = append(cmds, cmd)
|
|
// } else {
|
|
// p.areas[p.selectedArea][p.columnCursor-1], cmd = p.areas[p.selectedArea][p.columnCursor-1].Update(msg)
|
|
// cmds = append(cmds, cmd)
|
|
// }
|
|
|
|
// p.statusline, cmd = p.statusline.Update(msg)
|
|
// cmds = append(cmds, cmd)
|
|
|
|
// // if p.form.State == huh.StateCompleted {
|
|
// // cmds = append(cmds, p.updateTasksCmd)
|
|
// // model, err := p.common.PopPage()
|
|
// // if err != nil {
|
|
// // slog.Error("page stack empty")
|
|
// // return nil, tea.Quit
|
|
// // }
|
|
// // return model, tea.Batch(cmds...)
|
|
// // }
|
|
|
|
// return p, tea.Batch(cmds...)
|
|
// }
|
|
|
|
// func (p *TaskEditorPage) View() string {
|
|
// columns := make([]string, len(p.columns))
|
|
// for i, c := range p.columns {
|
|
// columns[i] = c.View()
|
|
// }
|
|
|
|
// return lipgloss.JoinVertical(
|
|
// lipgloss.Left,
|
|
// lipgloss.JoinHorizontal(
|
|
// lipgloss.Top,
|
|
// // lipgloss.Place(p.common.Width(), p.common.Height()-1, 0.5, 0.5, p.form.View(), lipgloss.WithWhitespaceBackground(p.common.Styles.Warning.GetForeground())),
|
|
// // lipgloss.Place(p.common.Width(), p.common.Height()-1, 0.5, 0.5, p.form.View(), lipgloss.WithWhitespaceChars(" . ")),
|
|
// columns...,
|
|
// ),
|
|
// p.statusline.View(),
|
|
// )
|
|
// }
|
|
|
|
func (p *TaskEditorPage) updateTasksCmd() tea.Msg {
|
|
if p.task.Project == "(none)" {
|
|
p.task.Project = ""
|
|
}
|
|
if p.task.Priority == "(none)" {
|
|
p.task.Priority = ""
|
|
}
|
|
|
|
if *p.areas[areaTask].(taskEdit).newProjectName != "" {
|
|
p.task.Project = *p.areas[areaTask].(taskEdit).newProjectName
|
|
}
|
|
|
|
if *p.areas[areaTags].(tagEdit).newTagsValue != "" {
|
|
p.task.Tags = append(p.task.Tags, strings.Split(*p.areas[areaTags].(tagEdit).newTagsValue, " ")...)
|
|
}
|
|
|
|
// if p.additionalProject != "" {
|
|
// p.task.Project = p.additionalProject
|
|
// }
|
|
// tags := p.form.Get("tags").([]string)
|
|
// p.task.Tags = tags
|
|
p.common.TW.ImportTask(&p.task)
|
|
return UpdatedTasksMsg{}
|
|
}
|
|
|
|
// type StatusLine struct {
|
|
// common *common.Common
|
|
// mode mode
|
|
// input textinput.Model
|
|
// }
|
|
|
|
// func NewStatusLine(common *common.Common, mode mode) *StatusLine {
|
|
// input := textinput.New()
|
|
// input.Placeholder = ""
|
|
// input.Prompt = ""
|
|
// input.Blur()
|
|
|
|
// return &StatusLine{
|
|
// input: textinput.New(),
|
|
// common: common,
|
|
// mode: mode,
|
|
// }
|
|
// }
|
|
|
|
// func (s *StatusLine) Init() tea.Cmd {
|
|
// s.input.Blur()
|
|
// return nil
|
|
// }
|
|
|
|
// func (s *StatusLine) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
// var cmd tea.Cmd
|
|
|
|
// switch msg := msg.(type) {
|
|
// case SwitchModeMsg:
|
|
// s.mode = mode(msg)
|
|
// switch s.mode {
|
|
// case modeNormal:
|
|
// s.input.Blur()
|
|
// case modeInsert:
|
|
// s.input.Focus()
|
|
// }
|
|
// case tea.KeyMsg:
|
|
// switch {
|
|
// case key.Matches(msg, s.common.Keymap.Back):
|
|
// s.input.Blur()
|
|
// case key.Matches(msg, s.common.Keymap.Input):
|
|
// s.input.Focus()
|
|
// }
|
|
// }
|
|
|
|
// s.input, cmd = s.input.Update(msg)
|
|
// return s, cmd
|
|
// }
|
|
|
|
// func (s *StatusLine) View() string {
|
|
// var mode string
|
|
// switch s.mode {
|
|
// case modeNormal:
|
|
// mode = s.common.Styles.Base.Render("NORMAL")
|
|
// case modeInsert:
|
|
// mode = s.common.Styles.Active.Inline(true).Reverse(true).Render("INSERT")
|
|
// }
|
|
// return lipgloss.JoinHorizontal(lipgloss.Left, mode, s.input.View())
|
|
// }
|
|
|
|
// // TODO: move this to taskwarrior; add missing date formats
|
|
|
|
// type itemDelegate struct{}
|
|
|
|
// func (d itemDelegate) Height() int { return 1 }
|
|
// func (d itemDelegate) Spacing() int { return 0 }
|
|
// func (d itemDelegate) Update(_ tea.Msg, _ *list.Model) tea.Cmd { return nil }
|
|
// func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
|
|
// i, ok := listItem.(item)
|
|
// if !ok {
|
|
// return
|
|
// }
|
|
|
|
// str := fmt.Sprintf("%s", i)
|
|
|
|
// fn := itemStyle.Render
|
|
// if index == m.Index() {
|
|
// fn = func(s ...string) string {
|
|
// return selectedItemStyle.Render("> " + strings.Join(s, " "))
|
|
// }
|
|
// }
|
|
|
|
// fmt.Fprint(w, fn(str))
|
|
// }
|
|
|
|
// var (
|
|
// titleStyle = lipgloss.NewStyle().MarginLeft(2)
|
|
// itemStyle = lipgloss.NewStyle().PaddingLeft(4)
|
|
// selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170"))
|
|
// paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
|
|
// helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
|
|
// quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
|
|
// )
|
|
|
|
// type item string
|
|
|
|
// func (i item) FilterValue() string { return "" }
|