From a9cb2f464bb94c41dd8c3b272c646d844bf3cbf4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 16 Jun 2026 23:29:12 +0000 Subject: [PATCH] fix: stop the connect card from flashing on every screen open hasPermission started false while the async permission check ran, so the "Share your workouts" connect card flashed for ~1s on every open before the check confirmed permission was already granted. Make permission a tri-state (null = not checked yet) and render nothing until it resolves, so the connect prompt only appears once we actually know permission is missing. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015qgqQKHSewRHVM8vSCLt9P --- .../loggedIn/workouts/suggestion/WorkoutSuggestionCard.kt | 8 ++++++-- .../workouts/suggestion/WorkoutSuggestionState.kt | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionCard.kt index 1253003edf..6e2c570ece 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionCard.kt @@ -125,7 +125,11 @@ fun WorkoutSuggestions( val hasPermission by state.hasPermission.collectAsStateWithLifecycle() var connectDismissed by rememberSaveable(pubkeyHex) { mutableStateOf(false) } - if (suggestions.isEmpty() && (hasPermission || connectDismissed)) return + // Not checked yet: render nothing so the connect prompt never flashes during the check. + val granted = hasPermission ?: return + val showConnect = !granted && !connectDismissed + + if (suggestions.isEmpty() && !showConnect) return Column( modifier = @@ -135,7 +139,7 @@ fun WorkoutSuggestions( .animateContentSize(), verticalArrangement = Arrangement.spacedBy(8.dp), ) { - if (!hasPermission && !connectDismissed) { + if (showConnect) { ConnectHealthCard( onConnect = { permissionLauncher.launch(HealthConnectManager.PERMISSIONS) }, onDismiss = { connectDismissed = true }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionState.kt index 70771b7293..3052f90347 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionState.kt @@ -53,7 +53,10 @@ class WorkoutSuggestionState( private val _suggestions = MutableStateFlow>(emptyList()) val suggestions = _suggestions.asStateFlow() - private val _hasPermission = MutableStateFlow(false) + // null = not checked yet. Kept distinct from false so the connect prompt is only shown + // once we actually know permission is missing, never during the async check (which would + // otherwise flash the prompt every time the screen opens for an already-granted user). + private val _hasPermission = MutableStateFlow(null) val hasPermission = _hasPermission.asStateFlow() suspend fun refresh() {