| Age | Commit message (Collapse) | Author |
|
Wires ComputeBudgetPeriod together with availability blocks, tracked
project/label sets, calendar events, and native tasks into a new
computeBudgetStatus helper on *Handler. HandleWidgetGet now populates
WidgetResponse.BudgetStatus with today/week periods, but only when at
least one incomplete budget-tracked task exists in the rolling week
window -- otherwise the field is omitted entirely so unconfigured users
see no new UI. Errors are logged and swallowed, matching the existing
resilience pattern for this widget endpoint.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
|
|
task-filter doc comment; add multi-day test
Overlapping calendar events within the same availability block were each
subtracted independently, double-counting their intersection and making
availability under-counted (a 120-min block with two 60-min-overlap events
that overlap each other 18:30-19:00 came out to 0 min instead of the
correct 30 min). Replace the per-event overlapMinutes subtraction with
busyMinutesInBlock, which clips each event to the block, merges the
clipped intervals, and subtracts the union's total length.
Also clarify ComputeBudgetPeriod's doc comment: task filtering only
enforces an upper bound (due < end); start is intentionally not used to
filter tasks, since callers are expected to pre-fetch and pass in
already-overdue tasks. Add a multi-day-window test verifying availability
sums correctly across days, a block only contributes on its matching
weekday, and the day-iteration loop excludes the day at `end`.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
|
|
ComputeBudgetPeriod is a standalone, dependency-free function over
in-memory availability blocks, calendar events, and tasks: sums weekly
availability minus overlapping calendar events for [start, end), and
sums estimated minutes for tracked, incomplete tasks due in that window.
|
|
|
|
flag
|
|
|
|
|
|
Fix formatting and alignment violations: align struct field tags in Task,
realign Weekday comment in AvailabilityBlock, and remove extra blank line
before CalendarEvent.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session
|
|
Add EstimatedMinutes to Task, BudgetTracked to Project and LabelColor
structs. Create budget.go with AvailabilityBlock, BudgetPeriod, and
BudgetStatus types for modeling task budgets and calendar availability.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
|
|
Creates migrations/025_task_budgets_and_availability.sql with:
- New availability_blocks table for manual weekly availability templates
- estimated_minutes column on native_tasks for time budgeting
- budget_tracked flag on projects and labels for opt-in tracking
Fixes pre-existing bug in sqlite_test.go's setupTestStoreWithNativeTasks where
project_id column was missing from the schema, causing test failures.
Updates all hand-rolled test helpers (sqlite_test.go, native_tasks_test.go)
to include the new columns, and adds availability_test.go with newAvailabilityTestStore
helper for Task 4's availability CRUD tests.
All store tests pass, including the two that were previously failing
(TestGetNativeTasksByDateRange_ExcludesOverdue, TestGetOverdueNativeTasks_IncludesOnlyPastDue).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
|
|
HandleAgentTaskCreate decoded project_id from the request but never
forwarded it to CreateNativeTask, so a task created via the external
Agent API with a project assigned would silently create the task
unassigned instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
|
|
|
|
|
|
Tests verify ProjectColor is populated in BuildTimeline and copied to WidgetItem.
|
|
Projects are fetched once per BuildTimeline call into a color lookup
map, not queried per-task -- same pattern as RecurringEventID's
existing TimelineItem->WidgetItem threading.
|
|
Tests for HandleWidgetProjectsGet, HandleWidgetProjectsCreate,
HandleWidgetTaskProject, HandleWidgetTaskLabels, HandleWidgetLabelsGet,
HandleWidgetLabelsColorSet, and the extended HandleWidgetTaskDetail
response with project and labels fields.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Extends the task-detail response with project/labels so the popup can
display them without a second round trip.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
|
|
|
|
project_id joins the existing labels JSON column as series-level
metadata: CreateNextIteration copies both onto every new recurring
occurrence, matching content/description/priority's existing behavior.
|
|
Nine tasks: schema/model + project_id wiring, Projects CRUD,
label-color CRUD, HTTP endpoints, TimelineItem/WidgetItem
project-color threading, Android data layer, task-detail popup UI
(project picker + label editor), widget grid color accent,
build/deploy.
|
|
Labels/projects, budgets/availability, recurring maintenance buckets,
and linear task chains -- refined via a 24-question interview
(2026-07-15) into concrete data models, mechanisms, and API shapes.
None approved for implementation yet; each spec notes its
dependencies on the others (labels/projects is foundational to two
of the other three).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
DootWidget.kt (582 lines) mixed the GlanceAppWidget entry point/root
composable, all the row-rendering composables, and multi-day-event
detection logic in one file. Split into:
- MultiDayEvents.kt: MultiDayVariant, effectiveEndDay, isMultiDayEvent,
multiDayVariant, multiDayLabel, timeSuffix.
- WidgetRows.kt: sourceColor, calendarViewIntent, and all row/section
composables (AllDayRow, RefreshButton, QuickAddButton, HourRow,
EventBlock, TaskFragmentBlock, TaskRow, TomorrowSection,
TomorrowEventRow), plus hourLabel/calcGridStart/calcGridEnd.
- DootWidget.kt: just the GlanceAppWidget class and WidgetRoot, now
145 lines.
All same package (org.terst.doot.widget.ui), so no import changes
needed for cross-file references. Pure move, no behavior change --
full unit test suite (including DootWidgetGridTest/
DootWidgetMultiDayTest, which call the internal functions directly)
passes unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Pure move: all agent-session and agent CRUD/trust methods (~340 lines)
plus their full test suite and setupTestStoreWithAgents helper, out of
sqlite.go/sqlite_test.go into agents.go/agents_test.go. No behavior
change. Mirrors internal/handlers/agent.go's domain naming.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Pure move: SaveCalendarEvents/GetCalendarEvents/GetCalendarEventsByDateRange
into calendar.go, SaveGoogleTasks/GetGoogleTasks/GetGoogleTasksByDateRange
into google_tasks.go. Neither cluster had dedicated tests in
sqlite_test.go to move. No behavior change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Pure move: UserShoppingItem type, its CRUD methods, and
SetShoppingItemChecked/GetShoppingItemChecks, plus their tests and
setupTestStoreWithShopping helper, out of sqlite.go. No behavior
change. Mirrors the existing internal/handlers/shopping.go naming.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Pure move: SaveMeals/GetMeals/GetMealsByDateRange and their test
(plus its setupTestStoreWithMeals helper, used only by that test) out
of the 1400+ line sqlite.go into their own file. No behavior change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
dialog)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
The 4 frequency chips and 7 weekday chips were each laid out in a
single non-wrapping Row -- on a real phone width these overflow/get
cut off rather than wrapping. The interval field was a full-width
OutlinedTextField with the unit baked into its label ("Every N
dailys"/"weeklys" -- ungrammatical for anything but weekly), and the
whole dialog had no visual grouping.
Redesigned: FlowRow (wraps instead of overflowing) for both chip rows;
single-letter weekday chips (S M T W T F S) to stay compact; a narrow
fixed-width (72dp) interval field paired with a correctly-pluralized
unit label rendered separately from the field; muted section labels
(REPEATS / EVERY / ON THESE DAYS) for structure. No callback/API
changes -- purely a layout rewrite of the same onSave/onClear/onDismiss
contract.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
TaskRow used a flat hardcoded gray (0xFFDDDDDD) while EventBlock used
Color.White (dimmed only when past) at the same size/weight -- the
color mismatch read as a font difference. Both now use the same
Color.White base.
CompleteTaskAction previously did no local update at all: the row
stayed visible until CompleteWorker's full complete() ->
fetchAndPersist() -> updateAll() round trip finished (two sequential
network calls). It now optimistically removes the completed item from
the cached list and re-renders immediately, matching RefreshTaskAction's
existing synchronous-flag-then-updateAll pattern -- the background
worker's own fetchAndPersist still replaces this with the authoritative
server state (including a newly-created recurring successor, if any)
moments later.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
onEnabled only fires when the first widget instance is added to a home
screen, so if the periodic RefreshWorker job is ever silently dropped
(an app reinstall can clear WorkManager's persisted schedule without
the widget itself being removed/re-added -- exactly what happens when
sideloading a new APK build, as opposed to a Play Store update), there
was no way for it to come back except manually removing and re-adding
the widget. onUpdate fires far more often (reboot, periodic OS ticks)
and now also re-arms the schedule (a no-op via KEEP if already running).
Root-caused via manual refresh restoring all missing content instantly
(rules out a data/rendering bug) plus the widget only showing one
stale morning event beforehand (consistent with the periodic job
having stopped ticking hours earlier, right around today's APK
reinstalls).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Task.IsRecurring/Atom.IsRecurring were never assigned anywhere in the
codebase (confirmed via full-repo search), so PartitionAtomsByTime's
"hide future recurring tasks until due" branch was permanently dead.
RecurrenceSeriesID is the real recurring indicator now; wiring up
"hide future recurring successors" as an actual feature is a separate
design decision, not part of this cleanup pass.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
- SourceMeal/TypeMeal (AtomSource/AtomType): leftover from the removed
MealToAtom conversion (b2d8fc4); zero references anywhere else.
- HandleGetSourceOptions: never registered as a route, and its own
test comment already noted "may fail if template not found, which
is acceptable" -- the settings-source-options template it rendered
doesn't exist in web/templates/ at all. Fully unreachable/broken,
not just unused.
go build/vet/test all clean, no behavior change for anything reachable.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Two independent pre-existing failures, both from incomplete refactors:
- agent.go's four task write/create switches (complete/uncomplete,
update due date, update details, create) never got a "doot" case
added when the Todoist integration was removed (945c345) in favor
of native tasks -- the test file was updated to use source=doot,
but the handlers themselves still only recognized "trello"/"gtasks",
so every native-task Agent API call 400'd with "Unknown source".
getAtomDetails already had a "doot" case, confirming this was an
incomplete migration, not an intentional gap.
- TestMealToAtom in atom_test.go tested MealToAtom, a function removed
from atom.go months earlier (b2d8fc4) when meals were dropped from
the unified Atom/timeline system; the Meal struct itself is still
used elsewhere (shopping/meals feature) but no longer produces atoms,
and the test was never cleaned up to match.
go test ./internal/... ./cmd/... is now fully green with no failures.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Overdue and non-overdue tasks now render with the same plain title
color; no more red highlighting for overdue items.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Folds the "is this still the latest row in its series?" check directly
into the INSERT as a single atomic INSERT...SELECT...WHERE NOT EXISTS
statement, instead of a separate SELECT-then-INSERT sequence. Closes a
narrow race where the completion trigger and the periodic due-date
check could both pass their "still latest" check before either had
inserted, producing two duplicate successor rows for the same series.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
Editable title/description (Edit -> Cancel/Save toggle), linkified
description, and independently-tappable date/recurrence/next-date
chips. Non-doot sources (Trello, Google Tasks) are unaffected --
same title + Complete button as before, no live fetch, no edit UI.
|
|
|
|
|
|
HandleWidgetTaskUpdate now returns 404 instead of silently succeeding
when the widget's cached task id no longer exists, matching every
other native_tasks mutator's checkRowsAffected pattern.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
GET /api/widget/task, POST /api/widget/task/update,
POST /api/widget/task/recurrence, POST /api/widget/task/next-date.
Doot-only; the recurrence/next-date fields are null in the detail
response for a non-recurring task.
|
|
A recurring task's successor now also gets created once its due date
passes, independent of completion -- an ignored/overdue recurring task
no longer blocks the next occurrence from appearing. Runs every 15
minutes via a new goroutine in main.go, cancelled on shutdown.
|
|
CompleteNativeTask now creates a new row for the next occurrence when
completing the latest iteration of a recurring series (using the
one-shot next_occurrence_override if set, else ComputeNextOccurrence).
Completing an already-superseded row (the periodic due-check beat it
to creating the successor) just marks it completed, no double-create.
|
|
Implement pure function to compute next occurrence of recurring tasks given
frequency, interval, and optional weekday constraints. Supports daily, weekly,
monthly, and yearly recurrence patterns. Weekly recurrence with weekday
constraints wraps to next applicable week when needed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|
|
recurrence_series_id != "" is the real recurring indicator (IsRecurring
predates this feature and is never set). Adds parseWeekdays/formatWeekdays
for the comma-separated weekday-list column, and threads the five new
columns through scanNativeTasks and all four existing SELECT queries.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
|