Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 0 additions & 100 deletions Tools/i18n_audit_baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -472,50 +472,6 @@
"android/app/src/main/java/com/noop/ui/PipBar.kt",
"$label: $valueText $unit"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Auto · ${profile.hrMaxAuto} bpm (Tanaka)"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Background image"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Blood Oxygen: strap estimate"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Browse files"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Change photo"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Choose from Photos"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Choose photo"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Fill"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Fit"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Let the background show through every card. Tune how much just below."
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Manual override"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Needs the full encrypted bond: close the official WHOOP app and pair the strap to NOOP first (a live-HR-only link can't carry the unlock)."
Expand All @@ -524,62 +480,6 @@
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Put the strap on first. The deep stream is on-wrist only."
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Re-scan"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Recent"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Remove image"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Replace from Photos"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Scaling"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Scores today's hour-by-hour stress timeline against YOUR own cross-day baseline "
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Searching…"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Show custom background"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Sleep chart"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Stress: personal daytime baseline"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Stretch"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Surfaces your strap's nightly SpO₂ estimate in the Blood Oxygen tile when no "
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Tile"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Transparent cards"
],
[
"android/app/src/main/java/com/noop/ui/SettingsScreen.kt",
"Wear the strap, tap once, then let it sync and share your strap log."
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/main/java/com/noop/ui/DataSourcesScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,7 @@ fun DataSourcesScreen(vm: AppViewModel) {
subtitle = uiString(R.string.data_sources_whoop_live_subtitle),
) {
val (label, tone) = when {
// encryptedBond, not bonded — see strapStatusTitle. A 5/MG streaming over the open
// encryptedBond, not bonded — see strapStatusTitleRes. A 5/MG streaming over the open
// profile has bonded == true with no pairing at all, and after #1635 hello suppression it
// stays there for good rather than passing through.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ internal fun SettingsCard(
NoopCard(padding = 20.dp, tint = Palette.accent) {
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
Overline("Settings")
Overline(uiString(R.string.nav_settings))
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(10.dp),
Expand Down
48 changes: 28 additions & 20 deletions android/app/src/main/java/com/noop/ui/SettingsLogic.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.noop.ui

import android.content.SharedPreferences
import androidx.annotation.StringRes
import com.noop.R
import kotlin.math.roundToInt

// MARK: - Waist stepper (optional VO₂max input)
Expand Down Expand Up @@ -40,39 +42,45 @@ internal fun waistInchesStep(current: Double, up: Boolean): Double {
* It is not cosmetic. The encrypted bond gates buzz, alarms, double-tap and history sync, and Settings
* already says so a few rows further down ("Needs the full encrypted bond…"). A green "Bonded · streaming"
* above that contradicts it on the same screen.
*
* Returns a string resource rather than text so the branch stays testable in a plain JVM test, where
* [uiString] has no Application to resolve through.
*/
internal fun strapStatusTitle(encryptedBond: Boolean, bonded: Boolean, connected: Boolean): String = when {
encryptedBond && connected -> "Bonded · streaming"
encryptedBond -> "Bonded · idle"
bonded && connected -> "Live HR (not fully paired)"
connected -> "Connected"
@StringRes
internal fun strapStatusTitleRes(encryptedBond: Boolean, bonded: Boolean, connected: Boolean): Int = when {
encryptedBond && connected -> R.string.onboarding_state_bonded_streaming
encryptedBond -> R.string.l10n_settings_logic_bonded_idle_1930284f
bonded && connected -> R.string.l10n_settings_logic_live_hr_not_fully_paired_6fd6ddb1
connected -> R.string.recording_chip_title_connected
// No `bonded`-only idle arm: without an encrypted bond there was never a pairing to be idle from,
// and labelling that "Paired" would be the same overclaim this change exists to remove. The 5/MG
// shortcut's `bonded` is cleared on disconnect anyway, so the honest answer here is Disconnected.
else -> "Disconnected"
else -> R.string.l10n_settings_logic_disconnected_771e05f2
}

/** Positive ONLY for a real encrypted bond on a live link — see [strapStatusTitle]. A live-HR-only link
/** Positive ONLY for a real encrypted bond on a live link — see [strapStatusTitleRes]. A live-HR-only link
* is a warning, not a success: it works, but the pairing-gated features do not. */
internal fun strapTone(encryptedBond: Boolean, bonded: Boolean, connected: Boolean): StrandTone = when {
encryptedBond && connected -> StrandTone.Positive
connected || bonded -> StrandTone.Warning
else -> StrandTone.Critical
}

// `internal` (not private) so the unit test in the same package can assert the scanning branch.
internal fun strapStatusDetail(
// `internal` (not private) so the unit test in the same package can assert the scanning branch. A string
// resource for the same reason as [strapStatusTitleRes].
@StringRes
internal fun strapStatusDetailRes(
encryptedBond: Boolean,
bonded: Boolean,
connected: Boolean,
scanning: Boolean,
): String = when {
scanning -> "Searching for your WHOOP… make sure it's charged, on your wrist, and the official WHOOP app isn't connected to it."
encryptedBond && connected -> "Your strap is paired and sending data. Open Live for a real-time heart rate."
bonded && connected -> "Live heart rate is streaming, but your strap is not fully paired. The encrypted pairing is what carries motion, skin temperature, SpO₂ and respiratory rate — without it, sleep is staged from heart rate alone. Buzz, alarms and history sync need it too."
connected -> "Connected. Finishing the secure pairing handshake…"
bonded -> "Previously paired but not currently connected. Re-scan to reconnect."
else -> "No strap connected. Put your WHOOP nearby and tap Re-scan to pair."
): Int = when {
scanning -> R.string.l10n_settings_logic_searching_for_your_whoop_make_sure_7be37c50
encryptedBond && connected -> R.string.l10n_settings_logic_your_strap_is_paired_and_sending_ef06dfd4
bonded && connected -> R.string.l10n_settings_logic_live_heart_rate_is_streaming_but_934807fc
connected -> R.string.l10n_settings_logic_connected_finishing_the_secure_pairing_handshake_1e56d362
bonded -> R.string.l10n_settings_logic_previously_paired_but_not_currently_connected_0a84a072
else -> R.string.l10n_settings_logic_no_strap_connected_put_your_whoop_61a155c1
}

internal fun batteryTone(pct: Double): StrandTone = when {
Expand All @@ -83,12 +91,12 @@ internal fun batteryTone(pct: Double): StrandTone = when {

// MARK: - Sex options

internal data class SexOption(val tag: String, val label: String)
internal data class SexOption(val tag: String, @StringRes val labelRes: Int)

internal val SEX_OPTIONS = listOf(
SexOption("male", "Male"),
SexOption("female", "Female"),
SexOption("nonbinary", "Non-binary"),
SexOption("male", R.string.onboarding_male),
SexOption("female", R.string.onboarding_female),
SexOption("nonbinary", R.string.l10n_settings_logic_non_binary_dc82a40c),
)

// MARK: - Advanced disclosure persistence (S3)
Expand Down
Loading
Loading