summaryrefslogtreecommitdiff
path: root/android/app/src/main/java/org/terst
AgeCommit message (Collapse)Author
2026-07-16Show scheduled/available badge on widget TODAY headerPeter Stone
Threads the /api/widget budget_status field through the Android widget's DataStore-backed cache (a new BUDGET_STATUS_JSON pref, since the widget decomposes WidgetResponse into individual prefs rather than caching it whole) and renders a small "Nm/Nm" badge next to TODAY when there's a nonzero tracked load.
2026-07-16feat(widget): show project color as a small accent on task rowsPeter Stone
2026-07-16feat(widget): add project picker and label editor to task detail popupPeter Stone
2026-07-16feat(widget): add Android data layer for projects and label colorsPeter Stone
2026-07-16refactor(widget): split DootWidget.kt by responsibilityPeter Stone
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
2026-07-16fix(widget): redesign recurrence dialog layoutPeter Stone
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
2026-07-16fix(widget): match task font color to events; complete instantlyPeter Stone
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
2026-07-16fix(widget): re-arm periodic refresh on every onUpdate, not just onEnabledPeter Stone
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
2026-07-16fix(widget): remove red text color for overdue tasksPeter Stone
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
2026-07-16feat(widget): redesign task detail popup with editing and recurrencePeter Stone
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.
2026-07-16feat(widget): add description linkification for URLs and phone numbersPeter Stone
2026-07-16feat(widget): add WidgetRepository methods for task detail/recurrencePeter Stone
2026-07-16fix(widget): fix all-day alignment, drop duplicate TODAY, boost label ↵Peter Stone
legibility, soften overdue red - AllDayRow now has the same 32dp leading gutter as HourRow's hour-label column, so its color bar lines up with EventBlock's bar in the grid below instead of sitting flush left; also dropped the title's defaultWeight() so the multi-day label sits right after the title instead of being pushed to the far-right edge. - TaskFragmentBlock no longer renders its own "TODAY" sub-header -- it's always inside the already-labeled TODAY section, and Tomorrow's floating tasks never had this redundant label to begin with. - Section headers and hour/time labels bumped from ~30-40% to ~50-60% opacity -- against a home-screen wallpaper the previous values were barely legible. - Overdue task text alpha reduced to 0.75 -- full-opacity bright red read as too alarming.
2026-07-16fix(widget): scale content font sizes down 5% across all text-size tiersPeter Stone
2026-07-16fix(widget): render multi-day starts/ends label at full opacityPeter Stone
The label was concatenated into the title string, inheriting its 0.9 alpha. Split into its own Text at full opacity, matching EventBlock's treatment of upcoming (non-past) events.
2026-07-16feat(widget): show multi-day calendar events on every day they spanPeter Stone
Multi-day events (Start and End on different calendar days) are pulled out of the normal grid/all-day pipeline and rendered as an all-day-style row on every day they touch (Today and/or Tomorrow), labeled starts/ends/plain per the day being rendered. Previously such an event either only appeared in the single hourly grid slot matching its start time (never again on later days) or, if genuinely flagged all-day, never had its End forwarded at all.
2026-07-16feat(widget): tap event to open its source directly, drop detail popupPeter Stone
Tapping a calendar event (or any event-type item) now opens the event's URL (Google Calendar, Plan to Eat, etc.) directly instead of showing an intermediate popup with an "Open in Calendar" button. Removes EventDetailActivity and the recurrence-schedule lookup it was the only consumer of: WidgetRepository.getRecurrence, the Go /api/widget/recurrence endpoint, HandleWidgetRecurrence, GoogleCalendarAPI.GetRecurrenceRule, and formatRecurrence, plus their tests. RecurringEventID itself stays -- it's general calendar-sync metadata used elsewhere in the timeline pipeline, not exclusive to the removed popup.
2026-07-16fix(widget): give Text Size label and chip labels explicit colorsPeter Stone
These were the only labels in the settings screen without an explicit color, unlike the rest of the screen's text elements.
2026-07-16fix(widget): floor header text size/weight at NORMAL even when SMALLPeter Stone
Headers (hour labels, section titles) shrinking along with content at the SMALL setting made them too small relative to content. Content still shrinks at SMALL; headers now stay at NORMAL's scale/weight regardless of the selected tier.
2026-07-16chore(widget): remove dead sp importPeter Stone
Unused after threading WidgetTextSize's scaling functions through every Text() call site that previously used a literal .sp value.
2026-07-16fix(widget): restore trailing-slash trim on Test button's URLPeter Stone
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-16feat(widget): add Small/Normal/Large text size picker to widget settingsPeter Stone
2026-07-16feat(widget): thread WidgetTextSize through all widget text renderingPeter Stone
2026-07-16feat(widget): add WidgetTextSize enum with independent header/content scalingPeter Stone
2026-07-16fix(widget): stop tomorrow's events from stretching today's grid boundsPeter Stone
calcGridStart/calcGridEnd only looked at hour-of-day, so a tomorrow event's early or late hour could inflate today's grid range with empty rows, pushing the non-scrolling TomorrowSection below the widget's visible area. Filter to today-only events before computing bounds.
2026-07-13Merge github/master: reconcile with parallel widget workPeter Stone
Another session pushed 27 commits in parallel covering quick-add, event detail popups, recurrence display, overdue badges, a manual refresh button, and its own fix for the same overdue-tasks bug (via a separate GetOverdueNativeTasks fetch folded into BuildTimeline, rather than widening GetNativeTasksByDateRange's bound directly). Reconciled rather than blindly taking one side: - Reverted GetNativeTasksByDateRange to its original bounded query and kept upstream's GetOverdueNativeTasks + BuildTimeline fold-in as the sole overdue mechanism for native tasks, to avoid double-counting overdue items (my widened query + their separate fetch would have both returned them). Re-pointed the regression test at the now-correct contract and added a store-level test for GetOverdueNativeTasks directly. - Kept my GetGoogleTasksByDateRange fix as-is (single unbounded query) -- upstream never touched Google Tasks overdue handling, so there's no duplication risk there. - Rewove WidgetRoot's LazyColumn structure (added for scrolling) around upstream's new header buttons, pinned all-day event rows, and the enhanced TomorrowSection, none of which were written LazyColumn-aware since that work landed on this side only. - Combined both sides' additions to TaskDetailActivity/TaskDetailSheet (description-edit detail popup + due-date reschedule label) and WidgetRepository/Actions (optimistic local removal + refresh button wiring) -- these were independent, non-overlapping features that both needed to survive. - Renumbered the migration collision: both sides independently added a migration numbered 022. Card-description was already applied to the live production DB under that filename earlier this session (migrations are tracked by filename), so it keeps 022; the recurring-event-id migration, never deployed under any name here, moves to 023. Verified: go build clean, full test suite passes (only the two pre-existing agent-handler failures and the pre-existing models package build error remain, both confirmed unrelated via git stash before this session began), and a dry run against a copy of the live production database applies both migrations cleanly with no re-run conflicts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
2026-07-13feat(widget): editable task details, scrollable list, and overdue-task fixesPeter Stone
- Add description editing to the widget's task detail popup for doot/gtasks/trello, backed by new GET /api/widget/detail and POST /api/widget/update endpoints - Make Google Tasks and Trello cards completable via the widget (Trello completion archives the card); fix Trello description never being fetched, which meant saving could silently wipe a card's real desc - Fix google_tasks.due_date/updated_at (TEXT columns) never round-tripping through sql.NullTime, which broke cached Google Tasks reads whenever the cache was valid - Fix native-task and Google-Task date-range queries excluding anything due before the window start, which dropped incomplete tasks off the widget the moment their due day passed (the "overdue tasks disappeared" bug) - Fix native task description edits blanking the task's title - Make the widget's day list scroll (LazyColumn) instead of clipping - Optimistically remove a task from the widget immediately on completion, ahead of the authoritative background refresh Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
2026-07-12feat(widget): add event detail popup showing recurrence schedulePeter Stone
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
2026-07-12fix(widget): add IME handling to quick-add's keyboard-covering input fieldPeter Stone
2026-07-12feat(widget): add quick-add button and entry sheetPeter Stone
2026-07-12feat(widget): make the due-date display the reschedule tap targetPeter Stone
2026-07-12feat(widget): color overdue task titles distinctlyPeter Stone
2026-07-12feat(widget): add manual refresh button with loading-state iconPeter Stone
2026-07-12fix(widget): pin all-day calendar events to the top instead of losing themPeter Stone
WidgetItem.isAllDay was carried by the client's data model but nothing ever read it. All-day events had no Start at all, so they fell into the same floating-task queue as ordinary untimed tasks; if enough tasks were ahead of one in the queue, SlotPacker could assign it an hour slot past the visible grid range entirely -- not merely unpinned, actually invisible. Server: TimelineItemToWidgetItem now populates Start for all-day CALENDAR EVENTS specifically (their real event date), while leaving undated doot/gtask tasks -- also flagged IsAllDay as a "no specific time" fallback, a different concept -- on the existing nil-Start floating behavior. Client: all-day events are filtered out of the hourly grid/floating-task pipeline entirely, bucketed by day using the new Start date, and rendered in a new pinned AllDayRow section right after the TODAY/TOMORROW headers.
2026-07-12fix(widget): dedup rapid completeTask taps on the same taskPeter Stone
CompleteWorker.enqueue used a plain WorkManager.enqueue(), which allows unlimited concurrent OneTimeWorkRequests. A rapid double-tap on the same row (plausible since the checkbox doesn't visually update until the full async round-trip -- complete() -> fetchAndPersist() -> updateAll() -- finishes) could spawn two independent, unordered CompleteWorker runs for the same task, each doing its own fetchAndPersist(); a second worker's fetch started before the first worker's complete() call had actually landed server-side could persist a stale snapshot after the first worker's correct one. Now uses enqueueUniqueWork("complete_$id", KEEP, ...) so a tap on a task that already has a completion in flight is dropped rather than racing a second worker. Different task ids remain independent.
2026-07-06fix(widget): separate checkbox and row clickables to fix completeTask tapClaudomator Agent
In Glance 1.1.0 (RemoteViews), a parent Row with .clickable() silently overrides any nested child .clickable() — tapping the checkbox fired the detail-open action instead of CompleteTaskAction, producing no visible effect. Fix by splitting TaskRow into two sibling Boxes: a 24dp tap target wrapping the checkbox icon (routes to CompleteTaskAction) and a defaultWeight Box for the title (routes to actionStartActivity). No nesting, so both actions are independently reachable. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29feat: show tomorrow section in widget; note web viewPeter Stone
Widget now renders a TOMORROW block below the today grid: events with inline time labels (slightly dimmed) and task rows. Separated by a divider. Covers both explicit-start tomorrow items and slot-packed fragments that overflow from today. Web view: TODO comment to flatten the tomorrow section to match widget. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29feat: reschedule tasks from widget bottom sheetPeter Stone
Tapping a doot task shows a date picker. On confirm, POSTs to /api/widget/reschedule, updates due_date in native_tasks, refreshes widget. Reschedule button only shows for source="doot" tasks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29feat: native task management + Todoist migrationPeter Stone
Adds doot-owned task storage (native_tasks table) so tasks can be managed without Todoist. CompleteTask for 'doot' source just updates the DB — no external API call, no token dependency. Migration path: POST /settings/import-from-todoist — copies Todoist cache → native_tasks Then remove TODOIST_TOKEN from .env to disable Todoist Changes: - migration 020: native_tasks table - store: GetNativeTasks, GetNativeTasksByDateRange, GetUndatedNativeTasks, CreateNativeTask, CompleteNativeTask, UncompleteNativeTask, UpdateNativeTask, ImportFromTodoist - timeline: native tasks appear as source="doot" (teal) - handleAtomToggle: "doot" case — no external API needed - HandleWidgetComplete: method on Handler, handles "doot" natively - HandleUnifiedAdd: "doot" source creates in native_tasks - widget: "doot" tasks are completable, teal color indicator Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29feat: native bottom sheet for widget task detailPeter Stone
Replaces browser deep-link with a transparent TaskDetailActivity that shows a Material3 ModalBottomSheet (20-40% screen height). The launcher shows through the transparent window behind the dark scrim. Sheet shows source color dot, task title, and Mark Complete button for Todoist tasks. Tapping outside or swiping down dismisses. No browser involved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29feat: add standalone task detail page for Android widget deep-linksPeter Stone
Adds GET /task?id=xxx&source=xxx route that renders a full mobile-friendly task detail page (session-protected). Widget task rows now open this page when tapped. HandleUpdateTask redirects back to the page after a non-HTMX save. Android: threads serverUrl through composable chain to TaskRow. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29fix: more padding, larger text, past tasks float before untimed tasksPeter Stone
2026-06-29fix: widget doubling (hourEnd), transparent bg, tomorrow items, larger textPeter Stone
2026-06-29fix: resolve Glance ColorProvider import, Box content lambdas, OkHttp Call ↵Peter Stone
import in tests
2026-06-29feat: Android widget — SlotPacker, WidgetRepository, Workers, Glance UI, ↵Peter Stone
SettingsActivity
2026-06-29feat: add WidgetItem data class and DataStore keysPeter Stone