Settings: units, wheel circumference, HR alerts, auto-pause, vibration (#44) #91
No reviewers
Labels
No labels
area:companion
area:docs
area:shared
area:tooling
area:watchapp
blocker
kind:chore
kind:feature
kind:spike
kind:test
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
robert/PedalPebble!91
Loading…
Reference in a new issue
No description provided.
Delete branch "area/settings-screen"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #44.
What this does
The phone-side settings screen, scoped per the issue's two 2026-09 update comments:
Layout
companion/core/.../settings/RideSettings.kt+SettingsRepository.kt(pure JVM,:companion:core): the domain model (UnitSystem,WheelCircumference/WheelCircumferencePreset,HrZoneBoundaries,HrSettings,VibrationIntensity,RideSettings) and validated setters, over aSettingsStorageinterface — the sameRouteLibrary/RouteRecordStoragesplit #25 established.SettingsRepositoryTestcovers it: 16 Kotest cases, all green.:companion:settingsmodule (Android):SharedPreferencesSettingsStorage(adapter, same reasoning asSharedPreferencesActiveRoutePointerStoragefrom #25 — every setting is a scalar or small fixed tuple, no querying need, so no Room/KSP here),SettingsStore(wiring singleton, same shape asRouteStore),SettingsScreen/SettingsActivity(Compose, same shape asRouteLibraryScreen/RouteLibraryActivity).Why a new module rather than folding into
:companion:routeor the app module: settings are not a route concern (bundling them into:companion:routewould make that module's name misleading), and:companionis explicitly meant to stay thin composition-root wiring per its ownbuild.gradle.ktsKDoc — logic belongs in the module that owns it.MainActivitygets a second button (Settings, alongside the existingRoutesone) into the new activity, same-app explicitIntent, no package-visibility concern (D36 is a PebbleKit-only concern).Wheel circumference presets
Three common road sizes on the 622 mm (ETRTO/"700C") bead-seat diameter: 700x25c (2105 mm), 700x28c (2136 mm), 700x32c (2155 mm). These are the standard cyclocomputer wheel-size-table figures, checked live against https://sport-calculator.com/calculators/cycling/bicycle-tire-size-chart and the ETRTO tyre-size chart (2026-09-04) rather than recalled from memory.
WheelCircumference.Manualtakes an exact mm value for riders who measure their own rollout.What has a consumer today, and what does not
Nothing on the watch side has a consumer yet — that's the headline finding, not a per-setting exception:
unitSystem—UNITS(wire id 3) already has a defined shape indocs/PROTOCOL.md§2.1 (0 = metric, 1 = imperial), but no AppMessage send path exists anywhere in this codebase before Spike A (#4) —PebbleTransportin:companion:pebbleis still an empty placeholder interface.fields.con the watch is hardcoded to metric strings (km/h,km) regardless of this setting.wheelCircumference,hr.zoneBoundaries/hr.alertsEnabled,autoPauseEnabled,vibrationIntensity,autoSwitchToNavView,voiceAnnouncementsEnabled— no wire key exists at all.docs/PROTOCOL.md§2.6 (Configuration) defines onlyCONFIG_PAGES/CONFIG_SEQ(page layout, #61). Per D48 this PR does not invent a wire format for these; that's a call for whichever future issue actually needs the push to happen.HR_SAMPLES, which nothing turns into an alert).SettingsRepositoryenforces "alerts cannot be enabled while zones are unconfigured" as its own invariant, independent of delivery existing.ride_link.c's vibration calls (#11/PR #84) are hardcoded; nothing readsvibrationIntensityyet.autoSwitchToNavViewyet.voiceAnnouncementsEnabledfeeds the not-yet-built Phase 3 announcer (FR-N19, D45).So: "settings persisted and pushed to the watch on connect" from the issue's acceptance criteria is only half built here, honestly — persistence is real and tested, the push is scoped out because the transport to push over does not exist yet for any key, not just these.
Verification
./gradlew :companion:core:test— green, 16/16 (--no-configuration-cache; this sandbox only has JDK 25, no JDK 17 toolchain for Gradle's configuration-cache serialization step, unrelated to the actual test run)../gradlew projects— confirms:companion:settingsregisters and the whole build's Gradle configuration resolves cleanly.:companion:settings(Compose UI, manifest, MainActivity wiring) is hand-reviewed only, not compiled — no Android SDK in this sandbox (ANDROID_HOME/local.propertiesunset), the same constraint every companion PR has hit tonight../gradlew :companion:settings:compileDebugKotlinfails at the SDK-location check, not at any Kotlin/Gradle syntax problem.No new Gradle dependency was needed —
SharedPreferences, Compose and coroutines were already in the version catalog for:companion:route.5c1037d9445b0922790e