feat: add Compose setting to disable Health Connect workout suggestions

Adds a "Suggest workouts to share" toggle under Compose Settings (defaults on,
preserving current behavior) wired through UiSettings / UiSettingsFlow /
UiSharedPreferences. When set to NEVER, the Workouts screen no longer scans
Health Connect or shows the connect/suggestion banner.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015qgqQKHSewRHVM8vSCLt9P
This commit is contained in:
Claude
2026-06-16 22:33:05 +00:00
parent 6de43dec2d
commit 1c5c6d8a6b
6 changed files with 28 additions and 0 deletions
@@ -53,6 +53,7 @@ data class UiSettings(
val showProfileZapReceivedFeed: Boolean = true,
val showProfileFollowersFeed: Boolean = true,
val dontShowOnchainPublicWarning: Boolean = false,
val suggestWorkoutsFromHealthConnect: BooleanType = BooleanType.ALWAYS,
)
enum class ThemeType(
@@ -53,6 +53,7 @@ class UiSettingsFlow(
val showProfileZapReceivedFeed: MutableStateFlow<Boolean> = MutableStateFlow(true),
val showProfileFollowersFeed: MutableStateFlow<Boolean> = MutableStateFlow(true),
val dontShowOnchainPublicWarning: MutableStateFlow<Boolean> = MutableStateFlow(false),
val suggestWorkoutsFromHealthConnect: MutableStateFlow<BooleanType> = MutableStateFlow(BooleanType.ALWAYS),
) {
val listOfFlows: List<Flow<Any?>> =
listOf<Flow<Any?>>(
@@ -80,6 +81,7 @@ class UiSettingsFlow(
showProfileZapReceivedFeed,
showProfileFollowersFeed,
dontShowOnchainPublicWarning,
suggestWorkoutsFromHealthConnect,
)
// emits at every change in any of the propertyes.
@@ -111,6 +113,7 @@ class UiSettingsFlow(
flows[21] as Boolean,
flows[22] as Boolean,
flows[23] as Boolean,
flows[24] as BooleanType,
)
}
@@ -140,6 +143,7 @@ class UiSettingsFlow(
showProfileZapReceivedFeed.value,
showProfileFollowersFeed.value,
dontShowOnchainPublicWarning.value,
suggestWorkoutsFromHealthConnect.value,
)
fun update(torSettings: UiSettings): Boolean {
@@ -241,6 +245,10 @@ class UiSettingsFlow(
dontShowOnchainPublicWarning.tryEmit(torSettings.dontShowOnchainPublicWarning)
any = true
}
if (suggestWorkoutsFromHealthConnect.value != torSettings.suggestWorkoutsFromHealthConnect) {
suggestWorkoutsFromHealthConnect.tryEmit(torSettings.suggestWorkoutsFromHealthConnect)
any = true
}
return any
}
@@ -290,6 +298,7 @@ class UiSettingsFlow(
MutableStateFlow(uiSettings.showProfileZapReceivedFeed),
MutableStateFlow(uiSettings.showProfileFollowersFeed),
MutableStateFlow(uiSettings.dontShowOnchainPublicWarning),
MutableStateFlow(uiSettings.suggestWorkoutsFromHealthConnect),
)
}
}
@@ -117,6 +117,7 @@ class UiSharedPreferences(
val UI_SHOW_PROFILE_ZAP_RECEIVED_FEED = booleanPreferencesKey("ui.show_profile_zap_received_feed")
val UI_SHOW_PROFILE_FOLLOWERS_FEED = booleanPreferencesKey("ui.show_profile_followers_feed")
val UI_DONT_SHOW_ONCHAIN_PUBLIC_WARNING = booleanPreferencesKey("ui.dont_show_onchain_public_warning")
val UI_SUGGEST_WORKOUTS_FROM_HEALTH_CONNECT = stringPreferencesKey("ui.suggest_workouts_from_health_connect")
suspend fun uiPreferences(context: Context): UiSettings? =
try {
@@ -152,6 +153,8 @@ class UiSharedPreferences(
showProfileZapReceivedFeed = preferences[UI_SHOW_PROFILE_ZAP_RECEIVED_FEED] ?: true,
showProfileFollowersFeed = preferences[UI_SHOW_PROFILE_FOLLOWERS_FEED] ?: true,
dontShowOnchainPublicWarning = preferences[UI_DONT_SHOW_ONCHAIN_PUBLIC_WARNING] ?: false,
suggestWorkoutsFromHealthConnect =
preferences[UI_SUGGEST_WORKOUTS_FROM_HEALTH_CONNECT]?.let { BooleanType.valueOf(it) } ?: BooleanType.ALWAYS,
)
} catch (e: Exception) {
if (e is CancellationException) throw e
@@ -200,6 +203,7 @@ class UiSharedPreferences(
preferences[UI_SHOW_PROFILE_ZAP_RECEIVED_FEED] = sharedSettings.showProfileZapReceivedFeed
preferences[UI_SHOW_PROFILE_FOLLOWERS_FEED] = sharedSettings.showProfileFollowersFeed
preferences[UI_DONT_SHOW_ONCHAIN_PUBLIC_WARNING] = sharedSettings.dontShowOnchainPublicWarning
preferences[UI_SUGGEST_WORKOUTS_FROM_HEALTH_CONNECT] = sharedSettings.suggestWorkoutsFromHealthConnect.name
}
} catch (e: Exception) {
if (e is CancellationException) throw e
@@ -101,6 +101,13 @@ fun ComposeSettingsContent(
description = R.string.tracked_broadcasts_setting_description,
)
SettingsDivider()
BooleanSwitchTile(
flow = sharedPrefs.suggestWorkoutsFromHealthConnect,
icon = MaterialSymbols.DirectionsRun,
title = R.string.suggest_workouts_setting_title,
description = R.string.suggest_workouts_setting_description,
)
SettingsDivider()
AddClientTagTile(accountViewModel)
}
}
@@ -50,6 +50,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.model.BooleanType
import com.vitorpamplona.amethyst.service.workouts.health.DetectedWorkout
import com.vitorpamplona.amethyst.service.workouts.health.HealthConnectManager
import com.vitorpamplona.amethyst.service.workouts.health.HealthConnectStore
@@ -77,6 +78,10 @@ fun WorkoutSuggestions(
val available = remember { HealthConnectManager.isAvailable(context) }
if (!available) return
val suggestEnabled by accountViewModel.settings.uiSettingsFlow.suggestWorkoutsFromHealthConnect
.collectAsStateWithLifecycle()
if (suggestEnabled == BooleanType.NEVER) return
val pubkeyHex = accountViewModel.account.signer.pubKey
val state =
remember(pubkeyHex) {
+2
View File
@@ -3481,6 +3481,8 @@
<string name="ai_writing_setting_description">Uses an on-device AI model to propose text corrections and tone changes.</string>
<string name="tracked_broadcasts_setting_title">Tracked broadcasts</string>
<string name="tracked_broadcasts_setting_description">Use the tracked broadcaster when sending events. Shows live progress and per-relay status while broadcasting.</string>
<string name="suggest_workouts_setting_title">Suggest workouts to share</string>
<string name="suggest_workouts_setting_description">Reads finished workouts from Health Connect (Samsung Health, Google Fit, Fitbit, Garmin…) and suggests sharing them as a post. Permission is requested only when you connect.</string>
<string name="compose_settings">Compose Settings</string>
<string name="auto_create_drafts_setting_title">Automatically create drafts</string>
<string name="auto_create_drafts_setting_description">Saves a draft event automatically when you type or leave a composer with unsent text and sends to your private outbox relays.</string>