Skip to content

Configure logical day framing and multi-display capture#316

Open
rmqg wants to merge 10 commits into
JerryZLiu:mainfrom
rmqg:feature/configurable-day-start-time
Open

Configure logical day framing and multi-display capture#316
rmqg wants to merge 10 commits into
JerryZLiu:mainfrom
rmqg:feature/configurable-day-start-time

Conversation

@rmqg

@rmqg rmqg commented Jul 9, 2026

Copy link
Copy Markdown

What & why

Dayflow previously hard-coded a 4 AM logical-day boundary and always labeled a cross-midnight day by its start date. A display-only End date implementation was unsafe because headings could look right while cards, exports, reprocessing, chat, and analytics still used another date.

This PR makes the boundary and label mode configurable while preserving the existing storage model. It also completes multi-display capture and a reproducible local development workflow.

Date model

  • Storage and fetch keys remain anchored to the logical day's start date. There is no data migration.
  • Start date / End date controls the user-facing calendar label.
  • End-date mode shifts only when the configured boundary is after midnight; a 0 AM boundary is an identity mapping.
  • Weekly headers and Monday-Sunday columns remain a fixed natural week.
  • Each week column carries a separate storage key, and weekly queries use the mapped storage range.

Changes

  • Add a configurable day-start hour, defaulting to 4 AM.
  • Add Start date / End date labeling and immediate dayFramingChanged refreshes.
  • Apply label mapping to Daily, Standup, Workflow, Journal, date pickers, clipboard, export, reprocessing, and chat/dashboard tools.
  • Keep reprocess helper text, confirmation messages, progress messages, and export filenames aligned with the selected label date while operations still use storage keys.
  • Generate Chat system framing dynamically from the configured boundary and label mode; direct SQL guidance explains End date to storage-date mapping.
  • Load and group weekly Timeline and analytics data by mapped storage keys without moving the natural-week header.
  • Capture and composite every connected display into one screenshot record.
  • Request screen-capture access again when an onboarded installation loses approval.
  • Add scripts/dev.sh with stable local signing and automatic discovery of Xcode outside /Applications.
  • Fix a SwiftUI binding initialization issue exposed by Xcode 27.

Testing

  • ./scripts/dev.sh test with Xcode 27.0 (27A5218g): 15 tests passed.
  • Date tests cover 4 AM, 4 PM, 0 AM, Start/End modes, natural weeks, storage windows, display/storage separation, and Chat framing.
  • Composite tests cover negative-coordinate side-by-side displays and vertical display stacks.
  • Signed Debug build and installation succeeded with Xcode 27.
  • Two consecutive local installs retain the stable designated requirement without a second TCC reset.

Visual verification

Verified the installed /Applications/Dayflow.app in End date mode:

  • Export From/To and Reprocess picker showed Jul 11, 2026.
  • Reprocess ISO helper and confirmation alert showed 2026-07-11, not the internal 2026-07-10 storage key.
  • Export save panel defaulted to Dayflow timeline 2026-07-11 to 2026-07-11.
  • Reprocessing and export were cancelled; no user data was changed.

Compatibility and remaining validation

  • Defaults remain 4 AM and Start date.
  • Existing stored data is not rewritten.
  • Real mixed-DPI multi-display screenshot output still needs manual visual validation on representative hardware; layout geometry is covered by tests.
  • The project still emits its pre-existing warning about Info.plist in Copy Bundle Resources.

rmqg and others added 3 commits July 9, 2026 04:06
Dayflow's "day" rolled over at a hard-coded 4 AM. That boundary was
duplicated across ~15 call sites (timeline day bucketing, daily recap
scheduling, day reprocessing, journal activity checks, weekly ranges,
chat/dashboard date tools, and timeline review), so there was no single
place to change it.

This adds a user-configurable day start hour so people with non-standard
schedules can attribute late-night activity to the correct day.

Changes:
- Add DayBoundaryPreferences: a UserDefaults-backed hour (key
  "dayBoundaryHour"), clamped to 0-23, defaulting to 4 to preserve the
  current behavior.
- Route every day-boundary computation through
  DayBoundaryPreferences.boundaryHour instead of the literal 4.
- Add a "Day start time" picker to Settings -> Other.

The default is unchanged (4 AM), so existing users see no difference
until they pick a different hour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first pass covered day *bucketing* but missed several places that
independently hard-coded the 4 AM boundary for the visual hour axis and
for minute-based day-window math:

- Timeline hour axis: CanvasTimelineDataView and WeekTimelineGridView
  (startHour/endHour now derive from the boundary hour; the axis still
  spans a full 24h).
- Minute-based day window / midnight-wrap normalization: WeeklyDonutBuilder,
  WeeklyOverviewBuilder, WeeklyDashboardBuilder (+HeatmapWorkflow),
  DailyWorkflowComputation, DaySummaryStats -- the "< 240 (4*60)" wrap
  threshold and the [4*60, 28*60] window now use DayBoundaryPreferences.
- Add DayBoundaryPreferences.boundaryMinutes helper.

Verified with a clean xcodebuild (Xcode 26.6): BUILD SUCCEEDED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two spots still assumed a pre-noon (4 AM) boundary and broke when the day
start is later than noon (e.g. 4 PM):

- normalizedTimelineDate() anchored the timeline's representative time to
  noon. Composed with getDayInfoFor4AMBoundary() (as DaySummaryView's
  timelineDayInfo and the recording projection window both do), a noon
  anchor with a boundary later than noon rolled the day back one extra
  day -- so "Your day so far" fetched the wrong (empty) day and the live
  "generating next card" indicator was clamped to the bottom of the axis.
  Anchor to the boundary hour instead.
- nowCenteredTargetHourIndex() still hard-coded the 4 AM baseline for the
  scroll-to-now target; derive it from CanvasConfig.startHour.

Verified with a clean xcodebuild (Xcode 26.6): BUILD SUCCEEDED, and
confirmed at runtime with the day start set to 4 PM (stats populate and
the live indicator sits at the current time).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rmqg

rmqg commented Jul 9, 2026

Copy link
Copy Markdown
Author

Follow-up: pushed two more commits that make the timeline hour axis + weekly/daily aggregation respect the boundary, and fix two spots that assumed a pre-noon boundary (normalizedTimelineDate anchored to noon, and a hard-coded 4 AM baseline in the scroll-to-now target). Without these, a boundary later than noon (e.g. 4 PM) made "Your day so far" show the wrong/empty day and pinned the live indicator to the bottom of the axis.

Built cleanly (Xcode 26.6) and runtime-tested end to end with the day start set to 4 PM: timeline axis starts at 4 PM, stats populate for the correct logical day, and the live indicator sits at the current time.

@rmqg rmqg changed the title Add configurable day start time (day boundary hour) Configure logical day framing and multi-display capture Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant