Remove the green badge on a pending invite after a first preview (#4532)
* Remove condition on displayType as I believe, that it has no effect. * Remove the green badge on a pending invite after a first preview * Update screenshots * Fix test * Improve DefaultSeenInvitesStore, clear it on logout, and on clear cache. Also create a store per session. * Remember the returned flow. --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
parent
77a7c0b2e5
commit
ef8eeb804e
26 changed files with 326 additions and 29 deletions
|
|
@ -11,8 +11,10 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
||||
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
|
||||
import io.element.android.libraries.fullscreenintent.api.aFullScreenIntentPermissionsState
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentSet
|
||||
|
||||
open class RoomListContentStateProvider : PreviewParameterProvider<RoomListContentState> {
|
||||
override val values: Sequence<RoomListContentState>
|
||||
|
|
@ -29,10 +31,12 @@ internal fun aRoomsContentState(
|
|||
securityBannerState: SecurityBannerState = SecurityBannerState.None,
|
||||
summaries: ImmutableList<RoomListRoomSummary> = aRoomListRoomSummaryList(),
|
||||
fullScreenIntentPermissionsState: FullScreenIntentPermissionsState = aFullScreenIntentPermissionsState(),
|
||||
seenRoomInvites: Set<RoomId> = emptySet(),
|
||||
) = RoomListContentState.Rooms(
|
||||
securityBannerState = securityBannerState,
|
||||
fullScreenIntentPermissionsState = fullScreenIntentPermissionsState,
|
||||
summaries = summaries,
|
||||
seenRoomInvites = seenRoomInvites.toPersistentSet(),
|
||||
)
|
||||
|
||||
internal fun aSkeletonContentState() = RoomListContentState.Skeleton(16)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import io.element.android.features.invite.api.SeenInvitesStore
|
||||
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
|
||||
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
|
||||
import io.element.android.features.invite.api.response.InviteData
|
||||
|
|
@ -57,6 +58,7 @@ import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
|||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.collections.immutable.toPersistentSet
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -92,6 +94,7 @@ class RoomListPresenter @Inject constructor(
|
|||
private val logoutPresenter: Presenter<DirectLogoutState>,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val rageshakeFeatureAvailability: RageshakeFeatureAvailability,
|
||||
private val seenInvitesStore: SeenInvitesStore,
|
||||
) : Presenter<RoomListState> {
|
||||
private val encryptionService: EncryptionService = client.encryptionService()
|
||||
|
||||
|
|
@ -227,6 +230,7 @@ class RoomListPresenter @Inject constructor(
|
|||
loadingState == RoomList.LoadingState.NotLoaded || roomSummaries is AsyncData.Loading
|
||||
}
|
||||
}
|
||||
val seenRoomInvites by remember { seenInvitesStore.seenRoomIds() }.collectAsState(emptySet())
|
||||
val securityBannerState by rememberSecurityBannerState(securityBannerDismissed)
|
||||
return when {
|
||||
showEmpty -> RoomListContentState.Empty(securityBannerState = securityBannerState)
|
||||
|
|
@ -235,7 +239,8 @@ class RoomListPresenter @Inject constructor(
|
|||
RoomListContentState.Rooms(
|
||||
securityBannerState = securityBannerState,
|
||||
fullScreenIntentPermissionsState = fullScreenIntentPermissionsPresenter.present(),
|
||||
summaries = roomSummaries.dataOrNull().orEmpty().toPersistentList()
|
||||
summaries = roomSummaries.dataOrNull().orEmpty().toPersistentList(),
|
||||
seenRoomInvites = seenRoomInvites.toPersistentSet(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermiss
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableSet
|
||||
|
||||
@Immutable
|
||||
data class RoomListState(
|
||||
|
|
@ -65,9 +66,11 @@ sealed interface RoomListContentState {
|
|||
data class Empty(
|
||||
val securityBannerState: SecurityBannerState,
|
||||
) : RoomListContentState
|
||||
|
||||
data class Rooms(
|
||||
val securityBannerState: SecurityBannerState,
|
||||
val fullScreenIntentPermissionsState: FullScreenIntentPermissionsState,
|
||||
val summaries: ImmutableList<RoomListRoomSummary>,
|
||||
val seenRoomInvites: ImmutableSet<RoomId>,
|
||||
) : RoomListContentState
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
|
|||
import io.element.android.features.roomlist.impl.filters.aRoomListFiltersState
|
||||
import io.element.android.features.roomlist.impl.filters.selection.FilterSelectionState
|
||||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.roomlist.impl.model.RoomSummaryDisplayType
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
|
|
@ -239,6 +240,8 @@ private fun RoomsViewList(
|
|||
) { index, room ->
|
||||
RoomSummaryRow(
|
||||
room = room,
|
||||
isInviteSeen = room.displayType == RoomSummaryDisplayType.INVITE &&
|
||||
state.seenRoomInvites.contains(room.roomId),
|
||||
onClick = onRoomClick,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ internal val minHeight = 84.dp
|
|||
@Composable
|
||||
internal fun RoomSummaryRow(
|
||||
room: RoomListRoomSummary,
|
||||
isInviteSeen: Boolean,
|
||||
onClick: (RoomListRoomSummary) -> Unit,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -85,7 +86,7 @@ internal fun RoomSummaryRow(
|
|||
Timber.d("Long click on invite room")
|
||||
},
|
||||
) {
|
||||
InviteNameAndIndicatorRow(name = room.name)
|
||||
InviteNameAndIndicatorRow(name = room.name, isInviteSeen = isInviteSeen)
|
||||
InviteSubtitle(isDm = room.isDm, inviteSender = room.inviteSender)
|
||||
if (!room.isDm && room.inviteSender != null) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
|
@ -300,6 +301,7 @@ private fun LastMessageAndIndicatorRow(
|
|||
@Composable
|
||||
private fun InviteNameAndIndicatorRow(
|
||||
name: String?,
|
||||
isInviteSeen: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -316,9 +318,11 @@ private fun InviteNameAndIndicatorRow(
|
|||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
UnreadIndicatorAtom(
|
||||
color = ElementTheme.colors.unreadIndicator
|
||||
)
|
||||
if (!isInviteSeen) {
|
||||
UnreadIndicatorAtom(
|
||||
color = ElementTheme.colors.unreadIndicator
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -384,6 +388,8 @@ private fun MentionIndicatorAtom() {
|
|||
internal fun RoomSummaryRowPreview(@PreviewParameter(RoomListRoomSummaryProvider::class) data: RoomListRoomSummary) = ElementPreview {
|
||||
RoomSummaryRow(
|
||||
room = data,
|
||||
// Set isInviteSeen to true for the preview when the room has name "Bob"
|
||||
isInviteSeen = data.name == "Bob",
|
||||
onClick = {},
|
||||
eventSink = {},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -39,12 +39,10 @@ data class RoomListRoomSummary(
|
|||
) {
|
||||
val isHighlighted = userDefinedNotificationMode != RoomNotificationMode.MUTE &&
|
||||
(numberOfUnreadNotifications > 0 || numberOfUnreadMentions > 0) ||
|
||||
isMarkedUnread ||
|
||||
displayType == RoomSummaryDisplayType.INVITE
|
||||
isMarkedUnread
|
||||
|
||||
val hasNewContent = numberOfUnreadMessages > 0 ||
|
||||
numberOfUnreadMentions > 0 ||
|
||||
numberOfUnreadNotifications > 0 ||
|
||||
isMarkedUnread ||
|
||||
displayType == RoomSummaryDisplayType.INVITE
|
||||
isMarkedUnread
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,6 +173,8 @@ private fun RoomListSearchContent(
|
|||
) { room ->
|
||||
RoomSummaryRow(
|
||||
room = room,
|
||||
// TODO
|
||||
isInviteSeen = false,
|
||||
onClick = ::onRoomClick,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,9 +12,11 @@ import app.cash.molecule.moleculeFlow
|
|||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import io.element.android.features.invite.api.SeenInvitesStore
|
||||
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
|
||||
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
|
||||
import io.element.android.features.invite.api.response.anAcceptDeclineInviteState
|
||||
import io.element.android.features.invite.test.InMemorySeenInvitesStore
|
||||
import io.element.android.features.leaveroom.api.LeaveRoomEvent
|
||||
import io.element.android.features.leaveroom.api.LeaveRoomState
|
||||
import io.element.android.features.leaveroom.api.aLeaveRoomState
|
||||
|
|
@ -169,10 +171,11 @@ class RoomListPresenterTest {
|
|||
val matrixClient = FakeMatrixClient(
|
||||
roomListService = roomListService
|
||||
)
|
||||
val presenter = createRoomListPresenter(client = matrixClient)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val presenter = createRoomListPresenter(
|
||||
client = matrixClient,
|
||||
seenInvitesStore = InMemorySeenInvitesStore(setOf(A_ROOM_ID, A_ROOM_ID_2, A_ROOM_ID_3)),
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = consumeItemsUntilPredicate { state -> state.contentState is RoomListContentState.Skeleton }.last()
|
||||
assertThat(initialState.contentState).isInstanceOf(RoomListContentState.Skeleton::class.java)
|
||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
||||
|
|
@ -194,6 +197,7 @@ class RoomListPresenterTest {
|
|||
timestamp = "0 TimeOrDate true",
|
||||
)
|
||||
)
|
||||
assertThat(withRoomsState.contentAsRooms().seenRoomInvites).containsExactly(A_ROOM_ID, A_ROOM_ID_2, A_ROOM_ID_3)
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
|
@ -680,6 +684,7 @@ class RoomListPresenterTest {
|
|||
notificationCleaner: NotificationCleaner = FakeNotificationCleaner(),
|
||||
appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore(),
|
||||
rageshakeFeatureAvailability: RageshakeFeatureAvailability = RageshakeFeatureAvailability { true },
|
||||
seenInvitesStore: SeenInvitesStore = InMemorySeenInvitesStore()
|
||||
) = RoomListPresenter(
|
||||
client = client,
|
||||
syncService = syncService,
|
||||
|
|
@ -711,6 +716,7 @@ class RoomListPresenterTest {
|
|||
logoutPresenter = { aDirectLogoutState() },
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
rageshakeFeatureAvailability = rageshakeFeatureAvailability,
|
||||
seenInvitesStore = seenInvitesStore,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,12 +65,12 @@ class RoomListRoomSummaryTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `when display type is invite then isHighlighted and hasNewContent are true`() {
|
||||
fun `when display type is invite then isHighlighted and hasNewContent are false`() {
|
||||
val sut = createRoomListRoomSummary(
|
||||
displayType = RoomSummaryDisplayType.INVITE,
|
||||
)
|
||||
assertThat(sut.isHighlighted).isTrue()
|
||||
assertThat(sut.hasNewContent).isTrue()
|
||||
assertThat(sut.isHighlighted).isFalse()
|
||||
assertThat(sut.hasNewContent).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue