Add time editing

This commit is contained in:
Martin
2026-02-01 21:46:11 +01:00
parent 72a5c57faa
commit 5cbfc58aa3
3 changed files with 194 additions and 0 deletions

168
pages/timeEditor.go Normal file
View File

@ -0,0 +1,168 @@
package pages
import (
"log/slog"
"strings"
"tasksquire/common"
"tasksquire/timewarrior"
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/huh"
)
type TimeEditorPage struct {
common *common.Common
interval *timewarrior.Interval
form *huh.Form
startStr string
endStr string
tagsStr string
}
func NewTimeEditorPage(com *common.Common, interval *timewarrior.Interval) *TimeEditorPage {
p := &TimeEditorPage{
common: com,
interval: interval,
startStr: interval.Start,
endStr: interval.End,
tagsStr: formatTags(interval.Tags),
}
p.form = huh.NewForm(
huh.NewGroup(
huh.NewInput().
Title("Start").
Value(&p.startStr).
Validate(func(s string) error {
return timewarrior.ValidateDate(s)
}),
huh.NewInput().
Title("End").
Value(&p.endStr).
Validate(func(s string) error {
if s == "" {
return nil // End can be empty (active)
}
return timewarrior.ValidateDate(s)
}),
huh.NewInput().
Title("Tags").
Value(&p.tagsStr).
Description("Space separated, use \"\" for tags with spaces"),
),
).WithTheme(com.Styles.Form)
return p
}
func (p *TimeEditorPage) Init() tea.Cmd {
return p.form.Init()
}
func (p *TimeEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
if 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 tea.WindowSizeMsg:
p.SetSize(msg.Width, msg.Height)
}
form, cmd := p.form.Update(msg)
if f, ok := form.(*huh.Form); ok {
p.form = f
}
cmds = append(cmds, cmd)
if p.form.State == huh.StateCompleted {
p.saveInterval()
model, err := p.common.PopPage()
if err != nil {
slog.Error("page stack empty")
return nil, tea.Quit
}
// Return with a command to refresh the intervals
return model, tea.Batch(tea.Batch(cmds...), refreshIntervals)
}
return p, tea.Batch(cmds...)
}
func (p *TimeEditorPage) View() string {
return p.form.View()
}
func (p *TimeEditorPage) SetSize(width, height int) {
p.common.SetSize(width, height)
}
func (p *TimeEditorPage) saveInterval() {
// If it's an existing interval (has ID), delete it first so we can replace it with the modified version
if p.interval.ID != 0 {
err := p.common.TimeW.DeleteInterval(p.interval.ID)
if err != nil {
slog.Error("Failed to delete old interval during edit", "err", err)
// Proceeding to import anyway, attempting to save user data
}
}
p.interval.Start = p.startStr
p.interval.End = p.endStr
// Parse tags
p.interval.Tags = parseTags(p.tagsStr)
err := p.common.TimeW.ModifyInterval(p.interval)
if err != nil {
slog.Error("Failed to modify interval", "err", err)
}
}
func parseTags(tagsStr string) []string {
var tags []string
var current strings.Builder
inQuotes := false
for _, r := range tagsStr {
switch {
case r == '"':
inQuotes = !inQuotes
case r == ' ' && !inQuotes:
if current.Len() > 0 {
tags = append(tags, current.String())
current.Reset()
}
default:
current.WriteRune(r)
}
}
if current.Len() > 0 {
tags = append(tags, current.String())
}
return tags
}
func formatTags(tags []string) string {
var formatted []string
for _, t := range tags {
if strings.Contains(t, " ") {
formatted = append(formatted, "\""+t+"\"")
} else {
formatted = append(formatted, t)
}
}
return strings.Join(formatted, " ")
}