Merge pull request #2124 from vitorpamplona/claude/dismiss-poll-notifications-AEVw5

Add ability to dismiss poll notifications
This commit is contained in:
Vitor Pamplona
2026-04-03 18:19:13 -04:00
committed by GitHub
6 changed files with 48 additions and 5 deletions
@@ -130,6 +130,7 @@ private object PrefKeys {
const val LOGIN_WITH_EXTERNAL_SIGNER = "login_with_external_signer" const val LOGIN_WITH_EXTERNAL_SIGNER = "login_with_external_signer"
const val SIGNER_PACKAGE_NAME = "signer_package_name" const val SIGNER_PACKAGE_NAME = "signer_package_name"
const val HAS_DONATED_IN_VERSION = "has_donated_in_version" const val HAS_DONATED_IN_VERSION = "has_donated_in_version"
const val DISMISSED_POLL_NOTE_IDS = "dismissed_poll_note_ids"
const val PENDING_ATTESTATIONS = "pending_attestations" const val PENDING_ATTESTATIONS = "pending_attestations"
const val ALL_ACCOUNT_INFO = "all_saved_accounts_info" const val ALL_ACCOUNT_INFO = "all_saved_accounts_info"
@@ -389,6 +390,7 @@ object LocalPreferences {
JsonMapper.toJson(regularMap), JsonMapper.toJson(regularMap),
) )
putStringSet(PrefKeys.HAS_DONATED_IN_VERSION, settings.hasDonatedInVersion.value) putStringSet(PrefKeys.HAS_DONATED_IN_VERSION, settings.hasDonatedInVersion.value)
putStringSet(PrefKeys.DISMISSED_POLL_NOTE_IDS, settings.dismissedPollNoteIds.value)
putString( putString(
PrefKeys.PENDING_ATTESTATIONS, PrefKeys.PENDING_ATTESTATIONS,
@@ -473,6 +475,7 @@ object LocalPreferences {
val hideBlockAlertDialog = getBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, false) val hideBlockAlertDialog = getBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, false)
val hideNIP17WarningDialog = getBoolean(PrefKeys.HIDE_NIP_17_WARNING_DIALOG, false) val hideNIP17WarningDialog = getBoolean(PrefKeys.HIDE_NIP_17_WARNING_DIALOG, false)
val hasDonatedInVersion = getStringSet(PrefKeys.HAS_DONATED_IN_VERSION, null) ?: setOf() val hasDonatedInVersion = getStringSet(PrefKeys.HAS_DONATED_IN_VERSION, null) ?: setOf()
val dismissedPollNoteIds = getStringSet(PrefKeys.DISMISSED_POLL_NOTE_IDS, null) ?: setOf()
val localRelayServers = getStringSet(PrefKeys.LOCAL_RELAY_SERVERS, null) ?: setOf() val localRelayServers = getStringSet(PrefKeys.LOCAL_RELAY_SERVERS, null) ?: setOf()
val defaultHomeFollowListStr = getString(PrefKeys.DEFAULT_HOME_FOLLOW_LIST, null) val defaultHomeFollowListStr = getString(PrefKeys.DEFAULT_HOME_FOLLOW_LIST, null)
@@ -594,6 +597,7 @@ object LocalPreferences {
backupTrustProviderList = latestTrustProviderList.await(), backupTrustProviderList = latestTrustProviderList.await(),
lastReadPerRoute = MutableStateFlow(lastReadPerRoute.await()), lastReadPerRoute = MutableStateFlow(lastReadPerRoute.await()),
hasDonatedInVersion = MutableStateFlow(hasDonatedInVersion), hasDonatedInVersion = MutableStateFlow(hasDonatedInVersion),
dismissedPollNoteIds = MutableStateFlow(dismissedPollNoteIds),
pendingAttestations = MutableStateFlow(pendingAttestations.await()), pendingAttestations = MutableStateFlow(pendingAttestations.await()),
backupNipA3PaymentTargets = latestPaymentTargets.await(), backupNipA3PaymentTargets = latestPaymentTargets.await(),
) )
@@ -2150,6 +2150,8 @@ class Account(
fun markDonatedInThisVersion() = settings.markDonatedInThisVersion(BuildConfig.VERSION_NAME) fun markDonatedInThisVersion() = settings.markDonatedInThisVersion(BuildConfig.VERSION_NAME)
fun dismissPollNotification(noteId: String) = settings.dismissPollNotification(noteId)
init { init {
Log.d("AccountRegisterObservers", "Init") Log.d("AccountRegisterObservers", "Init")
@@ -193,6 +193,7 @@ class AccountSettings(
var backupTrustProviderList: TrustProviderListEvent? = null, var backupTrustProviderList: TrustProviderListEvent? = null,
val lastReadPerRoute: MutableStateFlow<Map<String, MutableStateFlow<Long>>> = MutableStateFlow(mapOf()), val lastReadPerRoute: MutableStateFlow<Map<String, MutableStateFlow<Long>>> = MutableStateFlow(mapOf()),
val hasDonatedInVersion: MutableStateFlow<Set<String>> = MutableStateFlow(setOf()), val hasDonatedInVersion: MutableStateFlow<Set<String>> = MutableStateFlow(setOf()),
val dismissedPollNoteIds: MutableStateFlow<Set<String>> = MutableStateFlow(setOf()),
val pendingAttestations: MutableStateFlow<Map<HexKey, String>> = MutableStateFlow(mapOf()), val pendingAttestations: MutableStateFlow<Map<HexKey, String>> = MutableStateFlow(mapOf()),
var backupNipA3PaymentTargets: PaymentTargetsEvent? = null, var backupNipA3PaymentTargets: PaymentTargetsEvent? = null,
) : EphemeralChatRepository, ) : EphemeralChatRepository,
@@ -679,6 +680,21 @@ class AccountSettings(
return false return false
} }
// ---
// dismissed polls
// ---
fun isDismissedPoll(noteId: String) = dismissedPollNoteIds.value.contains(noteId)
fun dismissPollNotification(noteId: String) {
if (!dismissedPollNoteIds.value.contains(noteId)) {
dismissedPollNoteIds.update {
it + noteId
}
saveAccountSettings()
}
}
// ---- // ----
// last read flows // last read flows
// ---- // ----
@@ -1126,6 +1126,8 @@ class AccountViewModel(
fun markDonatedInThisVersion() = account.markDonatedInThisVersion() fun markDonatedInThisVersion() = account.markDonatedInThisVersion()
fun dismissPollNotification(noteId: String) = account.dismissPollNotification(noteId)
fun dontTranslateFrom() = account.settings.syncedSettings.languages.dontTranslateFrom.value fun dontTranslateFrom() = account.settings.syncedSettings.languages.dontTranslateFrom.value
fun translateTo() = account.settings.syncedSettings.languages.translateTo.value fun translateTo() = account.settings.syncedSettings.languages.translateTo.value
@@ -36,6 +36,7 @@ import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -59,6 +60,7 @@ import com.vitorpamplona.amethyst.ui.feeds.FeedError
import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.note.BadgeCompose import com.vitorpamplona.amethyst.ui.note.BadgeCompose
import com.vitorpamplona.amethyst.ui.note.CloseIcon
import com.vitorpamplona.amethyst.ui.note.MessageSetCompose import com.vitorpamplona.amethyst.ui.note.MessageSetCompose
import com.vitorpamplona.amethyst.ui.note.MultiSetCompose import com.vitorpamplona.amethyst.ui.note.MultiSetCompose
import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.NoteCompose
@@ -183,8 +185,20 @@ private fun FeedLoaded(
Row(modifier = Modifier.padding(start = Size10dp, end = Size10dp, bottom = Size10dp)) { Row(modifier = Modifier.padding(start = Size10dp, end = Size10dp, bottom = Size10dp)) {
Card( Card(
modifier = MaterialTheme.colorScheme.imageModifier, modifier = MaterialTheme.colorScheme.imageModifier,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) { ) {
OpenPollsSectionHeader() OpenPollsSectionHeader()
IconButton(
modifier = Modifier.padding(end = Size10dp),
onClick = { accountViewModel.dismissPollNotification(note.idHex) },
) {
CloseIcon()
}
}
Row(Modifier.fillMaxWidth().animateItem()) { Row(Modifier.fillMaxWidth().animateItem()) {
NoteCompose( NoteCompose(
baseNote = note, baseNote = note,
@@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
@@ -47,10 +48,14 @@ class OpenPollsState(
) )
val flow: StateFlow<List<Note>> = val flow: StateFlow<List<Note>> =
combine(
account.cache account.cache
.observeNotes(filter) .observeNotes(filter)
.map { notes -> filterOpenPolls(notes) } .map { notes -> filterOpenPolls(notes) },
.flowOn(Dispatchers.IO) account.settings.dismissedPollNoteIds,
) { polls, dismissed ->
polls.filter { it.idHex !in dismissed }
}.flowOn(Dispatchers.IO)
.stateIn( .stateIn(
scope, scope,
SharingStarted.Eagerly, SharingStarted.Eagerly,