Repository navigation
Description
Follow-up to #931, which adds a third motion signal on the Apple side only. Filed because #931's description originally claimed this Kotlin pref already existed — it does not, and that wording is corrected there.
The asymmetry
After #931 lands, the two gates read differently:
| signals | |
|---|---|
Apple — NoopMotionState.poseStill (Packages/StrandDesign/Sources/StrandDesign/NoopMotion.swift:140) |
system Reduce Motion ‖ Low Power Mode ‖ in-app "Reduce motion in NOOP" |
Android — rememberPoseStill() (android/app/src/main/java/com/noop/ui/NoopMotion.kt:149) |
system Reduce Motion ‖ battery saver |
fun rememberPoseStill(): Boolean = rememberReduceMotion() || rememberPowerSaveMode()The first two signals reached parity in #909 / #911. The third — an in-app toggle, default OFF — is the one that is Apple-only, and it is the signal the user who asked for this actually wanted: a way to quiet the app without putting the whole phone into battery saver.
What the Android side needs
- A pref.
NoopPrefs(android/app/src/main/java/com/noop/ui/MainActivity.kt:163) stores keys asKEY_*constants, so this should beconst val KEY_QUIET_MOTION = "noop.quietMotion"— note the key string is the cross-platform contract and must match the Apple@AppStoragekeynoop.quietMotionexactly, so a.noopbakround-trip carries the setting across platforms. (Worth saying plainly: the correct Kotlin spelling isNoopPrefs.KEY_QUIET_MOTION, notNoopPrefs.quietMotion— the latter is the name Make Low Power Mode mean "stop everything decorative", and stop the tilt sensor (#909) #931 wrongly claimed already existed, and it does not match this file's convention either.) - A third term in the gate, read live rather than once — the Apple side uses
UserDefaults.didChangeNotificationso flipping the toggle poses the surfaces without leaving the screen; Android needs theSharedPreferencesequivalent, for the same reasonACTION_POWER_SAVE_MODE_CHANGEDis already observed. - A Settings toggle, default OFF, under the Appearance section, with the string translated into the catalog locales.
- Update
PoseStillCoverageTest.android/app/src/test/java/com/noop/ui/PoseStillCoverageTest.kt:112currently pins the exact two-signal source line:That assertion will fail the moment the third signal is added, which is the test working correctly — it is a census of the gate's shape, and the shape is changing. The Apple twin (code.contains("fun rememberPoseStill(): Boolean = rememberReduceMotion() || rememberPowerSaveMode()")QuietMotionCoverageTests.testGateReadsAllThreeSignalsAndStaysLive) is the model for what it should assert afterwards: that all three signals are OR-ed and that each stays live, because losing one signal is invisible in the app — the screen looks right in whichever mode still works.
Not in scope here
The LiquidMotion half of #931 (stopping the decorative 60 Hz CMMotionManager feed at the app boundary) has no Android twin to fix: there is no equivalent decorative sensor loop on that side. This issue is only the third gate signal and its toggle.
Activity
settings(android): in-app Reduce Motion control (quiet motion) — pari…
settings(android): in-app Reduce Motion control (quiet motion) — pari…