Repository navigation
today: window the iOS Latest Workouts feed to the same 14 days as Android - #1703
Merged
Merged
Conversation
…roid Reported as #1702. The two platforms rendered the same section from different data: Android windows to today-13 at start of day and says "14 days" in the header, while iOS drew from repo.workoutRows(), whose default is days: 4000 — effectively all-time — under a heading that says "Latest", trailed by a count of every workout ever recorded. The visible result was that one account read two ways. Someone who last trained three months ago saw no section at all on Android and six stale sessions on iOS. Reading the call sites suggests iOS's behaviour was never a product decision. Android keeps two sets — recentUnion for the feed, separate all-time queries for the Data Sources counts — while iOS has a single `workouts` array serving both, and the section simply used what was already there. That is also why the window is applied at the SECTION rather than to the array. `workouts` also feeds the Data Sources Apple-workout count and the HR chart's sport glyphs, both all-time by design; windowing it at the source compiles, looks correct, and quietly shrinks two unrelated numbers on the same screen. The trailing header now describes the window on both platforms. "14 days" was already in the string catalogue in all ten locales, so no new copy. Tile caps stay 4 on Android and 6 on iOS. That difference is layout, not content: Android is deliberately single-column full-width (the 2x2 grid truncated durations on narrow phones, #332), iOS uses an adaptive grid. Same vertical budget, and unifying it would change one platform's density for no reader benefit. TodayWorkoutsWindowTests pins the boundary rather than the happy path — a session exactly on the cutoff is kept, one second earlier is dropped — because an off-by-one there silently drops a session the other platform still shows. TodayWorkoutTapTest gains a parity assertion that runs in ordinary CI and checks the Data Sources count still reads the unwindowed array, so the trap is guarded and not merely sidestepped once. Verified: 4,713 Android tests, 0 failures with --rerun-tasks --no-build-cache; i18n audit clean. The Swift half compiles only under app-build.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #1702, on the decision to match Android's window.
What was actually wrong
The two platforms rendered the same section from different data. Android windows to
today − 13at start of day and says "14 days" in the header. iOS drew fromrepo.workoutRows(), whose default isdays: 4000— effectively all-time — under a heading that says "Latest", trailed by a count of every workout ever recorded.One account read two ways: someone who last trained three months ago saw no section on Android and six stale sessions on iOS.
Reading the call sites suggests iOS's behaviour was never a product decision. Android keeps two sets —
recentUnionfor the feed, separate all-time queries for the Data Sources counts. iOS has a singleworkoutsarray serving both, and the section simply used what was already there.Why the window is applied at the section
This is the part worth reviewing carefully.
workoutsis shared:TodayView.swift:3939)workoutSpans)Both are all-time by design. Windowing the array at its source compiles, looks correct, and quietly shrinks two unrelated numbers on the same screen. So
TodayView.recentWorkoutsFeedwindows at the section and the shared array is left alone.Also
"14 days"already existed in the catalogue in all ten locales, so there is no new copy and no xcstrings work."\(workouts.count) total"is gone — it counted all-time while showing six.Tests
TodayWorkoutsWindowTests(Swift, runs under app-build) pins the boundary, not the happy path: a session exactly on the cutoff is kept, one second earlier is dropped, and filtering must not reorder. An off-by-one there silently drops a session the other platform still shows — the same class of drift that produced the issue.TodayWorkoutTapTestgains a parity assertion that runs in ordinary CI and explicitly checks the Data Sources count still reads the unwindowed array. The trap above is guarded, not merely sidestepped once.Verified
4,713 Android tests, 0 failures with
--rerun-tasks --no-build-cache;Tools/i18n_audit.py --ciclean. The Swift half compiles only under app-build — dispatching it, and I will post the result here before this merges.Note for review
This changes iOS behaviour: the section now disappears when you have not trained in two weeks, matching Android. That is the consequence of the chosen option, not a side effect.