From f3b64f706e2df8ceffafdef916a127e8e22c296b Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 23 Jun 2026 06:53:20 +0300 Subject: Refactor status auto-clear helper for xq0 --- internal/ui/editor_handlers.go | 19 +++---------------- internal/ui/handlers.go | 31 +++++-------------------------- internal/ui/helpers.go | 16 ++++++++++++++++ internal/ui/helpers_test.go | 14 ++++++++++++++ internal/ui/table.go | 2 +- 5 files changed, 39 insertions(+), 43 deletions(-) diff --git a/internal/ui/editor_handlers.go b/internal/ui/editor_handlers.go index 857e3c7..e85acf4 100644 --- a/internal/ui/editor_handlers.go +++ b/internal/ui/editor_handlers.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "strings" - "time" tea "charm.land/bubbletea/v2" ) @@ -34,21 +33,13 @@ func (m *Model) handleDescEditDone(msg descEditDoneMsg) (tea.Model, tea.Cmd) { } if msg.err != nil { - m.statusMsg = fmt.Sprintf("Edit error: %v", msg.err) - cmd := tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return struct{ clearStatus bool }{true} - }) - return m, cmd + return m, m.showStatusTimed(fmt.Sprintf("Edit error: %v", msg.err)) } // Read the edited content content, err := os.ReadFile(msg.tempFile) if err != nil { - m.statusMsg = fmt.Sprintf("Error reading file: %v", err) - cmd := tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return struct{ clearStatus bool }{true} - }) - return m, cmd + return m, m.showStatusTimed(fmt.Sprintf("Error reading file: %v", err)) } // Update the description @@ -58,11 +49,7 @@ func (m *Model) handleDescEditDone(msg descEditDoneMsg) (tea.Model, tea.Cmd) { err = m.taskwarriorClient().SetDescriptionContext(ctx, m.currentTaskDetail.ID, newDesc) cancel() if err != nil { - m.statusMsg = fmt.Sprintf("Error updating description: %v", err) - cmd := tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return struct{ clearStatus bool }{true} - }) - return m, cmd + return m, m.showStatusTimed(fmt.Sprintf("Error updating description: %v", err)) } // Reload and start blinking diff --git a/internal/ui/handlers.go b/internal/ui/handlers.go index cc11f89..cd6b9de 100644 --- a/internal/ui/handlers.go +++ b/internal/ui/handlers.go @@ -3,7 +3,6 @@ package ui import ( "fmt" "strings" - "time" "charm.land/bubbles/v2/textinput" tea "charm.land/bubbletea/v2" @@ -15,11 +14,7 @@ func (m *Model) handleTextInput(msg tea.KeyPressMsg, input *textinput.Model, onE case "enter": value := input.Value() if err := onEnter(value); err != nil { - m.statusMsg = fmt.Sprintf("Error: %v", err) - cmd := tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return struct{ clearStatus bool }{true} - }) - return m, cmd + return m, m.showErrorTimed(err) } input.Blur() onExit() @@ -172,11 +167,7 @@ func (m *Model) handleDueEditMode(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { err := m.taskwarriorClient().SetDueDateContext(ctx, m.dueID, m.dueDate.Format("2006-01-02")) cancel() if err != nil { - m.statusMsg = fmt.Sprintf("Error: %v", err) - cmd := tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return struct{ clearStatus bool }{true} - }) - return m, cmd + return m, m.showErrorTimed(err) } m.dueEditing = false if !m.reloadAndReport() { @@ -273,21 +264,13 @@ func (m *Model) handlePriorityMode(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { case "enter": priority := priorityOptions[m.priorityIndex] if err := validatePriority(priority); err != nil { - m.statusMsg = fmt.Sprintf("Error: %v", err) - cmd := tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return struct{ clearStatus bool }{true} - }) - return m, cmd + return m, m.showErrorTimed(err) } ctx, cancel := m.taskOperationContext() err := m.taskwarriorClient().SetPriorityContext(ctx, m.priorityID, priority) cancel() if err != nil { - m.statusMsg = fmt.Sprintf("Error: %v", err) - cmd := tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return struct{ clearStatus bool }{true} - }) - return m, cmd + return m, m.showErrorTimed(err) } m.prioritySelecting = false if !m.reloadAndReport() { @@ -362,11 +345,7 @@ func (m *Model) handleAddTaskMode(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { err := m.taskwarriorClient().AddLineContext(ctx, m.addInput.Value()) cancel() if err != nil { - m.statusMsg = fmt.Sprintf("Error: %v", err) - cmd := tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return struct{ clearStatus bool }{true} - }) - return m, cmd + return m, m.showErrorTimed(err) } m.addingTask = false diff --git a/internal/ui/helpers.go b/internal/ui/helpers.go index bebc937..5d753ab 100644 --- a/internal/ui/helpers.go +++ b/internal/ui/helpers.go @@ -6,6 +6,7 @@ import ( "strings" "time" + tea "charm.land/bubbletea/v2" "github.com/google/shlex" "codeberg.org/snonux/tasksamurai/internal/task" @@ -16,6 +17,21 @@ import ( // to qualify every parse/format call with the package name. const taskDateFormat = task.DateFormat +const statusClearDelay = 2 * time.Second + +type clearStatusMsg struct{} + +func (m *Model) showStatusTimed(message string) tea.Cmd { + m.statusMsg = message + return tea.Tick(statusClearDelay, func(time.Time) tea.Msg { + return clearStatusMsg{} + }) +} + +func (m *Model) showErrorTimed(err error) tea.Cmd { + return m.showStatusTimed(fmt.Sprintf("Error: %v", err)) +} + // parseTaskDate parses a date string in Taskwarrior format func parseTaskDate(dateStr string) (time.Time, error) { if dateStr == "" { diff --git a/internal/ui/helpers_test.go b/internal/ui/helpers_test.go index 7245145..8e58b63 100644 --- a/internal/ui/helpers_test.go +++ b/internal/ui/helpers_test.go @@ -434,6 +434,20 @@ func TestHandleTextInputKeepsStateOnEnterError(t *testing.T) { } } +func TestClearStatusMsgClearsStatus(t *testing.T) { + m := Model{statusMsg: "temporary"} + + mv, cmd := (&m).Update(clearStatusMsg{}) + m = *mv.(*Model) + + if cmd != nil { + t.Fatalf("clear status returned command") + } + if m.statusMsg != "" { + t.Fatalf("status message was not cleared: %q", m.statusMsg) + } +} + func TestActivateDueEditFallsBackToNowOnInvalidDate(t *testing.T) { m := Model{windowHeight: 20} before := time.Now().Add(-time.Second) diff --git a/internal/ui/table.go b/internal/ui/table.go index be775fb..f7e9ed6 100644 --- a/internal/ui/table.go +++ b/internal/ui/table.go @@ -659,7 +659,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m.handleOpenURLDone(msg) case blinkMsg: return m.handleBlinkMsg() - case struct{ clearStatus bool }: + case clearStatusMsg: m.statusMsg = "" return m, nil case tea.KeyPressMsg: -- cgit v1.2.3