Extract AnnouncementStatus to its own file.
This commit is contained in:
parent
196f3ef462
commit
3b78ab88c5
10 changed files with 45 additions and 32 deletions
|
|
@ -13,6 +13,7 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import dev.zacsweers.metro.Inject
|
import dev.zacsweers.metro.Inject
|
||||||
import io.element.android.features.announcement.api.Announcement
|
import io.element.android.features.announcement.api.Announcement
|
||||||
|
import io.element.android.features.announcement.impl.store.AnnouncementStatus
|
||||||
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
@ -25,7 +26,7 @@ class AnnouncementPresenter(
|
||||||
override fun present(): AnnouncementState {
|
override fun present(): AnnouncementState {
|
||||||
val showSpaceAnnouncement by remember {
|
val showSpaceAnnouncement by remember {
|
||||||
announcementStore.announcementStatusFlow(Announcement.Space).map {
|
announcementStore.announcementStatusFlow(Announcement.Space).map {
|
||||||
it == AnnouncementStore.AnnouncementStatus.Show
|
it == AnnouncementStatus.Show
|
||||||
}
|
}
|
||||||
}.collectAsState(false)
|
}.collectAsState(false)
|
||||||
return AnnouncementState(
|
return AnnouncementState(
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import io.element.android.features.announcement.api.Announcement
|
||||||
import io.element.android.features.announcement.api.AnnouncementService
|
import io.element.android.features.announcement.api.AnnouncementService
|
||||||
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementState
|
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementState
|
||||||
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementView
|
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementView
|
||||||
|
import io.element.android.features.announcement.impl.store.AnnouncementStatus
|
||||||
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
@ -38,13 +39,13 @@ class DefaultAnnouncementService(
|
||||||
when (announcement) {
|
when (announcement) {
|
||||||
Announcement.Space -> showSpaceAnnouncement()
|
Announcement.Space -> showSpaceAnnouncement()
|
||||||
Announcement.NewNotificationSound -> {
|
Announcement.NewNotificationSound -> {
|
||||||
announcementStore.setAnnouncementStatus(Announcement.NewNotificationSound, AnnouncementStore.AnnouncementStatus.Show)
|
announcementStore.setAnnouncementStatus(Announcement.NewNotificationSound, AnnouncementStatus.Show)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onAnnouncementDismissed(announcement: Announcement) {
|
override suspend fun onAnnouncementDismissed(announcement: Announcement) {
|
||||||
announcementStore.setAnnouncementStatus(announcement, AnnouncementStore.AnnouncementStatus.Shown)
|
announcementStore.setAnnouncementStatus(announcement, AnnouncementStatus.Shown)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun announcementsToShowFlow(): Flow<List<Announcement>> {
|
override fun announcementsToShowFlow(): Flow<List<Announcement>> {
|
||||||
|
|
@ -53,10 +54,10 @@ class DefaultAnnouncementService(
|
||||||
announcementStore.announcementStatusFlow(Announcement.NewNotificationSound),
|
announcementStore.announcementStatusFlow(Announcement.NewNotificationSound),
|
||||||
) { spaceAnnouncementStatus, newNotificationSoundStatus ->
|
) { spaceAnnouncementStatus, newNotificationSoundStatus ->
|
||||||
buildList {
|
buildList {
|
||||||
if (spaceAnnouncementStatus == AnnouncementStore.AnnouncementStatus.Show) {
|
if (spaceAnnouncementStatus == AnnouncementStatus.Show) {
|
||||||
add(Announcement.Space)
|
add(Announcement.Space)
|
||||||
}
|
}
|
||||||
if (newNotificationSoundStatus == AnnouncementStore.AnnouncementStatus.Show) {
|
if (newNotificationSoundStatus == AnnouncementStatus.Show) {
|
||||||
add(Announcement.NewNotificationSound)
|
add(Announcement.NewNotificationSound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -65,8 +66,8 @@ class DefaultAnnouncementService(
|
||||||
|
|
||||||
private suspend fun showSpaceAnnouncement() {
|
private suspend fun showSpaceAnnouncement() {
|
||||||
val currentValue = announcementStore.announcementStatusFlow(Announcement.Space).first()
|
val currentValue = announcementStore.announcementStatusFlow(Announcement.Space).first()
|
||||||
if (currentValue == AnnouncementStore.AnnouncementStatus.NeverShown) {
|
if (currentValue == AnnouncementStatus.NeverShown) {
|
||||||
announcementStore.setAnnouncementStatus(Announcement.Space, AnnouncementStore.AnnouncementStatus.Show)
|
announcementStore.setAnnouncementStatus(Announcement.Space, AnnouncementStatus.Show)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import dev.zacsweers.metro.Inject
|
import dev.zacsweers.metro.Inject
|
||||||
import io.element.android.features.announcement.api.Announcement
|
import io.element.android.features.announcement.api.Announcement
|
||||||
|
import io.element.android.features.announcement.impl.store.AnnouncementStatus
|
||||||
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
||||||
import io.element.android.features.announcement.impl.store.AnnouncementStore.AnnouncementStatus
|
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.announcement.impl.store
|
||||||
|
|
||||||
|
enum class AnnouncementStatus {
|
||||||
|
NeverShown,
|
||||||
|
Show,
|
||||||
|
Shown,
|
||||||
|
}
|
||||||
|
|
@ -21,10 +21,4 @@ interface AnnouncementStore {
|
||||||
): Flow<AnnouncementStatus>
|
): Flow<AnnouncementStatus>
|
||||||
|
|
||||||
suspend fun reset()
|
suspend fun reset()
|
||||||
|
|
||||||
enum class AnnouncementStatus {
|
|
||||||
NeverShown,
|
|
||||||
Show,
|
|
||||||
Shown,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,23 +27,23 @@ class DefaultAnnouncementStore(
|
||||||
) : AnnouncementStore {
|
) : AnnouncementStore {
|
||||||
private val store = preferenceDataStoreFactory.create("elementx_announcement")
|
private val store = preferenceDataStoreFactory.create("elementx_announcement")
|
||||||
|
|
||||||
override suspend fun setAnnouncementStatus(announcement: Announcement, status: AnnouncementStore.AnnouncementStatus) {
|
override suspend fun setAnnouncementStatus(announcement: Announcement, status: AnnouncementStatus) {
|
||||||
val key = announcement.toKey()
|
val key = announcement.toKey()
|
||||||
store.edit { prefs ->
|
store.edit { prefs ->
|
||||||
prefs[key] = status.ordinal
|
prefs[key] = status.ordinal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun announcementStatusFlow(announcement: Announcement): Flow<AnnouncementStore.AnnouncementStatus> {
|
override fun announcementStatusFlow(announcement: Announcement): Flow<AnnouncementStatus> {
|
||||||
val key = announcement.toKey()
|
val key = announcement.toKey()
|
||||||
// For NewNotificationSound, a migration will set it to Show on application upgrade (see AppMigration08)
|
// For NewNotificationSound, a migration will set it to Show on application upgrade (see AppMigration08)
|
||||||
val defaultStatus = when (announcement) {
|
val defaultStatus = when (announcement) {
|
||||||
Announcement.Space -> AnnouncementStore.AnnouncementStatus.NeverShown
|
Announcement.Space -> AnnouncementStatus.NeverShown
|
||||||
Announcement.NewNotificationSound -> AnnouncementStore.AnnouncementStatus.Shown
|
Announcement.NewNotificationSound -> AnnouncementStatus.Shown
|
||||||
}
|
}
|
||||||
return store.data.map { prefs ->
|
return store.data.map { prefs ->
|
||||||
val ordinal = prefs[key] ?: defaultStatus.ordinal
|
val ordinal = prefs[key] ?: defaultStatus.ordinal
|
||||||
AnnouncementStore.AnnouncementStatus.entries.getOrElse(ordinal) { defaultStatus }
|
AnnouncementStatus.entries.getOrElse(ordinal) { defaultStatus }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package io.element.android.features.announcement.impl
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.announcement.api.Announcement
|
import io.element.android.features.announcement.api.Announcement
|
||||||
|
import io.element.android.features.announcement.impl.store.AnnouncementStatus
|
||||||
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
||||||
import io.element.android.features.announcement.impl.store.InMemoryAnnouncementStore
|
import io.element.android.features.announcement.impl.store.InMemoryAnnouncementStore
|
||||||
import io.element.android.tests.testutils.test
|
import io.element.android.tests.testutils.test
|
||||||
|
|
@ -34,10 +35,10 @@ class AnnouncementPresenterTest {
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val state = awaitItem()
|
val state = awaitItem()
|
||||||
assertThat(state.showSpaceAnnouncement).isFalse()
|
assertThat(state.showSpaceAnnouncement).isFalse()
|
||||||
store.setAnnouncementStatus(Announcement.Space, AnnouncementStore.AnnouncementStatus.Show)
|
store.setAnnouncementStatus(Announcement.Space, AnnouncementStatus.Show)
|
||||||
val updatedState = awaitItem()
|
val updatedState = awaitItem()
|
||||||
assertThat(updatedState.showSpaceAnnouncement).isTrue()
|
assertThat(updatedState.showSpaceAnnouncement).isTrue()
|
||||||
store.setAnnouncementStatus(Announcement.Space, AnnouncementStore.AnnouncementStatus.Shown)
|
store.setAnnouncementStatus(Announcement.Space, AnnouncementStatus.Shown)
|
||||||
val finalState = awaitItem()
|
val finalState = awaitItem()
|
||||||
assertThat(finalState.showSpaceAnnouncement).isFalse()
|
assertThat(finalState.showSpaceAnnouncement).isFalse()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.announcement.api.Announcement
|
import io.element.android.features.announcement.api.Announcement
|
||||||
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementState
|
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementState
|
||||||
import io.element.android.features.announcement.impl.spaces.aSpaceAnnouncementState
|
import io.element.android.features.announcement.impl.spaces.aSpaceAnnouncementState
|
||||||
|
import io.element.android.features.announcement.impl.store.AnnouncementStatus
|
||||||
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
||||||
import io.element.android.features.announcement.impl.store.InMemoryAnnouncementStore
|
import io.element.android.features.announcement.impl.store.InMemoryAnnouncementStore
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
|
|
@ -25,14 +26,14 @@ class DefaultAnnouncementServiceTest {
|
||||||
val sut = createDefaultAnnouncementService(
|
val sut = createDefaultAnnouncementService(
|
||||||
announcementStore = announcementStore,
|
announcementStore = announcementStore,
|
||||||
)
|
)
|
||||||
assertThat(announcementStore.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStore.AnnouncementStatus.NeverShown)
|
assertThat(announcementStore.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStatus.NeverShown)
|
||||||
sut.showAnnouncement(Announcement.Space)
|
sut.showAnnouncement(Announcement.Space)
|
||||||
assertThat(announcementStore.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStore.AnnouncementStatus.Show)
|
assertThat(announcementStore.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStatus.Show)
|
||||||
// Simulate user close the announcement
|
// Simulate user close the announcement
|
||||||
sut.onAnnouncementDismissed(Announcement.Space)
|
sut.onAnnouncementDismissed(Announcement.Space)
|
||||||
// Entering again the space tab should not change the value
|
// Entering again the space tab should not change the value
|
||||||
sut.showAnnouncement(Announcement.Space)
|
sut.showAnnouncement(Announcement.Space)
|
||||||
assertThat(announcementStore.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStore.AnnouncementStatus.Shown)
|
assertThat(announcementStore.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStatus.Shown)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDefaultAnnouncementService(
|
private fun createDefaultAnnouncementService(
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package io.element.android.features.announcement.impl.spaces
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.announcement.api.Announcement
|
import io.element.android.features.announcement.api.Announcement
|
||||||
|
import io.element.android.features.announcement.impl.store.AnnouncementStatus
|
||||||
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
import io.element.android.features.announcement.impl.store.AnnouncementStore
|
||||||
import io.element.android.features.announcement.impl.store.InMemoryAnnouncementStore
|
import io.element.android.features.announcement.impl.store.InMemoryAnnouncementStore
|
||||||
import io.element.android.tests.testutils.test
|
import io.element.android.tests.testutils.test
|
||||||
|
|
@ -24,10 +25,10 @@ class SpaceAnnouncementPresenterTest {
|
||||||
announcementStore = store,
|
announcementStore = store,
|
||||||
)
|
)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
assertThat(store.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStore.AnnouncementStatus.NeverShown)
|
assertThat(store.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStatus.NeverShown)
|
||||||
val state = awaitItem()
|
val state = awaitItem()
|
||||||
state.eventSink(SpaceAnnouncementEvents.Continue)
|
state.eventSink(SpaceAnnouncementEvents.Continue)
|
||||||
assertThat(store.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStore.AnnouncementStatus.Shown)
|
assertThat(store.announcementStatusFlow(Announcement.Space).first()).isEqualTo(AnnouncementStatus.Shown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,23 +13,23 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
|
||||||
class InMemoryAnnouncementStore(
|
class InMemoryAnnouncementStore(
|
||||||
initialSpaceAnnouncementStatus: AnnouncementStore.AnnouncementStatus = AnnouncementStore.AnnouncementStatus.NeverShown,
|
initialSpaceAnnouncementStatus: AnnouncementStatus = AnnouncementStatus.NeverShown,
|
||||||
initialNewNotificationSoundAnnouncementStatus: AnnouncementStore.AnnouncementStatus = AnnouncementStore.AnnouncementStatus.NeverShown,
|
initialNewNotificationSoundAnnouncementStatus: AnnouncementStatus = AnnouncementStatus.NeverShown,
|
||||||
) : AnnouncementStore {
|
) : AnnouncementStore {
|
||||||
private val spaceAnnouncement = MutableStateFlow(initialSpaceAnnouncementStatus)
|
private val spaceAnnouncement = MutableStateFlow(initialSpaceAnnouncementStatus)
|
||||||
private val newNotificationSoundAnnouncement = MutableStateFlow(initialNewNotificationSoundAnnouncementStatus)
|
private val newNotificationSoundAnnouncement = MutableStateFlow(initialNewNotificationSoundAnnouncementStatus)
|
||||||
|
|
||||||
override suspend fun setAnnouncementStatus(announcement: Announcement, status: AnnouncementStore.AnnouncementStatus) {
|
override suspend fun setAnnouncementStatus(announcement: Announcement, status: AnnouncementStatus) {
|
||||||
announcement.toMutableStateFlow().value = status
|
announcement.toMutableStateFlow().value = status
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun announcementStatusFlow(announcement: Announcement): Flow<AnnouncementStore.AnnouncementStatus> {
|
override fun announcementStatusFlow(announcement: Announcement): Flow<AnnouncementStatus> {
|
||||||
return announcement.toMutableStateFlow().asStateFlow()
|
return announcement.toMutableStateFlow().asStateFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun reset() {
|
override suspend fun reset() {
|
||||||
spaceAnnouncement.value = AnnouncementStore.AnnouncementStatus.NeverShown
|
spaceAnnouncement.value = AnnouncementStatus.NeverShown
|
||||||
newNotificationSoundAnnouncement.value = AnnouncementStore.AnnouncementStatus.NeverShown
|
newNotificationSoundAnnouncement.value = AnnouncementStatus.NeverShown
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Announcement.toMutableStateFlow() = when (this) {
|
private fun Announcement.toMutableStateFlow() = when (this) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue