Add annual location time forecasts - #187
Conversation
| stay.region == region && stay.through >= today ? stay : nil | ||
| } | ||
| let plannedEnd = matchingStay.map { min($0.through, lastDay) } | ||
| let plannedDays = plannedEnd.map { tomorrow.days(through: $0).count } ?? 0 |
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Review focus: this is the load-bearing forecast policy. Planned days begin tomorrow, include the selected through-date, and baseline projection resumes the following day. The tests cover the April threshold, matching and non-matching stays, and cross-year stays.
There was a problem hiding this comment.
How come this has the "I'll be here through" button button but others don't? IMO we should have it on all of them?
|
|
||
| public func replacePlannedStayRecord(with record: PlannedStayRecord) async throws { | ||
| let context = mutationContext() | ||
| for existing in try context.fetch(FetchDescriptor<SDPlannedStay>()) { |
There was a problem hiding this comment.
wait, we're fetching them all and deleting them all, for one record?
There was a problem hiding this comment.
I guess this is because we can only have one planned stay, which wasn't exactly my intent, but maybe it makes sense for now?
| /// User intent that the current stay in `region` continues through an inclusive | ||
| /// calendar day. The day is timezone-independent so travel cannot move the | ||
| /// asserted departure onto a neighboring date. | ||
| public struct PlannedStay: Hashable, Sendable, Codable { |
There was a problem hiding this comment.
Should we also record when this was added? Might be useful if only for debugging and any UI that may show planned stays, especially if we allow entering future stays at some point.
| final class SDPlannedStay { | ||
| var id: UUID? | ||
| var regionID: String? | ||
| var throughDayKey: String? |
There was a problem hiding this comment.
Is this how we usually persist CalendarDays?
There was a problem hiding this comment.
I think our test data has too many days, if the current date is July 15th, then the stay duration (the regular duration, NOT the stay) should end there too.
| @@ -0,0 +1,29 @@ | |||
| import SwiftUI | |||
…orecasts # Conflicts: # Where/Tools/upgrade-backup.rb # Where/WhereCore/AGENTS.md # Where/WhereCore/README.md # Where/WhereCore/Sources/Backup/BackupArchive.swift # Where/WhereCore/Sources/Backup/BackupCoordinator.swift # Where/WhereCore/Sources/Backup/BackupService.swift # Where/WhereCore/Sources/Persistence/SwiftDataStore.swift # Where/WhereCore/Sources/Preferences/WherePreferences.swift # Where/WhereCore/Tests/BackupCoordinatorTests.swift # Where/WhereCore/Tests/BackupServiceTests.swift # Where/WhereCore/Tests/WherePreferencesTests.swift # Where/WhereUI/AGENTS.md # Where/WhereUI/README.md # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.Empty_iPhone.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.Empty_iPhone_dark.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.Focused_iPhone.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.Focused_iPhone_dark.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.FullContent_fullHeight.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPad.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPad_accessibility.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPad_ax5.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPad_contrast.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPad_dark.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPhone.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPhone_accessibility.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPhone_ax5.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPhone_contrast.png # Where/WhereUI/SnapshotTests/__Snapshots__/CalendarContentViewSnapshotTests/calendarContent.WithData_iPhone_dark.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPad.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPad_accessibility.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPad_ax5.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPad_contrast.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPad_dark.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPhone.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPhone_accessibility.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPhone_ax5.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPhone_contrast.png # Where/WhereUI/SnapshotTests/__Snapshots__/LocationsViewSnapshotTests/locations.Loaded_iPhone_dark.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Empty_iPhone.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Empty_iPhone_dark.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPad.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPad_accessibility.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPad_ax5.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPad_contrast.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPad_dark.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPhone.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPhone_accessibility.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPhone_ax5.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPhone_contrast.png # Where/WhereUI/SnapshotTests/__Snapshots__/YearViewSnapshotTests/year.Loaded_iPhone_dark.png # Where/WhereUI/Sources/Model/YearReportModel.swift # Where/WhereUI/Sources/Preview/PreviewSupport.swift # Where/WhereUI/Sources/Primary/CalendarContentView.swift # Where/WhereUI/Sources/Resources/Localizable.xcstrings # Where/WhereUI/Sources/Settings/LocationSettingsView.swift # Where/WhereUI/Sources/Settings/SettingsView.swift # Where/WhereUI/Tests/PrivacyPassportCardTests.swift # Where/WhereUI/Tests/Support/TestStore.swift
Summary
Behavior and trade-offs
The baseline annualizes days attributed to a region through today. A matching planned stay counts tomorrow through its inclusive departure date at full weight, then resumes the baseline pace for the remaining year. Only one planned stay is active at a time; clearing or expiry writes a tombstone so delayed sync cannot resurrect it.
Testing
./test --no-generate --everything— 1,638 unit tests and 33 snapshot suites passed./swiftformat --lint./xcstrings --lintruby -c Where/Tools/upgrade-backup.rbgit diff --check