fix(geocaches): observe the loaded feed's flow instead of reading .value

FeedState.Loaded is handed out once and then mutated through its inner
MutableStateFlow, so reading .value inside composition froze both
screens at whatever the feed held when they first composed:

- the map tab never grew a pin for a cache that streamed in afterwards
- a hunt's progress bar never moved when a new find was logged

Both now collect that inner flow, matching GalleryFeedLoaded. Caught by
Android Lint (StateFlowValueCalledInComposition), which the repo's
pre-commit hook does not run; verified with
:amethyst:lintFdroidBenchmark, which goes from 2 errors to 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WG7T9hAHDMKPaHsWvqySEr
This commit is contained in:
Claude
2026-09-21 14:21:04 +00:00
parent 8344a2dd48
commit d446839fa5
2 changed files with 36 additions and 15 deletions
@@ -39,13 +39,22 @@ fun rememberMyFoundCacheIds(accountViewModel: AccountViewModel): Set<String> {
val finds by accountViewModel.feedStates.geocacheFindsFeed.feedContent
.collectAsStateWithLifecycle()
val notes =
when (val state = finds) {
is FeedState.Loaded -> state.feed.value.list
else -> emptyList()
}
return remember(notes) {
notes.mapNotNullTo(mutableSetOf()) { (it.event as? GeocacheFoundLogEvent)?.geocacheId() }
return when (val state = finds) {
is FeedState.Loaded -> rememberFoundCacheIds(state)
else -> emptySet()
}
}
/**
* Collects the loaded feed's own flow. [FeedState.Loaded] is handed out once and then mutated
* through its inner flow, so reading `.value` here would freeze the set at whatever the feed held
* when the hunt screen first composed — the progress bar would never move.
*/
@Composable
private fun rememberFoundCacheIds(state: FeedState.Loaded): Set<String> {
val loaded by state.feed.collectAsStateWithLifecycle()
return remember(loaded) {
loaded.list.mapNotNullTo(mutableSetOf()) { (it.event as? GeocacheFoundLogEvent)?.geocacheId() }
}
}
@@ -111,13 +111,7 @@ fun GeocacheMapTab(
val feedState by feedContentState.feedContent.collectAsStateWithLifecycle()
val found = rememberMyFoundCacheIds(accountViewModel)
val listings =
when (val state = feedState) {
is FeedState.Loaded ->
state.feed.value.list
.mapNotNull { it.event as? GeocacheListingEvent }
else -> emptyList()
}
val listings = rememberGeocacheListings(feedState)
var peek by remember { mutableStateOf<GeocacheListingEvent?>(null) }
@@ -368,3 +362,21 @@ private fun markerFor(
}
}
}
/**
* Collects the loaded feed's own flow. [FeedState.Loaded] is handed out once and then mutated
* through its inner flow, so reading `.value` here would pin the map to whatever had arrived when
* the tab first composed — caches streaming in from relays would never get a pin.
*/
@Composable
private fun rememberGeocacheListings(feedState: FeedState): List<GeocacheListingEvent> =
when (feedState) {
is FeedState.Loaded -> {
val loaded by feedState.feed.collectAsStateWithLifecycle()
remember(loaded) {
loaded.list.mapNotNull { it.event as? GeocacheListingEvent }
}
}
else -> emptyList()
}