Add timestamp editor

This commit is contained in:
Martin Pander
2026-02-02 10:55:47 +01:00
parent 7032d0fa54
commit fc8e9481c3
19 changed files with 922 additions and 113 deletions

View File

@ -8,6 +8,7 @@ import (
"time"
"tasksquire/components/input"
"tasksquire/components/timestampeditor"
"tasksquire/taskwarrior"
"github.com/charmbracelet/bubbles/key"
@ -676,45 +677,56 @@ func (t tagEdit) View() string {
type timeEdit struct {
common *common.Common
fields []huh.Field
fields []*timestampeditor.TimestampEditor
cursor int
// Store task field pointers to update them
due *string
scheduled *string
wait *string
until *string
}
func NewTimeEdit(common *common.Common, due *string, scheduled *string, wait *string, until *string) *timeEdit {
// defaultKeymap := huh.NewDefaultKeyMap()
// Create timestamp editors for each date field
dueEditor := timestampeditor.New(common).
Title("Due").
Description("When the task is due").
ValueFromString(*due)
scheduledEditor := timestampeditor.New(common).
Title("Scheduled").
Description("When to start working on the task").
ValueFromString(*scheduled)
waitEditor := timestampeditor.New(common).
Title("Wait").
Description("Hide task until this date").
ValueFromString(*wait)
untilEditor := timestampeditor.New(common).
Title("Until").
Description("Task expires after this date").
ValueFromString(*until)
t := timeEdit{
common: common,
fields: []huh.Field{
huh.NewInput().
Title("Due").
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),
fields: []*timestampeditor.TimestampEditor{
dueEditor,
scheduledEditor,
waitEditor,
untilEditor,
},
due: due,
scheduled: scheduled,
wait: wait,
until: until,
}
// Focus the first field
if len(t.fields) > 0 {
t.fields[0].Focus()
}
return &t
@ -725,12 +737,21 @@ func (t *timeEdit) GetName() string {
}
func (t *timeEdit) SetCursor(c int) {
if len(t.fields) == 0 {
return
}
// Blur the current field
t.fields[t.cursor].Blur()
// Set new cursor position
if c < 0 {
t.cursor = len(t.fields) - 1
} else {
t.cursor = c
}
// Focus the new field
t.fields[t.cursor].Focus()
}
@ -739,42 +760,71 @@ func (t *timeEdit) Init() tea.Cmd {
}
func (t *timeEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.(type) {
switch msg := msg.(type) {
case nextFieldMsg:
if t.cursor == len(t.fields)-1 {
// Update task field before moving to next area
t.syncToTaskFields()
t.fields[t.cursor].Blur()
return t, nextArea()
}
t.fields[t.cursor].Blur()
t.cursor++
t.fields[t.cursor].Focus()
return t, nil
case prevFieldMsg:
if t.cursor == 0 {
// Update task field before moving to previous area
t.syncToTaskFields()
t.fields[t.cursor].Blur()
return t, prevArea()
}
t.fields[t.cursor].Blur()
t.cursor--
t.fields[t.cursor].Focus()
return t, nil
default:
field, cmd := t.fields[t.cursor].Update(msg)
t.fields[t.cursor] = field.(huh.Field)
// Update the current timestamp editor
model, cmd := t.fields[t.cursor].Update(msg)
t.fields[t.cursor] = model.(*timestampeditor.TimestampEditor)
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()
if i < len(t.fields)-1 {
views[i] += "\n"
}
}
return lipgloss.JoinVertical(
lipgloss.Left,
views...,
)
}
// syncToTaskFields converts the timestamp editor values back to task field strings
func (t *timeEdit) syncToTaskFields() {
// Update the task fields with values from the timestamp editors
// GetValueString() returns empty string for unset timestamps
if len(t.fields) > 0 {
*t.due = t.fields[0].GetValueString()
}
if len(t.fields) > 1 {
*t.scheduled = t.fields[1].GetValueString()
}
if len(t.fields) > 2 {
*t.wait = t.fields[2].GetValueString()
}
if len(t.fields) > 3 {
*t.until = t.fields[3].GetValueString()
}
}
type detailsEdit struct {
com *common.Common
vp viewport.Model
@ -1009,6 +1059,9 @@ func (p *TaskEditorPage) updateTasksCmd() tea.Msg {
}
}
// Sync timestamp fields from the timeEdit area (area 2)
p.areas[2].(*timeEdit).syncToTaskFields()
if *(p.areas[0].(*taskEdit).newAnnotation) != "" {
p.task.Annotations = append(p.task.Annotations, taskwarrior.Annotation{
Entry: time.Now().Format("20060102T150405Z"),