Pinned messages list : add loading for pinned messages count and add tests

This commit is contained in:
ganfra 2024-09-03 14:36:35 +02:00
parent faae2d1004
commit 80f750ae34
6 changed files with 41 additions and 9 deletions

View file

@ -86,7 +86,7 @@ class RoomDetailsPresenter @Inject constructor(
val isPublic by remember { derivedStateOf { roomInfo?.isPublic.orFalse() } } val isPublic by remember { derivedStateOf { roomInfo?.isPublic.orFalse() } }
val canShowPinnedMessages = isPinnedMessagesFeatureEnabled() val canShowPinnedMessages = isPinnedMessagesFeatureEnabled()
val pinnedMessagesCount by remember { derivedStateOf { roomInfo?.pinnedEventIds?.size ?: 0 } } val pinnedMessagesCount by remember { derivedStateOf { roomInfo?.pinnedEventIds?.size } }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
canShowNotificationSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.NotificationSettings) canShowNotificationSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.NotificationSettings)

View file

@ -47,7 +47,7 @@ data class RoomDetailsState(
val isPublic: Boolean, val isPublic: Boolean,
val heroes: ImmutableList<MatrixUser>, val heroes: ImmutableList<MatrixUser>,
val canShowPinnedMessages: Boolean, val canShowPinnedMessages: Boolean,
val pinnedMessagesCount: Int, val pinnedMessagesCount: Int?,
val eventSink: (RoomDetailsEvent) -> Unit val eventSink: (RoomDetailsEvent) -> Unit
) )

View file

@ -53,6 +53,7 @@ open class RoomDetailsStateProvider : PreviewParameterProvider<RoomDetailsState>
aRoomDetailsState(canCall = false, canInvite = false), aRoomDetailsState(canCall = false, canInvite = false),
aRoomDetailsState(isPublic = false), aRoomDetailsState(isPublic = false),
aRoomDetailsState(heroes = aMatrixUserList()), aRoomDetailsState(heroes = aMatrixUserList()),
aRoomDetailsState(pinnedMessagesCount = 3),
// Add other state here // Add other state here
) )
} }
@ -106,7 +107,7 @@ fun aRoomDetailsState(
isPublic: Boolean = true, isPublic: Boolean = true,
heroes: List<MatrixUser> = emptyList(), heroes: List<MatrixUser> = emptyList(),
canShowPinnedMessages: Boolean = true, canShowPinnedMessages: Boolean = true,
pinnedMessagesCount: Int = 3, pinnedMessagesCount: Int? = null,
eventSink: (RoomDetailsEvent) -> Unit = {}, eventSink: (RoomDetailsEvent) -> Unit = {},
) = RoomDetailsState( ) = RoomDetailsState(
roomId = roomId, roomId = roomId,

View file

@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -66,6 +67,7 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.DropdownMenu import io.element.android.libraries.designsystem.theme.components.DropdownMenu
import io.element.android.libraries.designsystem.theme.components.DropdownMenuItem import io.element.android.libraries.designsystem.theme.components.DropdownMenuItem
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
@ -184,7 +186,7 @@ fun RoomDetailsView(
} }
) )
if(state.canShowPinnedMessages) { if (state.canShowPinnedMessages) {
PinnedMessagesItem( PinnedMessagesItem(
pinnedMessagesCount = state.pinnedMessagesCount, pinnedMessagesCount = state.pinnedMessagesCount,
onPinnedMessagesClick = onPinnedMessagesClick onPinnedMessagesClick = onPinnedMessagesClick
@ -513,13 +515,20 @@ private fun MembersItem(
@Composable @Composable
private fun PinnedMessagesItem( private fun PinnedMessagesItem(
pinnedMessagesCount: Int, pinnedMessagesCount: Int?,
onPinnedMessagesClick: () -> Unit, onPinnedMessagesClick: () -> Unit,
) { ) {
ListItem( ListItem(
headlineContent = { Text(stringResource(CommonStrings.screen_room_details_pinned_events_row_title)) }, headlineContent = { Text(stringResource(CommonStrings.screen_room_details_pinned_events_row_title)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Pin())), leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Pin())),
trailingContent = ListItemContent.Text(pinnedMessagesCount.toString()), trailingContent =
if (pinnedMessagesCount == null) {
ListItemContent.Custom {
CircularProgressIndicator(strokeWidth = 2.dp, modifier = Modifier.size(24.dp))
}
} else {
ListItemContent.Text(pinnedMessagesCount.toString())
},
onClick = onPinnedMessagesClick, onClick = onPinnedMessagesClick,
) )
} }

View file

@ -42,6 +42,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID_2
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
@ -81,6 +82,7 @@ class RoomDetailsPresenterTest {
dispatchers: CoroutineDispatchers = testCoroutineDispatchers(), dispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
analyticsService: AnalyticsService = FakeAnalyticsService(), analyticsService: AnalyticsService = FakeAnalyticsService(),
isPinnedMessagesFeatureEnabled: Boolean = true,
): RoomDetailsPresenter { ): RoomDetailsPresenter {
val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService) val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService)
val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory { val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory {
@ -99,6 +101,7 @@ class RoomDetailsPresenterTest {
roomMembersDetailsPresenterFactory = roomMemberDetailsPresenterFactory, roomMembersDetailsPresenterFactory = roomMemberDetailsPresenterFactory,
leaveRoomPresenter = leaveRoomPresenter, leaveRoomPresenter = leaveRoomPresenter,
dispatchers = dispatchers, dispatchers = dispatchers,
isPinnedMessagesFeatureEnabled = { isPinnedMessagesFeatureEnabled },
analyticsService = analyticsService, analyticsService = analyticsService,
) )
} }
@ -127,14 +130,15 @@ class RoomDetailsPresenterTest {
assertThat(initialState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(room.topic!!)) assertThat(initialState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(room.topic!!))
assertThat(initialState.memberCount).isEqualTo(room.joinedMemberCount) assertThat(initialState.memberCount).isEqualTo(room.joinedMemberCount)
assertThat(initialState.isEncrypted).isEqualTo(room.isEncrypted) assertThat(initialState.isEncrypted).isEqualTo(room.isEncrypted)
assertThat(initialState.canShowPinnedMessages).isTrue()
assertThat(initialState.pinnedMessagesCount).isNull()
cancelAndIgnoreRemainingEvents() cancelAndIgnoreRemainingEvents()
} }
} }
@Test @Test
fun `present - initial state is updated with roomInfo if it exists`() = runTest { fun `present - initial state is updated with roomInfo if it exists`() = runTest {
val roomInfo = aRoomInfo(name = "A room name", topic = "A topic", avatarUrl = "https://matrix.org/avatar.jpg") val roomInfo = aRoomInfo(name = "A room name", topic = "A topic", avatarUrl = "https://matrix.org/avatar.jpg", pinnedEventIds = listOf(AN_EVENT_ID))
val room = aMatrixRoom( val room = aMatrixRoom(
canInviteResult = { Result.success(true) }, canInviteResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) },
@ -149,7 +153,7 @@ class RoomDetailsPresenterTest {
assertThat(updatedState.roomName).isEqualTo(roomInfo.name) assertThat(updatedState.roomName).isEqualTo(roomInfo.name)
assertThat(updatedState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl) assertThat(updatedState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl)
assertThat(updatedState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(roomInfo.topic!!)) assertThat(updatedState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(roomInfo.topic!!))
assertThat(updatedState.pinnedMessagesCount).isEqualTo(roomInfo.pinnedEventIds.size)
cancelAndIgnoreRemainingEvents() cancelAndIgnoreRemainingEvents()
} }
} }

