Handle UDAs for editing; Fix layout; Add annotations
This commit is contained in:
@ -5,12 +5,15 @@ import (
|
||||
"log/slog"
|
||||
"strings"
|
||||
"tasksquire/common"
|
||||
"time"
|
||||
|
||||
"tasksquire/taskwarrior"
|
||||
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
"github.com/charmbracelet/bubbles/viewport"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/glamour"
|
||||
"github.com/charmbracelet/huh"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
@ -26,13 +29,16 @@ type TaskEditorPage struct {
|
||||
common *common.Common
|
||||
task taskwarrior.Task
|
||||
|
||||
colWidth int
|
||||
colHeight int
|
||||
|
||||
mode mode
|
||||
|
||||
columnCursor int
|
||||
|
||||
area area
|
||||
area int
|
||||
areaPicker *areaPicker
|
||||
areas map[area]tea.Model
|
||||
areas []area
|
||||
}
|
||||
|
||||
func NewTaskEditorPage(com *common.Common, task taskwarrior.Task) *TaskEditorPage {
|
||||
@ -41,21 +47,17 @@ func NewTaskEditorPage(com *common.Common, task taskwarrior.Task) *TaskEditorPag
|
||||
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()
|
||||
|
||||
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.areas = []area{
|
||||
NewTaskEdit(p.common, &p.task),
|
||||
NewTagEdit(p.common, &p.task.Tags, tagOptions),
|
||||
NewTimeEdit(p.common, &p.task.Due, &p.task.Scheduled, &p.task.Wait, &p.task.Until),
|
||||
NewDetailsEdit(p.common, &p.task),
|
||||
}
|
||||
|
||||
// p.areaList = NewAreaList(common, areaItems)
|
||||
@ -66,17 +68,30 @@ func NewTaskEditorPage(com *common.Common, task taskwarrior.Task) *TaskEditorPag
|
||||
|
||||
p.columnCursor = 1
|
||||
if p.task.Uuid == "" {
|
||||
// p.mode = modeInsert
|
||||
p.mode = modeInsert
|
||||
} else {
|
||||
p.mode = modeNormal
|
||||
}
|
||||
|
||||
p.SetSize(com.Width(), com.Height())
|
||||
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *TaskEditorPage) SetSize(width, height int) {
|
||||
p.common.SetSize(width, height)
|
||||
|
||||
if width >= 70 {
|
||||
p.colWidth = 70 - p.common.Styles.ColumnFocused.GetVerticalFrameSize()
|
||||
} else {
|
||||
p.colWidth = width - p.common.Styles.ColumnFocused.GetVerticalFrameSize()
|
||||
}
|
||||
|
||||
if height >= 40 {
|
||||
p.colHeight = 40 - p.common.Styles.ColumnFocused.GetVerticalFrameSize()
|
||||
} else {
|
||||
p.colHeight = height - p.common.Styles.ColumnFocused.GetVerticalFrameSize()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *TaskEditorPage) Init() tea.Cmd {
|
||||
@ -85,8 +100,10 @@ func (p *TaskEditorPage) Init() tea.Cmd {
|
||||
|
||||
func (p *TaskEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
p.SetSize(msg.Width, msg.Height)
|
||||
case changeAreaMsg:
|
||||
p.area = area(msg)
|
||||
p.area = int(msg)
|
||||
case changeModeMsg:
|
||||
p.mode = mode(msg)
|
||||
case prevColumnMsg:
|
||||
@ -102,13 +119,15 @@ func (p *TaskEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case prevAreaMsg:
|
||||
p.area--
|
||||
if p.area < 0 {
|
||||
p.area = 2
|
||||
p.area = len(p.areas) - 1
|
||||
}
|
||||
p.areas[p.area].SetCursor(-1)
|
||||
case nextAreaMsg:
|
||||
p.area++
|
||||
if p.area > 2 {
|
||||
if p.area > len(p.areas)-1 {
|
||||
p.area = 0
|
||||
}
|
||||
p.areas[p.area].SetCursor(0)
|
||||
}
|
||||
|
||||
switch p.mode {
|
||||
@ -137,23 +156,23 @@ func (p *TaskEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
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{})
|
||||
model, cmd := p.areas[p.area].Update(prevFieldMsg{})
|
||||
p.areas[p.area] = model.(area)
|
||||
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{})
|
||||
model, cmd := p.areas[p.area].Update(nextFieldMsg{})
|
||||
p.areas[p.area] = model.(area)
|
||||
return p, cmd
|
||||
}
|
||||
}
|
||||
@ -175,39 +194,39 @@ func (p *TaskEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case key.Matches(msg, p.common.Keymap.Back):
|
||||
return p, changeMode(modeNormal)
|
||||
case key.Matches(msg, p.common.Keymap.Prev):
|
||||
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{})
|
||||
model, cmd := p.areas[p.area].Update(prevFieldMsg{})
|
||||
p.areas[p.area] = model.(area)
|
||||
return p, cmd
|
||||
}
|
||||
case key.Matches(msg, p.common.Keymap.Next):
|
||||
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{})
|
||||
model, cmd := p.areas[p.area].Update(nextFieldMsg{})
|
||||
p.areas[p.area] = model.(area)
|
||||
return p, cmd
|
||||
}
|
||||
case key.Matches(msg, p.common.Keymap.Ok):
|
||||
area, cmd := p.areas[p.area].Update(msg)
|
||||
p.areas[p.area] = area
|
||||
model, cmd := p.areas[p.area].Update(msg)
|
||||
p.areas[p.area] = model.(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)
|
||||
model, cmd := p.areas[p.area].Update(msg)
|
||||
p.areas[p.area] = model.(area)
|
||||
return p, cmd
|
||||
}
|
||||
}
|
||||
@ -215,143 +234,45 @@ func (p *TaskEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
func (p *TaskEditorPage) View() string {
|
||||
var focusStyle lipgloss.Style
|
||||
var focusedStyle, blurredStyle lipgloss.Style
|
||||
if p.mode == modeInsert {
|
||||
focusStyle = p.common.Styles.ColumnInsert
|
||||
focusedStyle = p.common.Styles.ColumnInsert.Width(p.colWidth).Height(p.colHeight)
|
||||
} else {
|
||||
focusStyle = p.common.Styles.ColumnFocused
|
||||
focusedStyle = p.common.Styles.ColumnFocused.Width(p.colWidth).Height(p.colHeight)
|
||||
}
|
||||
var picker, area string
|
||||
blurredStyle = p.common.Styles.ColumnBlurred.Width(p.colWidth).Height(p.colHeight)
|
||||
// var picker, area string
|
||||
var area string
|
||||
if p.columnCursor == 0 {
|
||||
picker = focusStyle.Render(p.areaPicker.View())
|
||||
area = p.common.Styles.ColumnBlurred.Render(p.areas[p.area].View())
|
||||
// picker = focusedStyle.Render(p.areaPicker.View())
|
||||
area = blurredStyle.Render(p.areas[p.area].View())
|
||||
} else {
|
||||
picker = p.common.Styles.ColumnBlurred.Render(p.areaPicker.View())
|
||||
area = focusStyle.Render(p.areas[p.area].View())
|
||||
// picker = blurredStyle.Render(p.areaPicker.View())
|
||||
area = focusedStyle.Render(p.areas[p.area].View())
|
||||
|
||||
}
|
||||
|
||||
return lipgloss.JoinHorizontal(
|
||||
lipgloss.Center,
|
||||
picker,
|
||||
area,
|
||||
)
|
||||
if p.task.Uuid != "" {
|
||||
area = lipgloss.JoinHorizontal(
|
||||
lipgloss.Top,
|
||||
area,
|
||||
p.common.Styles.ColumnFocused.Render(p.common.TW.GetInformation(&p.task)),
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// return lipgloss.Place(p.common.Width(), p.common.Height(), lipgloss.Center, lipgloss.Center, lipgloss.JoinHorizontal(
|
||||
// lipgloss.Center,
|
||||
// picker,
|
||||
// area,
|
||||
// ))
|
||||
return lipgloss.Place(p.common.Width(), p.common.Height(), lipgloss.Center, lipgloss.Center, 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 area interface {
|
||||
tea.Model
|
||||
SetCursor(c int)
|
||||
}
|
||||
|
||||
type areaPicker struct {
|
||||
common *common.Common
|
||||
@ -383,17 +304,18 @@ func NewAreaPicker(common *common.Common, items []string) *areaPicker {
|
||||
}
|
||||
}
|
||||
|
||||
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) Area() int {
|
||||
// switch a.list.SelectedItem() {
|
||||
// case item("Task"):
|
||||
// return areaTask
|
||||
// case item("Tags"):
|
||||
// return areaTags
|
||||
// case item("Dates"):
|
||||
// return areaTime
|
||||
// default:
|
||||
// return areaTask
|
||||
// }
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a *areaPicker) Init() tea.Cmd {
|
||||
@ -429,50 +351,138 @@ type taskEdit struct {
|
||||
cursor int
|
||||
|
||||
newProjectName *string
|
||||
newAnnotation *string
|
||||
udaValues map[string]*string
|
||||
}
|
||||
|
||||
func NewTaskEdit(common *common.Common, description *string, priority *string, project *string, priorityOptions []string, projectOptions []string) *taskEdit {
|
||||
func NewTaskEdit(com *common.Common, task *taskwarrior.Task) *taskEdit {
|
||||
newProject := ""
|
||||
projectOptions := append([]string{"(none)"}, com.TW.GetProjects()...)
|
||||
if task.Project == "" {
|
||||
task.Project = "(none)"
|
||||
}
|
||||
|
||||
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
|
||||
}).
|
||||
fields := []huh.Field{
|
||||
huh.NewInput().
|
||||
Title("Task").
|
||||
Value(&task.Description).
|
||||
Validate(func(desc string) error {
|
||||
if desc == "" {
|
||||
return fmt.Errorf("task description is required")
|
||||
}
|
||||
return nil
|
||||
}).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(com.Styles.Form),
|
||||
|
||||
huh.NewSelect[string]().
|
||||
Options(huh.NewOptions(projectOptions...)...).
|
||||
Title("Project").
|
||||
Value(&task.Project).
|
||||
WithKeyMap(defaultKeymap).
|
||||
WithTheme(com.Styles.Form),
|
||||
|
||||
huh.NewInput().
|
||||
Title("New Project").
|
||||
Value(&newProject).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(com.Styles.Form),
|
||||
}
|
||||
|
||||
udaValues := make(map[string]*string)
|
||||
for _, uda := range com.Udas {
|
||||
switch uda.Type {
|
||||
case taskwarrior.UdaTypeNumeric:
|
||||
val := ""
|
||||
udaValues[uda.Name] = &val
|
||||
fields = append(fields, huh.NewInput().
|
||||
Title(uda.Label).
|
||||
Value(udaValues[uda.Name]).
|
||||
Validate(taskwarrior.ValidateNumeric).
|
||||
Inline(true).
|
||||
WithTheme(common.Styles.Form),
|
||||
Prompt(": ").
|
||||
WithTheme(com.Styles.Form))
|
||||
case taskwarrior.UdaTypeString:
|
||||
if len(uda.Values) > 0 {
|
||||
var val string
|
||||
values := make([]string, len(uda.Values))
|
||||
for i, v := range uda.Values {
|
||||
values[i] = v
|
||||
if v == "" {
|
||||
values[i] = "(none)"
|
||||
}
|
||||
if v == uda.Default {
|
||||
val = values[i]
|
||||
}
|
||||
}
|
||||
if val == "" {
|
||||
val = values[0]
|
||||
}
|
||||
if v, ok := task.Udas[uda.Name]; ok {
|
||||
//TODO: handle uda types correctly
|
||||
val = v.(string)
|
||||
}
|
||||
udaValues[uda.Name] = &val
|
||||
|
||||
huh.NewSelect[string]().
|
||||
Options(huh.NewOptions(priorityOptions...)...).
|
||||
Title("Priority").
|
||||
Key("priority").
|
||||
Value(priority).
|
||||
WithKeyMap(defaultKeymap).
|
||||
WithTheme(common.Styles.Form),
|
||||
fields = append(fields, huh.NewSelect[string]().
|
||||
Options(huh.NewOptions(values...)...).
|
||||
Title(uda.Label).
|
||||
Value(udaValues[uda.Name]).
|
||||
WithKeyMap(defaultKeymap).
|
||||
WithTheme(com.Styles.Form))
|
||||
} else {
|
||||
val := ""
|
||||
udaValues[uda.Name] = &val
|
||||
fields = append(fields, huh.NewInput().
|
||||
Title(uda.Label).
|
||||
Value(udaValues[uda.Name]).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(com.Styles.Form))
|
||||
}
|
||||
case taskwarrior.UdaTypeDate:
|
||||
val := ""
|
||||
udaValues[uda.Name] = &val
|
||||
fields = append(fields, huh.NewInput().
|
||||
Title(uda.Label).
|
||||
Value(udaValues[uda.Name]).
|
||||
Validate(taskwarrior.ValidateDate).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(com.Styles.Form))
|
||||
case taskwarrior.UdaTypeDuration:
|
||||
val := ""
|
||||
udaValues[uda.Name] = &val
|
||||
fields = append(fields, huh.NewInput().
|
||||
Title(uda.Label).
|
||||
Value(udaValues[uda.Name]).
|
||||
Validate(taskwarrior.ValidateDuration).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(com.Styles.Form))
|
||||
}
|
||||
}
|
||||
|
||||
huh.NewSelect[string]().
|
||||
Options(huh.NewOptions(projectOptions...)...).
|
||||
Title("Project").
|
||||
Value(project).
|
||||
WithKeyMap(defaultKeymap).
|
||||
WithTheme(common.Styles.Form),
|
||||
newAnnotation := ""
|
||||
fields = append(fields, huh.NewInput().
|
||||
Title("New Annotation").
|
||||
Value(&newAnnotation).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(com.Styles.Form))
|
||||
|
||||
huh.NewInput().
|
||||
Title("New Project").
|
||||
Value(&newProject).
|
||||
WithTheme(common.Styles.Form),
|
||||
},
|
||||
t := taskEdit{
|
||||
common: com,
|
||||
fields: fields,
|
||||
|
||||
udaValues: udaValues,
|
||||
|
||||
newProjectName: &newProject,
|
||||
newAnnotation: &newAnnotation,
|
||||
}
|
||||
|
||||
t.fields[0].Focus()
|
||||
@ -480,6 +490,16 @@ func NewTaskEdit(common *common.Common, description *string, priority *string, p
|
||||
return &t
|
||||
}
|
||||
|
||||
func (t *taskEdit) SetCursor(c int) {
|
||||
t.fields[t.cursor].Blur()
|
||||
if c < 0 {
|
||||
t.cursor = len(t.fields) - 1
|
||||
} else {
|
||||
t.cursor = c
|
||||
}
|
||||
t.fields[t.cursor].Focus()
|
||||
}
|
||||
|
||||
func (t *taskEdit) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
@ -515,6 +535,9 @@ func (t *taskEdit) View() string {
|
||||
views := make([]string, len(t.fields))
|
||||
for i, field := range t.fields {
|
||||
views[i] = field.View()
|
||||
if i < len(t.fields)-1 {
|
||||
views[i] += "\n"
|
||||
}
|
||||
}
|
||||
return lipgloss.JoinVertical(
|
||||
lipgloss.Left,
|
||||
@ -551,16 +574,25 @@ func NewTagEdit(common *common.Common, selected *[]string, options []string) *ta
|
||||
Title("New Tags").
|
||||
Value(&newTags).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(common.Styles.Form),
|
||||
},
|
||||
newTagsValue: &newTags,
|
||||
}
|
||||
|
||||
t.fields[0].Focus()
|
||||
|
||||
return &t
|
||||
}
|
||||
|
||||
func (t *tagEdit) SetCursor(c int) {
|
||||
t.fields[t.cursor].Blur()
|
||||
if c < 0 {
|
||||
t.cursor = len(t.fields) - 1
|
||||
} else {
|
||||
t.cursor = c
|
||||
}
|
||||
t.fields[t.cursor].Focus()
|
||||
}
|
||||
|
||||
func (t *tagEdit) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
@ -619,33 +651,45 @@ func NewTimeEdit(common *common.Common, due *string, scheduled *string, wait *st
|
||||
Value(due).
|
||||
Validate(taskwarrior.ValidateDate).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(common.Styles.Form),
|
||||
huh.NewInput().
|
||||
Title("Scheduled").
|
||||
Value(scheduled).
|
||||
Validate(taskwarrior.ValidateDate).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(common.Styles.Form),
|
||||
huh.NewInput().
|
||||
Title("Wait").
|
||||
Value(wait).
|
||||
Validate(taskwarrior.ValidateDate).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(common.Styles.Form),
|
||||
huh.NewInput().
|
||||
Title("Until").
|
||||
Value(until).
|
||||
Validate(taskwarrior.ValidateDate).
|
||||
Inline(true).
|
||||
Prompt(": ").
|
||||
WithTheme(common.Styles.Form),
|
||||
},
|
||||
}
|
||||
|
||||
t.fields[0].Focus()
|
||||
|
||||
return &t
|
||||
}
|
||||
|
||||
func (t *timeEdit) SetCursor(c int) {
|
||||
t.fields[t.cursor].Blur()
|
||||
if c < 0 {
|
||||
t.cursor = len(t.fields) - 1
|
||||
} else {
|
||||
t.cursor = c
|
||||
}
|
||||
t.fields[t.cursor].Focus()
|
||||
}
|
||||
|
||||
func (t *timeEdit) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
@ -687,6 +731,75 @@ func (t *timeEdit) View() string {
|
||||
)
|
||||
}
|
||||
|
||||
type detailsEdit struct {
|
||||
com *common.Common
|
||||
renderer *glamour.TermRenderer
|
||||
vp viewport.Model
|
||||
}
|
||||
|
||||
func NewDetailsEdit(com *common.Common, task *taskwarrior.Task) *detailsEdit {
|
||||
renderer, err := glamour.NewTermRenderer(
|
||||
// glamour.WithStandardStyle("light"),
|
||||
glamour.WithAutoStyle(),
|
||||
glamour.WithWordWrap(40),
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
vp := viewport.New(40, 30)
|
||||
d := detailsEdit{
|
||||
com: com,
|
||||
renderer: renderer,
|
||||
vp: vp,
|
||||
}
|
||||
|
||||
return &d
|
||||
}
|
||||
|
||||
func (d *detailsEdit) SetCursor(c int) {
|
||||
}
|
||||
|
||||
func (d *detailsEdit) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *detailsEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg.(type) {
|
||||
case nextFieldMsg:
|
||||
return d, nextArea()
|
||||
case prevFieldMsg:
|
||||
return d, prevArea()
|
||||
default:
|
||||
var cmd tea.Cmd
|
||||
d.vp, cmd = d.vp.Update(msg)
|
||||
return d, cmd
|
||||
}
|
||||
}
|
||||
|
||||
func (d *detailsEdit) View() string {
|
||||
dtls := `
|
||||
# Cool Details!
|
||||
## Things I need
|
||||
- [ ] A thing
|
||||
- [x] Done thing
|
||||
|
||||
## People
|
||||
- pe1
|
||||
- pe2
|
||||
`
|
||||
|
||||
details, err := d.renderer.Render(dtls)
|
||||
if err != nil {
|
||||
slog.Error(err.Error())
|
||||
return "Could not parse markdown"
|
||||
}
|
||||
|
||||
d.vp.SetContent(details)
|
||||
return d.vp.View()
|
||||
}
|
||||
|
||||
// func (p *TaskEditorPage) SetSize(width, height int) {
|
||||
// p.common.SetSize(width, height)
|
||||
// }
|
||||
@ -813,26 +926,36 @@ func (p *TaskEditorPage) updateTasksCmd() tea.Msg {
|
||||
if p.task.Project == "(none)" {
|
||||
p.task.Project = ""
|
||||
}
|
||||
if p.task.Priority == "(none)" {
|
||||
p.task.Priority = ""
|
||||
|
||||
for _, uda := range p.common.Udas {
|
||||
if val, ok := p.areas[0].(*taskEdit).udaValues[uda.Name]; ok {
|
||||
if *val == "(none)" {
|
||||
*val = ""
|
||||
}
|
||||
p.task.Udas[uda.Name] = *val
|
||||
}
|
||||
}
|
||||
|
||||
if *(p.areas[areaTask].(*taskEdit).newProjectName) != "" {
|
||||
p.task.Project = *p.areas[areaTask].(*taskEdit).newProjectName
|
||||
if *(p.areas[0].(*taskEdit).newProjectName) != "" {
|
||||
p.task.Project = *p.areas[0].(*taskEdit).newProjectName
|
||||
}
|
||||
|
||||
if *(p.areas[areaTags].(*tagEdit).newTagsValue) != "" {
|
||||
newTags := strings.Split(*p.areas[areaTags].(*tagEdit).newTagsValue, " ")
|
||||
if *(p.areas[1].(*tagEdit).newTagsValue) != "" {
|
||||
newTags := strings.Split(*p.areas[1].(*tagEdit).newTagsValue, " ")
|
||||
if len(newTags) > 0 {
|
||||
p.task.Tags = append(p.task.Tags, newTags...)
|
||||
}
|
||||
}
|
||||
|
||||
// if p.additionalProject != "" {
|
||||
// p.task.Project = p.additionalProject
|
||||
// }
|
||||
// tags := p.form.Get("tags").([]string)
|
||||
// p.task.Tags = tags
|
||||
if *(p.areas[0].(*taskEdit).newAnnotation) != "" {
|
||||
p.task.Annotations = append(p.task.Annotations, taskwarrior.Annotation{
|
||||
Entry: time.Now().Format("20060102T150405Z"),
|
||||
Description: *(p.areas[0].(*taskEdit).newAnnotation),
|
||||
})
|
||||
|
||||
// p.common.TW.AddTaskAnnotation(p.task.Uuid, *p.areas[0].(*taskEdit).newAnnotation)
|
||||
}
|
||||
|
||||
p.common.TW.ImportTask(&p.task)
|
||||
return UpdatedTasksMsg{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user