Skip to content

Park screen redraws at 1 Hz whenever it is open, with no low-power or Reduce Motion consideration #32

Description

@lightcloud00

What

The Park screen now drives two always-on TimelineView(.periodic(from: .now, by: 1)):

  • MeterHero — the countdown, its progress bar, and the state evaluation;
  • detailsCard — the "Parked for h:mm:ss" line.

Both tick every second for as long as the screen is open, and the hero's tick re-evaluates MeterState and re-renders a ProgressView. The elapsed timer predates the redesign; the hero is new, so the screen now does roughly twice the per-second work it used to.

Why it may matter here specifically

This is a screen people leave open while walking back to a car — outdoors, on cellular, often on a phone that has been out all day. It is close to the worst case for an always-on 1 Hz redraw.

What has not been established

Nothing has been measured. This is a flagged concern, not a demonstrated defect:

  • no Instruments trace of the Park screen idling with a meter set;
  • no comparison against the pre-redesign single timer;
  • no check of what Low Power Mode should do.

AGENTS.md requires Reduce Motion support. A per-second numeric update is arguably not "motion", but a continuously animating progress bar is closer to the line, and the question has not been asked.

Suggested approach

Measure first. If it is negligible, close this with the number and stop worrying about it. If it is not:

  • one TimelineView for the whole screen instead of two;
  • drop to .periodic(by: 60) once the remaining time is over an hour, where seconds carry no information;
  • consider @Environment(\.accessibilityReduceMotion) for the progress bar's animation only, never for the countdown itself — suppressing the number would remove information rather than motion.

Acceptance

  • Idle CPU/energy measured with a meter running, and recorded here.
  • Compared against the single-timer baseline.
  • Either closed with the measurement, or reduced and re-measured.

Resolution plan

  • Verified: 2026-08-25T04:51:19Z against main@04a6cd5e808720983471ee9595fd40bc94e1f0fe (commit time 2026-08-25T00:53:29Z).
  • Source basis: Original issue body, all 0 comment(s), current default-branch tree, referenced pull-request states, and the protected top-90 dossier revalidated without modifying it.
  • Disposition: Code or verification work - not complete on the verified default branch.
  • Outcome: Park screen redraws at 1 Hz whenever it is open, with no low-power or Reduce Motion consideration

Current evidence and corrected premise

Verdict — NOT_STARTED. Two exact sites confirmed.

ParkNudge/UI/Park/ParkView.swift:

:162    TimelineView(.periodic(from: .now, by: 1)) { context in
:319    TimelineView(.periodic(from: .now, by: 1)) { context in

Two independent 1 Hz timelines in one screen. Each rebuilds its subtree every second for as long as
the view is on screen, regardless of whether anything visible changed, whether the device is in Low
Power Mode, or whether the user has asked for Reduce Motion.
P2 · accessibility, area: ios, priority:p2, revenue:r3 · Canonical source: origin/main
All 0 issue comment(s) were read. There are no comments.
Verified source paths on this head:

  • AGENTS.md
  • ParkNudge/UI/Park/ParkView.swift
  • ParkNudgeTests/MeterStateTests.swift

Resolution steps

Exact fix

  1. Drop the cadence when seconds are not visible. If the label reads "2h 14m", a 1 Hz tick is
    ~119 wasted rebuilds per minute. Use .periodic(by: 1) only while the remaining time is under a
    minute (or whatever threshold makes the seconds digit meaningful); otherwise by: 60. This alone
    removes almost all of the cost.
  2. Honour Low Power ModeProcessInfo.processInfo.isLowPowerModeEnabled, and observe
    .NSProcessInfoPowerStateDidChange so it reacts rather than sampling once at launch.
  3. Honour Reduce Motion@Environment(\.accessibilityReduceMotion). Where the timeline drives
    an animation rather than a text update, this should stop it entirely, not slow it.
  4. Collapse the two timelines into one if both drive the same clock. Two independent periodic
    sources in one view means two rebuild storms with no shared phase.

Keep the countdown correct — recompute from a stored expiry Date, never by decrementing a
counter, so a slower tick or a missed one cannot drift.

Tests and acceptance

Test / proof

ParkNudgeTests/MeterStateTests.swift already tests the state transitions; extend the same seam
with a test that the chosen tick interval is 60 when remaining time is large and 1 when small.
Battery behaviour itself is not unit-testable — verify by observing that the view body evaluates at
the expected cadence (a counter incremented in the timeline closure under test).

Gate — the repo's unit scheme

  • For every listed xcodebuild argv, submit the equivalent focused job through the shared fleet-build gate after iOS capacity admission; do not run xcodebuild directly.

Dependencies and stop gates

Out of scope — #29's meter hero states; general animation policy elsewhere in the app

  • Do not close this issue until every acceptance item is mapped to exact merged-head evidence.

Next AI first action

Drop the cadence when seconds are not visible.** If the label reads "2h 14m", a 1 Hz tick is

Metadata

Metadata

Assignees

No one assigned

    Labels

    accessibilityBarrier affecting people with disabilitiesarea: iosiOS application workpriority:p2Post-MVP or lower-priority workreadiness:diagnosticExact bounded investigation requiredrevenue:r3Indirect or long-range revenue impact

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions