Skip to content

settings: Live notifications — one switch each, and each hides only its own - #2419

Closed
UtkuDenizAltiok wants to merge 3 commits into
ryanbr:mainfrom
UtkuDenizAltiok:lockscreen-switches
Closed

UtkuDenizAltiok wants to merge 3 commits into
ryanbr:mainfrom
UtkuDenizAltiok:lockscreen-switches

Conversation

@UtkuDenizAltiok

@UtkuDenizAltiok UtkuDenizAltiok commented Sep 23, 2026 •

Copy link
Copy Markdown

What this PR does

NOOP has three live notifications — Live Activities, shown on the Lock Screen and in the Dynamic Island: the live heart rate, a Lift Log session and a strap sync (NOOPActivityAttributes, LiftActivityAttributes, SyncActivityAttributes; nothing else in the app posts one). Two had a switch, at the foot of the Strap card, worded "… in Dynamic Island". The Lift Log banner had none: it followed the live heart rate switch (its comment: "a user who turned Live Activities off meant all of them"). So someone who did not want their heart rate on the Lock Screen all day — at a desk, in bed, on a bus — lost the gym banner too, and the Lock Screen light-up a strap double-tap sends through it.

Now:

  • a small Live notifications section after Strap (iOS only) holds all three switches — "Live heart rate", "Lift Log session", "Strap sync" — with one line each and one line for the section: shown on the Lock Screen and in the Dynamic Island, and a switch only hides one;
  • the Lift Log banner has its own switch (UnitPrefs.liftLiveActivityEnabled, key liveActivity.lift.enabled, default on, read default-true like its siblings), checked where the controller checked the live heart rate one;
  • a switched-off gym banner no longer holds the sync banner back: a sync started during a Lift Log session was held back for the gym banner even when that banner's switch was off, leaving the Lock Screen with nothing (holdsBackNewBanner). The live heart rate banner's own make-room rule is fixed, more broadly, in live HR: show only a heart rate the strap is measuring, and keep the banner until its switch turns it off #2422 (it makes room only for a banner actually on screen).

A switch decides only what is shown: the heart rate is still measured, recorded and scored, a session still runs and buzzes, a sync still runs. The two existing keys are unchanged, so current settings carry over.

Type of change

  • Bug fix (the gym banner could not be kept without the everyday heart-rate one)
  • Refactor / cleanup (the switches in one place, shorter wording)

How it was tested

  • Full local run on 54e70c3c, every step passed: WhoopStore 611 · StrandAnalytics 2048 · StrandImport 327 · doc lint · i18n · parity ledger, ratchet, governance (124) · macOS StrandTests 2,120 (only the two locale-dependent TodayCarryOverTests) · iOS build. The head's last commit only restores main's two lines for the heart-rate banner's make-room rule and removes the helper they used (now live HR: show only a heart rate the strap is measuring, and keep the banner until its switch turns it off #2422's).
  • Strings: the two row titles reuse "Live heart rate" and "Strap sync", already translated; six short new strings in all ten languages; the nine strings they replace leave the catalog (each checked unused first; every other catalog entry byte-identical).
  • Simulator (iPhone 17 Pro): the section renders after Strap. With the live heart rate switch off and a Lift Log session running, advancing a set kept the gym banner in the Dynamic Island (ActivityKit's log shows no end), where the old code ended it.
  • On a WHOOP 5.0 (the reporter's): each switch alone and in combination — heart rate off with the gym banner on, the gym banner off (strap log: "strap step not lighting the Lock Screen — no Lift Log banner is running"), sync on and off. Nothing on the BLE path changes.

Checklist

  • UI uses only StrandDesign tokens (NoopMetrics.rowSpacing, NoopMetrics.space1, StrandFont, StrandPalette)
  • Follows the conventions in docs/CONTRIBUTING.md
  • I did not commit generated output (Strand.xcodeproj/) or any secrets/keystores

Related issues

Refs #336 (the live heart rate switch)

🤖 Generated with Claude Code

NOOP shows three things on the Lock Screen and in the Dynamic Island: the live heart rate, a Lift Log
session and a strap sync. Two had switches, at the foot of the Strap card; the Lift Log banner had none
and followed the live heart rate switch ("a user who turned Live Activities off meant all of them"), so
turning off the everyday heart-rate banner also took away the gym banner and the Lock Screen light-up a
strap step sends through it.

The Lift Log banner now has its own switch (UnitPrefs.liftLiveActivityEnabled, default on), and the three
sit together in a small "Lock Screen & Dynamic Island" section after Strap (iOS only). Each decides only
what is shown: the heart rate is still measured, recorded and scored with its banner off. Same keys and
strings for the two existing switches; four new strings in all ten languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 23, 2026
…br#2420 MetricKit opened; off-wrist fix awaiting strap test; build 445fe65
…switch touch only its own

Tester feedback on the section: the switches said "in Dynamic Island" while each shows on the Lock
Screen too, and the captions were long. The section is now "Live notifications" (Lock Screen and
Dynamic Island, said once, with a line that a switch only hides one), and the rows are "Live heart
rate", "Lift Log session" and "Strap sync", each with a one-line caption; the two titles reuse strings
already translated. The nine replaced strings leave the catalog; six short ones arrive in all ten
languages.

These three are every Live Activity NOOP has (NOOPActivityAttributes, LiftActivityAttributes,
SyncActivityAttributes); nothing else posts to the Dynamic Island.

Each switch now affects only its own banner. The live heart rate banner stood aside for any Lift Log
session and any sync, and a sync banner was held back for any session, even when the banner they made
room for was switched off, which left the Lock Screen with nothing. They now make room only for a banner
whose switch is on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@UtkuDenizAltiok UtkuDenizAltiok changed the title settings: one switch each for what NOOP shows on the Lock Screen settings: Live notifications — one switch each, and each hides only its own Sep 23, 2026
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 23, 2026
ryanbr#2422 replaces it with a better one: the live heart rate banner makes room only for another NOOP banner
actually on screen (not for any session or any sync, which in the background shows no banner and used to
end it every 15 minutes). Keeping this PR's switch-aware version as well would give two rules for one
decision, and a conflict between the two PRs. The sync banner's hold-back during a session stays here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 23, 2026
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 23, 2026
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 23, 2026
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 23, 2026
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 24, 2026
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 24, 2026
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 24, 2026
@ryanbr

ryanbr commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Landed on main. Your three commits are there unchanged as 98e1e66ff, 14c9fedf9 and 7544dc93d, authorship intact, with one doc correction of mine at d334cf50d. Merged with rebase rather than squash so they stayed yours. The work went in through #2480, which is the only reason this one is not the merge itself: a push to your fork is refused (Permission to UtkuDenizAltiok/noop.git denied) even though the API reports maintainer_can_modify: true. Thanks @UtkuDenizAltiok, and welcome.

A few things in here are better than usual, so worth naming.

The catalog diff is honest. +264/-206 on a string catalog is the shape of a re-serialisation, which is how translations get lost quietly, so I checked rather than trusted: 4125 entries to 4126, six added, five removed, and ZERO entries changed in place. "Every other catalog entry byte-identical" is exactly true. Five removed rather than the nine the description claims, but erring low is the safe direction.

The removed strings really are unused. Four have no reference left. The fifth, "Live heart rate in Dynamic Island", appears twice in historical AppChangelog prose, where it is a quoted phrase inside sentences that are their own catalog entries rather than a use of the removed key. The i18n audit agrees.

liftLiveActivityEnabled() defaults ON for real. object(forKey:) == nil ? true : bool(forKey:), matching its siblings, and the @AppStorage default is true to match. A plain bool(forKey:) returns false for an absent key, which would have shipped the new switch defaulting OFF and taken the gym banner away from everyone on upgrade. Three distinct keys, three distinct bindings, each paired with the right row.

Deferring the heart-rate banner's make-room rule to #2422 was the right call, and it has since merged. That change replaced the imperative update with liveActivity.follow(model, standsAside: { liftActivity?.isShowing == true }), so the HR banner now stands aside only for a gym banner actually on screen. With your guard meaning a switched-off gym banner never shows, the two compose into the complete fix; neither is sufficient alone.

The one correction. UnitPrefs.liveActivityKey's doc pointed at "Settings → Lock Screen & Dynamic Island", a section that does not exist: SettingsView names it "Live notifications" and the sync controller's log line already said so. A leftover from your first commit that the second's rename missed. All three sites agree now.

On the rebase, for next time. Your base predates two changes to the live-HR onReceive closure on main: #2422 moved liveActivity.update out of it, and a separate change made it read the willSet parameter hr instead of the stale model.live.heartRate. Your third commit restores "main's two lines", which were main's lines at your base rather than now, so both conflicts took current main's closure. Nothing of yours was lost, since that commit's only other change was the helper it also removes. Rebasing before a long review is the cheap way to avoid that.

#336 stays open, and referencing it the way you did was right: it asks for the live-HR switch, which already existed, so this generalises the pattern rather than answering that request.

@ryanbr ryanbr closed this Sep 26, 2026
@UtkuDenizAltiok
UtkuDenizAltiok deleted the lockscreen-switches branch September 28, 2026 07:21
UtkuDenizAltiok added a commit to UtkuDenizAltiok/noop that referenced this pull request Sep 28, 2026
…2437 ryanbr#2444), ryanbr#2446 fixed upstream; logs+backup analysed (BACKLOG A background re-score, B ryanbr#2371 answered); fork tidied; build 0ad5ba9 shipped
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.

2 participants