summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/handlers/timeline_logic.go7
-rw-r--r--internal/handlers/timeline_logic_test.go42
-rw-r--r--internal/models/timeline.go11
3 files changed, 58 insertions, 2 deletions
diff --git a/internal/handlers/timeline_logic.go b/internal/handlers/timeline_logic.go
index e3da760..b008221 100644
--- a/internal/handlers/timeline_logic.go
+++ b/internal/handlers/timeline_logic.go
@@ -146,6 +146,13 @@ func BuildTimeline(ctx context.Context, s *store.Store, start, end time.Time) ([
IsCompleted: gTask.Completed,
Source: "gtasks",
ListID: gTask.ListID,
+ // No due date -- flag IsAllDay like nativeUndated tasks below so
+ // TimelineItemToWidgetItem leaves Start nil instead of pinning it
+ // to "now", which otherwise lands it among scheduledEvents and
+ // renders it via EventBlock/HourRow -- rows whose click handler
+ // always opens the source URL/Google Calendar, not the task's
+ // detail sheet.
+ IsAllDay: gTask.DueDate == nil,
}
item.ComputeDaySection(now)
items = append(items, item)
diff --git a/internal/handlers/timeline_logic_test.go b/internal/handlers/timeline_logic_test.go
index 7b5c47e..1a6ea6c 100644
--- a/internal/handlers/timeline_logic_test.go
+++ b/internal/handlers/timeline_logic_test.go
@@ -169,6 +169,48 @@ func TestBuildTimeline(t *testing.T) {
}
}
+// TestBuildTimeline_UndatedGoogleTaskIsAllDay guards against a regression
+// where a Google Task with no due date got Time set to "now" but IsAllDay
+// left false (unlike nativeUndated doot tasks, which set IsAllDay: true).
+// TimelineItemToWidgetItem then treated the near-"now" Time as a real
+// scheduled Start, so the task could land among scheduledEvents and render
+// via the widget's EventBlock/HourRow -- rows whose click handler always
+// opens the source URL / Google Calendar instead of the task detail sheet.
+func TestBuildTimeline_UndatedGoogleTaskIsAllDay(t *testing.T) {
+ s := setupTestStore(t)
+
+ if err := s.SaveGoogleTasks([]models.GoogleTask{
+ {ID: "g1", Title: "Hardware store", Status: "needsAction", ListID: "l1"},
+ }); err != nil {
+ t.Fatalf("SaveGoogleTasks failed: %v", err)
+ }
+
+ start := time.Now().Add(-24 * time.Hour)
+ end := time.Now().Add(24 * time.Hour)
+ items, err := BuildTimeline(context.Background(), s, start, end)
+ if err != nil {
+ t.Fatalf("BuildTimeline failed: %v", err)
+ }
+
+ var found *models.TimelineItem
+ for i := range items {
+ if items[i].ID == "g1" {
+ found = &items[i]
+ }
+ }
+ if found == nil {
+ t.Fatal("expected undated google task g1 to appear in timeline")
+ }
+ if !found.IsAllDay {
+ t.Error("expected undated google task to be flagged IsAllDay so it stays a floating task on the widget, not a scheduled event")
+ }
+
+ wi := TimelineItemToWidgetItem(*found)
+ if wi.Start != nil {
+ t.Error("expected undated google task to have nil Start so the widget renders it via TaskRow, not EventBlock")
+ }
+}
+
func TestCalcCalendarBounds(t *testing.T) {
tests := []struct {
name string
diff --git a/internal/models/timeline.go b/internal/models/timeline.go
index 4b90856..5224b72 100644
--- a/internal/models/timeline.go
+++ b/internal/models/timeline.go
@@ -66,8 +66,15 @@ func (item *TimelineItem) ComputeDaySection(now time.Time) {
// Check if item is overdue (before today)
item.IsOverdue = itemDay.Before(today)
- // Check if item is all-day (midnight time means no specific time)
- item.IsAllDay = localItemTime.Hour() == 0 && localItemTime.Minute() == 0
+ // Check if item is all-day (midnight time means no specific time).
+ // Only ever sets IsAllDay to true here -- never clears a true a caller
+ // already set (e.g. nativeUndated/gtask "no due date" tasks, which use
+ // IsAllDay as a floating-task marker with Time set to "now", not
+ // midnight -- clobbering it back to false made them look like real
+ // scheduled items to the widget client).
+ if localItemTime.Hour() == 0 && localItemTime.Minute() == 0 {
+ item.IsAllDay = true
+ }
if itemDay.Before(tomorrow) {
item.DaySection = DaySectionToday