From 244d751412a0a1e3ede8bd91e114a4ef4e1a7eaa Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Fri, 17 Jul 2026 08:53:57 +0000 Subject: fix(widget): autofocus quick-add title field, redesign as blank edit form Quick Add's text field never requested focus or triggered the keyboard, so tapping it opened a sheet with no visible way to type. Added a FocusRequester + delayed requestFocus()/keyboard show (ModalBottomSheet needs a beat to finish its enter animation before focus requests land). While in there, rebuilt the quick-add sheet to match the task edit popup instead of being a bare title field: due date, recurrence, project, and label chips, plus a description field, reusing the same dialogs the edit popup already uses. POST /api/widget/add now returns the created task's id so the client can chain the same project/labels/recurrence/due-date setter calls edit already relies on. --- internal/handlers/widget.go | 11 +++++++++-- internal/handlers/widget_test.go | 12 ++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'internal') diff --git a/internal/handlers/widget.go b/internal/handlers/widget.go index 5880314..a2a0837 100644 --- a/internal/handlers/widget.go +++ b/internal/handlers/widget.go @@ -430,7 +430,13 @@ func (h *Handler) HandleWidgetComplete(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -// HandleWidgetAdd creates a new undated native task from the widget's quick-add sheet. +type widgetAddResponse struct { + ID string `json:"id"` +} + +// HandleWidgetAdd creates a new undated native task from the widget's quick-add +// sheet and returns its id, so the client can follow up with the same +// project/labels/recurrence/due-date setter calls the edit popup uses. func (h *Handler) HandleWidgetAdd(w http.ResponseWriter, r *http.Request) { var req widgetAddRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { @@ -454,7 +460,8 @@ func (h *Handler) HandleWidgetAdd(w http.ResponseWriter, r *http.Request) { return } - w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(widgetAddResponse{ID: task.ID}) } type recurrenceResponse struct { diff --git a/internal/handlers/widget_test.go b/internal/handlers/widget_test.go index 02df111..749af3a 100644 --- a/internal/handlers/widget_test.go +++ b/internal/handlers/widget_test.go @@ -721,18 +721,26 @@ func TestHandleWidgetAdd_CreatesTask(t *testing.T) { t.Fatalf("expected 200, got %d", w.Code) } + var resp widgetAddResponse + if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { + t.Fatalf("failed to decode response: %v", err) + } + if resp.ID == "" { + t.Fatal("expected a non-empty id in the response") + } + tasks, err := s.GetUndatedNativeTasks() if err != nil { t.Fatalf("failed to read back tasks: %v", err) } found := false for _, task := range tasks { - if task.Content == "Buy milk" { + if task.Content == "Buy milk" && task.ID == resp.ID { found = true } } if !found { - t.Error("expected a task with content 'Buy milk' to have been created") + t.Error("expected a task with content 'Buy milk' and matching id to have been created") } } -- cgit v1.2.3