diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index a0a006ceb..59a852696 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -130,6 +130,7 @@ private object PrefKeys { const val LOGIN_WITH_EXTERNAL_SIGNER = "login_with_external_signer" const val SIGNER_PACKAGE_NAME = "signer_package_name" 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 ALL_ACCOUNT_INFO = "all_saved_accounts_info" @@ -389,6 +390,7 @@ object LocalPreferences { JsonMapper.toJson(regularMap), ) putStringSet(PrefKeys.HAS_DONATED_IN_VERSION, settings.hasDonatedInVersion.value) + putStringSet(PrefKeys.DISMISSED_POLL_NOTE_IDS, settings.dismissedPollNoteIds.value) putString( PrefKeys.PENDING_ATTESTATIONS, @@ -473,6 +475,7 @@ object LocalPreferences { val hideBlockAlertDialog = getBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, false) val hideNIP17WarningDialog = getBoolean(PrefKeys.HIDE_NIP_17_WARNING_DIALOG, false) 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 defaultHomeFollowListStr = getString(PrefKeys.DEFAULT_HOME_FOLLOW_LIST, null) @@ -594,6 +597,7 @@ object LocalPreferences { backupTrustProviderList = latestTrustProviderList.await(), lastReadPerRoute = MutableStateFlow(lastReadPerRoute.await()), hasDonatedInVersion = MutableStateFlow(hasDonatedInVersion), + dismissedPollNoteIds = MutableStateFlow(dismissedPollNoteIds), pendingAttestations = MutableStateFlow(pendingAttestations.await()), backupNipA3PaymentTargets = latestPaymentTargets.await(), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 79f1a2e9e..d05c96312 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -2150,6 +2150,8 @@ class Account( fun markDonatedInThisVersion() = settings.markDonatedInThisVersion(BuildConfig.VERSION_NAME) + fun dismissPollNotification(noteId: String) = settings.dismissPollNotification(noteId) + init { Log.d("AccountRegisterObservers", "Init") diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt index a600384ac..7946ee644 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt @@ -193,6 +193,7 @@ class AccountSettings( var backupTrustProviderList: TrustProviderListEvent? = null, val lastReadPerRoute: MutableStateFlow>> = MutableStateFlow(mapOf()), val hasDonatedInVersion: MutableStateFlow> = MutableStateFlow(setOf()), + val dismissedPollNoteIds: MutableStateFlow> = MutableStateFlow(setOf()), val pendingAttestations: MutableStateFlow> = MutableStateFlow(mapOf()), var backupNipA3PaymentTargets: PaymentTargetsEvent? = null, ) : EphemeralChatRepository, @@ -679,6 +680,21 @@ class AccountSettings( 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 // ---- diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 84889bb95..bf3ba6f9d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -1126,6 +1126,8 @@ class AccountViewModel( fun markDonatedInThisVersion() = account.markDonatedInThisVersion() + fun dismissPollNotification(noteId: String) = account.dismissPollNotification(noteId) + fun dontTranslateFrom() = account.settings.syncedSettings.languages.dontTranslateFrom.value fun translateTo() = account.settings.syncedSettings.languages.translateTo.value diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt index ff434728f..f4dba1193 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt @@ -36,6 +36,7 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.Card import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton 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.navigation.navs.INav 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.MultiSetCompose import com.vitorpamplona.amethyst.ui.note.NoteCompose @@ -184,7 +186,19 @@ private fun FeedLoaded( Card( modifier = MaterialTheme.colorScheme.imageModifier, ) { - OpenPollsSectionHeader() + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + OpenPollsSectionHeader() + IconButton( + modifier = Modifier.padding(end = Size10dp), + onClick = { accountViewModel.dismissPollNotification(note.idHex) }, + ) { + CloseIcon() + } + } Row(Modifier.fillMaxWidth().animateItem()) { NoteCompose( baseNote = note, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/OpenPollsState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/OpenPollsState.kt index ede972e7c..ee33578d4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/OpenPollsState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/OpenPollsState.kt @@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -47,10 +48,14 @@ class OpenPollsState( ) val flow: StateFlow> = - account.cache - .observeNotes(filter) - .map { notes -> filterOpenPolls(notes) } - .flowOn(Dispatchers.IO) + combine( + account.cache + .observeNotes(filter) + .map { notes -> filterOpenPolls(notes) }, + account.settings.dismissedPollNoteIds, + ) { polls, dismissed -> + polls.filter { it.idHex !in dismissed } + }.flowOn(Dispatchers.IO) .stateIn( scope, SharingStarted.Eagerly,