refactor: use LocalCache.observeNotes flow for open polls

Replace LocalCache.notes.forEach iteration with observeNotes using a
Filter for PollEvent.KIND and ZapPollEvent.KIND by the current user.
This makes the open polls list reactive — it updates automatically
when new polls arrive instead of only computing once on composition.

https://claude.ai/code/session_01LLLN5MDA5nJFYx38MVo81Q
This commit is contained in:
Claude
2026-03-20 21:38:48 +00:00
parent 638bad3672
commit b6e54db81b
@@ -24,74 +24,61 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
@Composable
fun openPollsState(accountViewModel: AccountViewModel) =
produceState(initialValue = emptyList<Note>(), accountViewModel) {
value =
withContext(Dispatchers.IO) {
findOpenPolls(accountViewModel)
}
}
remember(accountViewModel) {
val userPubkeyHex = accountViewModel.account.userProfile().pubkeyHex
private fun findOpenPolls(accountViewModel: AccountViewModel): List<Note> {
val userPubkeyHex = accountViewModel.account.userProfile().pubkeyHex
val filter =
Filter(
kinds = listOf(PollEvent.KIND, ZapPollEvent.KIND),
authors = listOf(userPubkeyHex),
)
accountViewModel.account.cache
.observeNotes(filter)
.map { notes -> filterOpenPolls(notes) }
.flowOn(Dispatchers.IO)
}.collectAsStateWithLifecycle(initialValue = emptyList())
private fun filterOpenPolls(notes: List<Note>): List<Note> {
val now = TimeUtils.now()
val oneDayInSeconds = TimeUtils.ONE_DAY
val openPolls = mutableListOf<Note>()
LocalCache.notes.forEach { _, note ->
val event = note.event ?: return@forEach
return notes.filter { note ->
val event = note.event ?: return@filter false
when (event) {
is PollEvent -> {
if (event.pubKey == userPubkeyHex) {
val endsAt = event.endsAt()
val isOpen =
if (endsAt != null) {
endsAt > now
} else {
event.createdAt + oneDayInSeconds > now
}
if (isOpen) {
openPolls.add(note)
}
}
val endsAt = event.endsAt()
if (endsAt != null) endsAt > now else event.createdAt + oneDayInSeconds > now
}
is ZapPollEvent -> {
if (event.pubKey == userPubkeyHex) {
val closedAt = event.closedAt()
val isOpen =
if (closedAt != null) {
closedAt > now
} else {
event.createdAt + oneDayInSeconds > now
}
if (isOpen) {
openPolls.add(note)
}
}
val closedAt = event.closedAt()
if (closedAt != null) closedAt > now else event.createdAt + oneDayInSeconds > now
}
}
}
return openPolls.sortedByDescending { it.createdAt() }
else -> false
}
}.sortedByDescending { it.createdAt() }
}
@Composable