View file

@ -127,6 +127,22 @@ class RoomDetailsViewTest {
} }
} }
@Config(qualifiers = "h1024dp")
@Test
fun `click on pinned messages invokes expected callback`() {
ensureCalledOnce { callback ->
rule.setRoomDetailView(
state = aRoomDetailsState(
eventSink = EventsRecorder(expectEvents = false),
canInvite = true,
),
onPinnedMessagesClick = callback,
)
rule.clickOn(CommonStrings.screen_room_details_pinned_events_row_title)
}
}
@Config(qualifiers = "h1024dp") @Config(qualifiers = "h1024dp")
@Test @Test
fun `click on add topic emit expected event`() { fun `click on add topic emit expected event`() {
@ -263,6 +279,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoomD
openPollHistory: () -> Unit = EnsureNeverCalled(), openPollHistory: () -> Unit = EnsureNeverCalled(),
openAdminSettings: () -> Unit = EnsureNeverCalled(), openAdminSettings: () -> Unit = EnsureNeverCalled(),
onJoinCallClick: () -> Unit = EnsureNeverCalled(), onJoinCallClick: () -> Unit = EnsureNeverCalled(),
onPinnedMessagesClick: () -> Unit = EnsureNeverCalled(),
) { ) {
setContent { setContent {
RoomDetailsView( RoomDetailsView(
@ -277,6 +294,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoomD
openPollHistory = openPollHistory, openPollHistory = openPollHistory,
openAdminSettings = openAdminSettings, openAdminSettings = openAdminSettings,
onJoinCallClick = onJoinCallClick, onJoinCallClick = onJoinCallClick,
onPinnedMessagesClick = onPinnedMessagesClick,
) )
} }
} }