Merge pull request #3631 from element-hq/feature/fga/rework_room_summary
Rework room summary
This commit is contained in:
commit
a3db4b2043
70 changed files with 734 additions and 563 deletions
|
|
@ -45,6 +45,8 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
|||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.getRoomInfoFlow
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
|
@ -120,12 +122,9 @@ class RoomFlowNode @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun subscribeToRoomInfoFlow(roomId: RoomId, serverNames: List<String>) {
|
||||
val roomInfoFlow = client.getRoomInfoFlow(
|
||||
roomId = roomId
|
||||
).map { it.getOrNull() }
|
||||
|
||||
val isSpaceFlow = roomInfoFlow.map { it?.isSpace.orFalse() }.distinctUntilChanged()
|
||||
val currentMembershipFlow = roomInfoFlow.map { it?.currentUserMembership }.distinctUntilChanged()
|
||||
val roomInfoFlow = client.getRoomInfoFlow(roomIdOrAlias = roomId.toRoomIdOrAlias())
|
||||
val isSpaceFlow = roomInfoFlow.map { it.getOrNull()?.isSpace.orFalse() }.distinctUntilChanged()
|
||||
val currentMembershipFlow = roomInfoFlow.map { it.getOrNull()?.currentUserMembership }.distinctUntilChanged()
|
||||
combine(currentMembershipFlow, isSpaceFlow) { membership, isSpace ->
|
||||
Timber.d("Room membership: $membership")
|
||||
when (membership) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ import io.element.android.libraries.core.meta.BuildMeta
|
|||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.getRoomInfoFlow
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomType
|
||||
|
|
@ -70,7 +72,7 @@ class JoinRoomPresenter @AssistedInject constructor(
|
|||
override fun present(): JoinRoomState {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
var retryCount by remember { mutableIntStateOf(0) }
|
||||
val roomInfo by matrixClient.getRoomInfoFlow(roomId).collectAsState(initial = Optional.empty())
|
||||
val roomInfo by matrixClient.getRoomInfoFlow(roomId.toRoomIdOrAlias()).collectAsState(initial = Optional.empty())
|
||||
val joinAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
val knockAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
val contentState by produceState<ContentState>(
|
||||
|
|
@ -204,7 +206,7 @@ internal fun MatrixRoomInfo.toContentState(): ContentState {
|
|||
name = name,
|
||||
topic = topic,
|
||||
alias = canonicalAlias,
|
||||
numberOfMembers = activeMembersCount,
|
||||
numberOfMembers = activeMembersCount.toLong(),
|
||||
isDm = isDm,
|
||||
roomType = if (isSpace) RoomType.Space else RoomType.Room,
|
||||
roomAvatarUrl = avatarUrl,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
|||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.room.RoomType
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import io.element.android.libraries.matrix.ui.model.InviteSender
|
||||
|
||||
open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
|||
import io.element.android.libraries.matrix.test.A_SERVER_LIST
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom
|
||||
import io.element.android.libraries.matrix.ui.model.toInviteSender
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
|
|
@ -67,10 +67,10 @@ class JoinRoomPresenterTest {
|
|||
|
||||
@Test
|
||||
fun `present - when room is joined then content state is filled with his data`() = runTest {
|
||||
val roomInfo = aRoomInfo()
|
||||
val roomSummary = aRoomSummary()
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
getRoomInfoFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomInfo))
|
||||
getRoomSummaryFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomSummary))
|
||||
}
|
||||
}
|
||||
val presenter = createJoinRoomPresenter(
|
||||
|
|
@ -81,22 +81,22 @@ class JoinRoomPresenterTest {
|
|||
awaitItem().also { state ->
|
||||
val contentState = state.contentState as ContentState.Loaded
|
||||
assertThat(contentState.roomId).isEqualTo(A_ROOM_ID)
|
||||
assertThat(contentState.name).isEqualTo(roomInfo.name)
|
||||
assertThat(contentState.topic).isEqualTo(roomInfo.topic)
|
||||
assertThat(contentState.alias).isEqualTo(roomInfo.canonicalAlias)
|
||||
assertThat(contentState.numberOfMembers).isEqualTo(roomInfo.activeMembersCount)
|
||||
assertThat(contentState.isDm).isEqualTo(roomInfo.isDirect)
|
||||
assertThat(contentState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl)
|
||||
assertThat(contentState.name).isEqualTo(roomSummary.info.name)
|
||||
assertThat(contentState.topic).isEqualTo(roomSummary.info.topic)
|
||||
assertThat(contentState.alias).isEqualTo(roomSummary.info.canonicalAlias)
|
||||
assertThat(contentState.numberOfMembers).isEqualTo(roomSummary.info.activeMembersCount)
|
||||
assertThat(contentState.isDm).isEqualTo(roomSummary.info.isDirect)
|
||||
assertThat(contentState.roomAvatarUrl).isEqualTo(roomSummary.info.avatarUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - when room is invited then join authorization is equal to invited`() = runTest {
|
||||
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.INVITED)
|
||||
val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.INVITED)
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
getRoomInfoFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomInfo))
|
||||
getRoomSummaryFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomSummary))
|
||||
}
|
||||
}
|
||||
val presenter = createJoinRoomPresenter(
|
||||
|
|
@ -114,13 +114,13 @@ class JoinRoomPresenterTest {
|
|||
fun `present - when room is invited then join authorization is equal to invited, an inviter is provided`() = runTest {
|
||||
val inviter = aRoomMember(userId = UserId("@bob:example.com"), displayName = "Bob")
|
||||
val expectedInviteSender = inviter.toInviteSender()
|
||||
val roomInfo = aRoomInfo(
|
||||
val roomSummary = aRoomSummary(
|
||||
currentUserMembership = CurrentUserMembership.INVITED,
|
||||
inviter = inviter,
|
||||
)
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
getRoomInfoFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomInfo))
|
||||
getRoomSummaryFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomSummary))
|
||||
}
|
||||
}
|
||||
val presenter = createJoinRoomPresenter(
|
||||
|
|
@ -140,10 +140,10 @@ class JoinRoomPresenterTest {
|
|||
val acceptDeclinePresenter = Presenter {
|
||||
anAcceptDeclineInviteState(eventSink = eventSinkRecorder)
|
||||
}
|
||||
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.INVITED)
|
||||
val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.INVITED)
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
getRoomInfoFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomInfo))
|
||||
getRoomSummaryFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomSummary))
|
||||
}
|
||||
}
|
||||
val presenter = createJoinRoomPresenter(
|
||||
|
|
@ -224,10 +224,10 @@ class JoinRoomPresenterTest {
|
|||
|
||||
@Test
|
||||
fun `present - when room is left and public then join authorization is equal to canJoin`() = runTest {
|
||||
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.LEFT, isPublic = true)
|
||||
val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.LEFT, isPublic = true)
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
getRoomInfoFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomInfo))
|
||||
getRoomSummaryFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomSummary))
|
||||
}
|
||||
}
|
||||
val presenter = createJoinRoomPresenter(
|
||||
|
|
@ -243,10 +243,10 @@ class JoinRoomPresenterTest {
|
|||
|
||||
@Test
|
||||
fun `present - when room is left and not public then join authorization is equal to unknown`() = runTest {
|
||||
val roomInfo = aRoomInfo(currentUserMembership = CurrentUserMembership.LEFT, isPublic = false)
|
||||
val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.LEFT, isPublic = false)
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
getRoomInfoFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomInfo))
|
||||
getRoomSummaryFlowLambda = { _ ->
|
||||
flowOf(Optional.of(roomSummary))
|
||||
}
|
||||
}
|
||||
val presenter = createJoinRoomPresenter(
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import im.vector.app.features.analytics.plan.Interaction
|
|||
import io.element.android.features.messages.impl.attachments.Attachment
|
||||
import io.element.android.features.messages.impl.attachments.preview.error.sendAttachmentError
|
||||
import io.element.android.features.messages.impl.draft.ComposerDraftService
|
||||
import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestionsDataSource
|
||||
import io.element.android.features.messages.impl.messagecomposer.suggestions.SuggestionsProcessor
|
||||
import io.element.android.features.messages.impl.timeline.TimelineController
|
||||
import io.element.android.features.messages.impl.utils.TextPillificationHelper
|
||||
|
|
|
|||
|
|
@ -5,20 +5,22 @@
|
|||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.messagecomposer
|
||||
package io.element.android.features.messages.impl.messagecomposer.suggestions
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
data class RoomAliasSuggestion(
|
||||
val roomAlias: RoomAlias,
|
||||
val roomSummary: RoomSummary,
|
||||
val roomId: RoomId,
|
||||
val roomName: String?,
|
||||
val roomAvatarUrl: String?,
|
||||
)
|
||||
|
||||
interface RoomAliasSuggestionsDataSource {
|
||||
|
|
@ -32,14 +34,16 @@ class DefaultRoomAliasSuggestionsDataSource @Inject constructor(
|
|||
override fun getAllRoomAliasSuggestions(): Flow<List<RoomAliasSuggestion>> {
|
||||
return roomListService
|
||||
.allRooms
|
||||
.filteredSummaries
|
||||
.summaries
|
||||
.map { roomSummaries ->
|
||||
roomSummaries
|
||||
.mapNotNull { roomSummary ->
|
||||
roomSummary.canonicalAlias?.let { roomAlias ->
|
||||
roomSummary.info.canonicalAlias?.let { roomAlias ->
|
||||
RoomAliasSuggestion(
|
||||
roomAlias = roomAlias,
|
||||
roomSummary = roomSummary,
|
||||
roomId = roomSummary.roomId,
|
||||
roomName = roomSummary.info.name,
|
||||
roomAvatarUrl = roomSummary.info.avatarUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,6 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
|||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
||||
import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -60,7 +59,7 @@ fun SuggestionsPickerView(
|
|||
when (suggestion) {
|
||||
is ResolvedSuggestion.AtRoom -> "@room"
|
||||
is ResolvedSuggestion.Member -> suggestion.roomMember.userId.value
|
||||
is ResolvedSuggestion.Alias -> suggestion.roomSummary.roomId.value
|
||||
is ResolvedSuggestion.Alias -> suggestion.roomId.value
|
||||
}
|
||||
}
|
||||
) {
|
||||
|
|
@ -96,12 +95,12 @@ private fun SuggestionItemView(
|
|||
val avatarData = when (suggestion) {
|
||||
is ResolvedSuggestion.AtRoom -> roomAvatar?.copy(size = avatarSize) ?: AvatarData(roomId, roomName, null, avatarSize)
|
||||
is ResolvedSuggestion.Member -> suggestion.roomMember.getAvatarData(avatarSize)
|
||||
is ResolvedSuggestion.Alias -> suggestion.roomSummary.getAvatarData(avatarSize)
|
||||
is ResolvedSuggestion.Alias -> suggestion.getAvatarData(avatarSize)
|
||||
}
|
||||
val title = when (suggestion) {
|
||||
is ResolvedSuggestion.AtRoom -> stringResource(R.string.screen_room_mentions_at_room_title)
|
||||
is ResolvedSuggestion.Member -> suggestion.roomMember.displayName
|
||||
is ResolvedSuggestion.Alias -> suggestion.roomSummary.name
|
||||
is ResolvedSuggestion.Alias -> suggestion.roomName
|
||||
}
|
||||
val subtitle = when (suggestion) {
|
||||
is ResolvedSuggestion.AtRoom -> "@room"
|
||||
|
|
@ -152,11 +151,6 @@ internal fun SuggestionsPickerViewPreview() {
|
|||
role = RoomMember.Role.USER,
|
||||
)
|
||||
val anAlias = remember { RoomAlias("#room:domain.org") }
|
||||
val roomSummaryDetails = remember {
|
||||
aRoomSummaryDetails(
|
||||
name = "My room",
|
||||
)
|
||||
}
|
||||
SuggestionsPickerView(
|
||||
roomId = RoomId("!room:matrix.org"),
|
||||
roomName = "Room",
|
||||
|
|
@ -166,8 +160,10 @@ internal fun SuggestionsPickerViewPreview() {
|
|||
ResolvedSuggestion.Member(roomMember),
|
||||
ResolvedSuggestion.Member(roomMember.copy(userId = UserId("@bob:server.org"), displayName = "Bob")),
|
||||
ResolvedSuggestion.Alias(
|
||||
anAlias,
|
||||
roomSummaryDetails,
|
||||
roomAlias = anAlias,
|
||||
roomId = RoomId("!room:matrix.org"),
|
||||
roomName = "My room",
|
||||
roomAvatarUrl = null,
|
||||
)
|
||||
),
|
||||
onSelectSuggestion = {}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
package io.element.android.features.messages.impl.messagecomposer.suggestions
|
||||
|
||||
import io.element.android.features.messages.impl.messagecomposer.RoomAliasSuggestion
|
||||
import io.element.android.libraries.core.data.filterUpTo
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
|
|
@ -55,7 +54,14 @@ class SuggestionsProcessor @Inject constructor() {
|
|||
SuggestionType.Room -> {
|
||||
roomAliasSuggestions
|
||||
.filter { it.roomAlias.value.contains(suggestion.text, ignoreCase = true) }
|
||||
.map { ResolvedSuggestion.Alias(it.roomAlias, it.roomSummary) }
|
||||
.map {
|
||||
ResolvedSuggestion.Alias(
|
||||
roomAlias = it.roomAlias,
|
||||
roomId = it.roomId,
|
||||
roomName = it.roomName,
|
||||
roomAvatarUrl = it.roomAvatarUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
SuggestionType.Command,
|
||||
is SuggestionType.Custom -> {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ package io.element.android.features.messages.impl.messagecomposer
|
|||
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.messages.impl.messagecomposer.suggestions.DefaultRoomAliasSuggestionsDataSource
|
||||
import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestion
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
|
|
@ -38,7 +40,9 @@ class DefaultRoomAliasSuggestionsDataSourceTest {
|
|||
listOf(
|
||||
RoomAliasSuggestion(
|
||||
roomAlias = A_ROOM_ALIAS,
|
||||
roomSummary = aRoomSummaryWithAnAlias
|
||||
roomId = aRoomSummaryWithAnAlias.roomId,
|
||||
roomName = aRoomSummaryWithAnAlias.info.name,
|
||||
roomAvatarUrl = aRoomSummaryWithAnAlias.info.avatarUrl
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
package io.element.android.features.messages.impl.messagecomposer
|
||||
|
||||
import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestion
|
||||
import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestionsDataSource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
package io.element.android.features.messages.impl.messagecomposer.suggestions
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.messages.impl.messagecomposer.RoomAliasSuggestion
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
||||
|
|
@ -110,13 +109,25 @@ class SuggestionsProcessorTest {
|
|||
val result = suggestionsProcessor.process(
|
||||
suggestion = aRoomSuggestion("ALI"),
|
||||
roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()),
|
||||
roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)),
|
||||
roomAliasSuggestions = listOf(
|
||||
RoomAliasSuggestion(
|
||||
roomAlias = A_ROOM_ALIAS,
|
||||
roomId = aRoomSummary.roomId,
|
||||
roomName = aRoomSummary.info.name,
|
||||
roomAvatarUrl = aRoomSummary.info.avatarUrl,
|
||||
)
|
||||
),
|
||||
currentUserId = A_USER_ID,
|
||||
canSendRoomMention = { true },
|
||||
)
|
||||
assertThat(result).isEqualTo(
|
||||
listOf(
|
||||
ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary)
|
||||
ResolvedSuggestion.Alias(
|
||||
roomAlias = A_ROOM_ALIAS,
|
||||
roomId = aRoomSummary.roomId,
|
||||
roomName = aRoomSummary.info.name,
|
||||
roomAvatarUrl = aRoomSummary.info.avatarUrl,
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -127,13 +138,25 @@ class SuggestionsProcessorTest {
|
|||
val result = suggestionsProcessor.process(
|
||||
suggestion = aRoomSuggestion("ali"),
|
||||
roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()),
|
||||
roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)),
|
||||
roomAliasSuggestions = listOf(
|
||||
RoomAliasSuggestion(
|
||||
roomAlias = A_ROOM_ALIAS,
|
||||
roomId = aRoomSummary.roomId,
|
||||
roomName = aRoomSummary.info.name,
|
||||
roomAvatarUrl = aRoomSummary.info.avatarUrl,
|
||||
)
|
||||
),
|
||||
currentUserId = A_USER_ID,
|
||||
canSendRoomMention = { true },
|
||||
)
|
||||
assertThat(result).isEqualTo(
|
||||
listOf(
|
||||
ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary)
|
||||
ResolvedSuggestion.Alias(
|
||||
roomAlias = A_ROOM_ALIAS,
|
||||
roomId = aRoomSummary.roomId,
|
||||
roomName = aRoomSummary.info.name,
|
||||
roomAvatarUrl = aRoomSummary.info.avatarUrl,
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -144,7 +167,14 @@ class SuggestionsProcessorTest {
|
|||
val result = suggestionsProcessor.process(
|
||||
suggestion = aRoomSuggestion("tot"),
|
||||
roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()),
|
||||
roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)),
|
||||
roomAliasSuggestions = listOf(
|
||||
RoomAliasSuggestion(
|
||||
roomAlias = A_ROOM_ALIAS,
|
||||
roomId = aRoomSummary.roomId,
|
||||
roomName = aRoomSummary.info.name,
|
||||
roomAvatarUrl = aRoomSummary.info.avatarUrl,
|
||||
)
|
||||
),
|
||||
currentUserId = A_USER_ID,
|
||||
canSendRoomMention = { true },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -21,11 +21,12 @@ import dagger.assisted.AssistedInject
|
|||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runUpdatingStateNoSuccess
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
|
|
@ -40,7 +41,6 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor(
|
|||
private val notificationSettingsService: NotificationSettingsService,
|
||||
@Assisted private val isOneToOne: Boolean,
|
||||
private val roomListService: RoomListService,
|
||||
private val matrixClient: MatrixClient,
|
||||
) : Presenter<EditDefaultNotificationSettingState> {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
|
@ -57,8 +57,8 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor(
|
|||
|
||||
val changeNotificationSettingAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
|
||||
val roomsWithUserDefinedMode: MutableState<List<RoomSummary>> = remember {
|
||||
mutableStateOf(listOf())
|
||||
val roomsWithUserDefinedMode: MutableState<List<EditNotificationSettingRoomInfo>> = remember {
|
||||
mutableStateOf(emptyList())
|
||||
}
|
||||
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
|
|
@ -106,31 +106,37 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor(
|
|||
.launchIn(this)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.observeRoomSummaries(roomsWithUserDefinedMode: MutableState<List<RoomSummary>>) {
|
||||
private fun CoroutineScope.observeRoomSummaries(roomsWithUserDefinedMode: MutableState<List<EditNotificationSettingRoomInfo>>) {
|
||||
roomListService.allRooms
|
||||
.summaries
|
||||
.onEach {
|
||||
updateRoomsWithUserDefinedMode(it, roomsWithUserDefinedMode)
|
||||
.onEach { roomSummaries ->
|
||||
updateRoomsWithUserDefinedMode(roomSummaries, roomsWithUserDefinedMode)
|
||||
}
|
||||
.launchIn(this)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.updateRoomsWithUserDefinedMode(
|
||||
private suspend fun updateRoomsWithUserDefinedMode(
|
||||
summaries: List<RoomSummary>,
|
||||
roomsWithUserDefinedMode: MutableState<List<RoomSummary>>
|
||||
) = launch {
|
||||
val roomWithUserDefinedRules: Set<String> = notificationSettingsService.getRoomsWithUserDefinedRules().getOrThrow().toSet()
|
||||
|
||||
val sortedSummaries = summaries
|
||||
.filterIsInstance<RoomSummary>()
|
||||
.filter {
|
||||
val room = matrixClient.getRoom(it.roomId) ?: return@filter false
|
||||
roomWithUserDefinedRules.contains(it.roomId.value) && isOneToOne == room.isOneToOne
|
||||
roomsWithUserDefinedMode: MutableState<List<EditNotificationSettingRoomInfo>>
|
||||
) {
|
||||
val roomWithUserDefinedRules: Set<String> = notificationSettingsService.getRoomsWithUserDefinedRules().getOrDefault(emptyList()).toSet()
|
||||
roomsWithUserDefinedMode.value = summaries
|
||||
.filter { roomSummary ->
|
||||
roomWithUserDefinedRules.contains(roomSummary.roomId.value) && roomSummary.isOneToOne == isOneToOne
|
||||
}
|
||||
.map { roomSummary ->
|
||||
EditNotificationSettingRoomInfo(
|
||||
roomId = roomSummary.roomId,
|
||||
name = roomSummary.info.name,
|
||||
heroesAvatar = roomSummary.info.heroes.map { hero ->
|
||||
hero.getAvatarData(AvatarSize.CustomRoomNotificationSetting)
|
||||
}.toImmutableList(),
|
||||
avatarData = roomSummary.info.getAvatarData(AvatarSize.CustomRoomNotificationSetting),
|
||||
notificationMode = roomSummary.info.userDefinedNotificationMode,
|
||||
)
|
||||
}
|
||||
// locale sensitive sorting
|
||||
.sortedWith(compareBy(Collator.getInstance()) { it.name })
|
||||
|
||||
roomsWithUserDefinedMode.value = sortedSummaries
|
||||
.sortedWith(compareBy(Collator.getInstance()) { roomSummary -> roomSummary.name })
|
||||
}
|
||||
|
||||
private fun CoroutineScope.setDefaultNotificationMode(mode: RoomNotificationMode, action: MutableState<AsyncAction<Unit>>) = launch {
|
||||
|
|
|
|||
|
|
@ -9,13 +9,12 @@ package io.element.android.features.preferences.impl.notifications.edit
|
|||
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class EditDefaultNotificationSettingState(
|
||||
val isOneToOne: Boolean,
|
||||
val mode: RoomNotificationMode?,
|
||||
val roomsWithUserDefinedMode: ImmutableList<RoomSummary>,
|
||||
val roomsWithUserDefinedMode: ImmutableList<EditNotificationSettingRoomInfo>,
|
||||
val changeNotificationSettingAction: AsyncAction<Unit>,
|
||||
val displayMentionsOnlyDisclaimer: Boolean,
|
||||
val eventSink: (EditDefaultNotificationSettingStateEvents) -> Unit,
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ package io.element.android.features.preferences.impl.notifications.edit
|
|||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
open class EditDefaultNotificationSettingStateProvider : PreviewParameterProvider<EditDefaultNotificationSettingState> {
|
||||
|
|
@ -33,21 +34,25 @@ private fun anEditDefaultNotificationSettingsState(
|
|||
isOneToOne = isOneToOne,
|
||||
mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
|
||||
roomsWithUserDefinedMode = persistentListOf(
|
||||
aRoomSummary("Room"),
|
||||
aRoomSummary(null),
|
||||
anEditNotificationSettingRoomInfo("Room"),
|
||||
anEditNotificationSettingRoomInfo(null),
|
||||
),
|
||||
changeNotificationSettingAction = changeNotificationSettingAction,
|
||||
displayMentionsOnlyDisclaimer = displayMentionsOnlyDisclaimer,
|
||||
eventSink = {}
|
||||
)
|
||||
|
||||
private fun aRoomSummary(
|
||||
private fun anEditNotificationSettingRoomInfo(
|
||||
name: String?,
|
||||
) = aRoomSummaryDetails(
|
||||
) = EditNotificationSettingRoomInfo(
|
||||
roomId = RoomId("!roomId:domain"),
|
||||
name = name,
|
||||
avatarUrl = null,
|
||||
isDirect = false,
|
||||
lastMessage = null,
|
||||
avatarData = AvatarData(
|
||||
id = "!roomId:domain",
|
||||
name = name,
|
||||
url = null,
|
||||
size = AvatarSize.CustomRoomNotificationSetting,
|
||||
),
|
||||
heroesAvatar = persistentListOf(),
|
||||
notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import androidx.compose.ui.text.font.FontStyle
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.features.preferences.impl.R
|
||||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.components.avatar.CompositeAvatar
|
||||
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
||||
|
|
@ -27,9 +26,7 @@ import io.element.android.libraries.designsystem.theme.components.ListItem
|
|||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
/**
|
||||
* A view that allows a user to edit the default notification setting for rooms. This can be set separately
|
||||
|
|
@ -80,7 +77,7 @@ fun EditDefaultNotificationSettingView(
|
|||
if (state.roomsWithUserDefinedMode.isNotEmpty()) {
|
||||
PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_edit_custom_settings_section_title)) {
|
||||
state.roomsWithUserDefinedMode.forEach { summary ->
|
||||
val subtitle = when (summary.userDefinedNotificationMode) {
|
||||
val subtitle = when (summary.notificationMode) {
|
||||
RoomNotificationMode.ALL_MESSAGES -> stringResource(id = R.string.screen_notification_settings_edit_mode_all_messages)
|
||||
RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> {
|
||||
stringResource(id = R.string.screen_notification_settings_edit_mode_mentions_and_keywords)
|
||||
|
|
@ -101,10 +98,8 @@ fun EditDefaultNotificationSettingView(
|
|||
},
|
||||
leadingContent = ListItemContent.Custom {
|
||||
CompositeAvatar(
|
||||
avatarData = summary.getAvatarData(size = AvatarSize.CustomRoomNotificationSetting),
|
||||
heroes = summary.heroes.map { user ->
|
||||
user.getAvatarData(size = AvatarSize.CustomRoomNotificationSetting)
|
||||
}.toPersistentList()
|
||||
avatarData = summary.avatarData,
|
||||
heroes = summary.heroesAvatar,
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.preferences.impl.notifications.edit
|
||||
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class EditNotificationSettingRoomInfo(
|
||||
val roomId: RoomId,
|
||||
val name: String?,
|
||||
val heroesAvatar: ImmutableList<AvatarData>,
|
||||
val avatarData: AvatarData,
|
||||
val notificationMode: RoomNotificationMode?
|
||||
)
|
||||
|
|
@ -14,11 +14,8 @@ import com.google.common.truth.Truth.assertThat
|
|||
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingPresenter
|
||||
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingStateEvents
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||
|
|
@ -49,24 +46,20 @@ class EditDefaultNotificationSettingsPresenterTest {
|
|||
|
||||
@Test
|
||||
fun `present - ensure list of rooms with user defined mode`() = runTest {
|
||||
val room = FakeMatrixRoom()
|
||||
val notificationSettingsService = FakeNotificationSettingsService(
|
||||
initialRoomMode = RoomNotificationMode.ALL_MESSAGES,
|
||||
initialRoomModeIsDefault = false
|
||||
)
|
||||
val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService).apply {
|
||||
givenGetRoomResult(A_ROOM_ID, room)
|
||||
}
|
||||
val roomListService = FakeRoomListService()
|
||||
val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService, matrixClient)
|
||||
val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
roomListService.postAllRooms(listOf(aRoomSummary(notificationMode = RoomNotificationMode.ALL_MESSAGES)))
|
||||
roomListService.postAllRooms(listOf(aRoomSummary(userDefinedNotificationMode = RoomNotificationMode.ALL_MESSAGES)))
|
||||
val loadedState = consumeItemsUntilPredicate { state ->
|
||||
state.roomsWithUserDefinedMode.any { it.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }
|
||||
state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.ALL_MESSAGES }
|
||||
}.last()
|
||||
assertThat(loadedState.roomsWithUserDefinedMode.any { it.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue()
|
||||
assertThat(loadedState.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,13 +114,11 @@ class EditDefaultNotificationSettingsPresenterTest {
|
|||
private fun createEditDefaultNotificationSettingPresenter(
|
||||
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||
roomListService: FakeRoomListService = FakeRoomListService(),
|
||||
matrixClient: FakeMatrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService)
|
||||
): EditDefaultNotificationSettingPresenter {
|
||||
return EditDefaultNotificationSettingPresenter(
|
||||
notificationSettingsService = notificationSettingsService,
|
||||
isOneToOne = false,
|
||||
roomListService = roomListService,
|
||||
matrixClient = matrixClient
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormat
|
|||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import io.element.android.libraries.matrix.ui.model.toInviteSender
|
||||
|
|
@ -24,34 +25,35 @@ class RoomListRoomSummaryFactory @Inject constructor(
|
|||
private val lastMessageTimestampFormatter: LastMessageTimestampFormatter,
|
||||
private val roomLastMessageFormatter: RoomLastMessageFormatter,
|
||||
) {
|
||||
fun create(details: RoomSummary): RoomListRoomSummary {
|
||||
val avatarData = details.getAvatarData(size = AvatarSize.RoomListItem)
|
||||
fun create(roomSummary: RoomSummary): RoomListRoomSummary {
|
||||
val roomInfo = roomSummary.info
|
||||
val avatarData = roomInfo.getAvatarData(size = AvatarSize.RoomListItem)
|
||||
return RoomListRoomSummary(
|
||||
id = details.roomId.value,
|
||||
roomId = details.roomId,
|
||||
name = details.name,
|
||||
numberOfUnreadMessages = details.numUnreadMessages,
|
||||
numberOfUnreadMentions = details.numUnreadMentions,
|
||||
numberOfUnreadNotifications = details.numUnreadNotifications,
|
||||
isMarkedUnread = details.isMarkedUnread,
|
||||
timestamp = lastMessageTimestampFormatter.format(details.lastMessageTimestamp),
|
||||
lastMessage = details.lastMessage?.let { message ->
|
||||
roomLastMessageFormatter.format(message.event, details.isDm)
|
||||
id = roomSummary.roomId.value,
|
||||
roomId = roomSummary.roomId,
|
||||
name = roomInfo.name,
|
||||
numberOfUnreadMessages = roomInfo.numUnreadMessages,
|
||||
numberOfUnreadMentions = roomInfo.numUnreadMentions,
|
||||
numberOfUnreadNotifications = roomInfo.numUnreadNotifications,
|
||||
isMarkedUnread = roomInfo.isMarkedUnread,
|
||||
timestamp = lastMessageTimestampFormatter.format(roomSummary.lastMessageTimestamp),
|
||||
lastMessage = roomSummary.lastMessage?.let { message ->
|
||||
roomLastMessageFormatter.format(message.event, roomInfo.isDm)
|
||||
}.orEmpty(),
|
||||
avatarData = avatarData,
|
||||
userDefinedNotificationMode = details.userDefinedNotificationMode,
|
||||
hasRoomCall = details.hasRoomCall,
|
||||
isDirect = details.isDirect,
|
||||
isFavorite = details.isFavorite,
|
||||
inviteSender = details.inviter?.toInviteSender(),
|
||||
isDm = details.isDm,
|
||||
canonicalAlias = details.canonicalAlias,
|
||||
displayType = if (details.currentUserMembership == CurrentUserMembership.INVITED) {
|
||||
userDefinedNotificationMode = roomInfo.userDefinedNotificationMode,
|
||||
hasRoomCall = roomInfo.hasRoomCall,
|
||||
isDirect = roomInfo.isDirect,
|
||||
isFavorite = roomInfo.isFavorite,
|
||||
inviteSender = roomInfo.inviter?.toInviteSender(),
|
||||
isDm = roomInfo.isDm,
|
||||
canonicalAlias = roomInfo.canonicalAlias,
|
||||
displayType = if (roomInfo.currentUserMembership == CurrentUserMembership.INVITED) {
|
||||
RoomSummaryDisplayType.INVITE
|
||||
} else {
|
||||
RoomSummaryDisplayType.ROOM
|
||||
},
|
||||
heroes = details.heroes.map { user ->
|
||||
heroes = roomInfo.heroes.map { user ->
|
||||
user.getAvatarData(size = AvatarSize.RoomListItem)
|
||||
}.toImmutableList(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ data class RoomListRoomSummary(
|
|||
val roomId: RoomId,
|
||||
val name: String?,
|
||||
val canonicalAlias: RoomAlias?,
|
||||
val numberOfUnreadMessages: Int,
|
||||
val numberOfUnreadMentions: Int,
|
||||
val numberOfUnreadNotifications: Int,
|
||||
val numberOfUnreadMessages: Long,
|
||||
val numberOfUnreadMentions: Long,
|
||||
val numberOfUnreadNotifications: Long,
|
||||
val isMarkedUnread: Boolean,
|
||||
val timestamp: String?,
|
||||
val lastMessage: CharSequence?,
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@ internal fun anInviteSender(
|
|||
internal fun aRoomListRoomSummary(
|
||||
id: String = "!roomId:domain",
|
||||
name: String? = "Room name",
|
||||
numberOfUnreadMessages: Int = 0,
|
||||
numberOfUnreadMentions: Int = 0,
|
||||
numberOfUnreadNotifications: Int = 0,
|
||||
numberOfUnreadMessages: Long = 0,
|
||||
numberOfUnreadMentions: Long = 0,
|
||||
numberOfUnreadNotifications: Long = 0,
|
||||
isMarkedUnread: Boolean = false,
|
||||
lastMessage: String? = "Last message",
|
||||
timestamp: String? = lastMessage?.let { "88:88" },
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@ class RoomListPresenterTest {
|
|||
val notificationSettingsService = FakeNotificationSettingsService()
|
||||
val roomListService = FakeRoomListService()
|
||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
||||
roomListService.postAllRooms(listOf(aRoomSummary(notificationMode = userDefinedMode)))
|
||||
roomListService.postAllRooms(listOf(aRoomSummary(userDefinedNotificationMode = userDefinedMode)))
|
||||
val matrixClient = FakeMatrixClient(
|
||||
roomListService = roomListService,
|
||||
notificationSettingsService = notificationSettingsService
|
||||
|
|
|
|||
|
|
@ -76,9 +76,9 @@ class RoomListRoomSummaryTest {
|
|||
}
|
||||
|
||||
internal fun createRoomListRoomSummary(
|
||||
numberOfUnreadMentions: Int = 0,
|
||||
numberOfUnreadMessages: Int = 0,
|
||||
numberOfUnreadNotifications: Int = 0,
|
||||
numberOfUnreadMentions: Long = 0,
|
||||
numberOfUnreadMessages: Long = 0,
|
||||
numberOfUnreadNotifications: Long = 0,
|
||||
isMarkedUnread: Boolean = false,
|
||||
userDefinedNotificationMode: RoomNotificationMode? = null,
|
||||
isFavorite: Boolean = false,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.io.Closeable
|
||||
import java.util.Optional
|
||||
|
||||
|
|
@ -94,7 +96,13 @@ interface MatrixClient : Closeable {
|
|||
suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?>
|
||||
suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String>
|
||||
fun roomMembershipObserver(): RoomMembershipObserver
|
||||
fun getRoomInfoFlow(roomId: RoomId): Flow<Optional<MatrixRoomInfo>>
|
||||
|
||||
/**
|
||||
* Get a room summary flow for a given room ID or alias.
|
||||
* The flow will emit a new value whenever the room summary is updated.
|
||||
* The flow will emit Optional.empty item if the room is not found.
|
||||
*/
|
||||
fun getRoomSummaryFlow(roomIdOrAlias: RoomIdOrAlias): Flow<Optional<RoomSummary>>
|
||||
|
||||
fun isMe(userId: UserId?) = userId == sessionId
|
||||
|
||||
|
|
@ -142,3 +150,14 @@ interface MatrixClient : Closeable {
|
|||
fun canDeactivateAccount(): Boolean
|
||||
suspend fun deactivateAccount(password: String, eraseData: Boolean): Result<Unit>
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a room info flow for a given room ID or alias.
|
||||
* The flow will emit a new value whenever the room info is updated.
|
||||
* The flow will emit Optional.empty item if the room is not found.
|
||||
*/
|
||||
fun MatrixClient.getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias): Flow<Optional<MatrixRoomInfo>> {
|
||||
return getRoomSummaryFlow(roomIdOrAlias)
|
||||
.map { roomSummary -> roomSummary.map { it.info } }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,13 @@ data class MatrixRoomInfo(
|
|||
val canonicalAlias: RoomAlias?,
|
||||
val alternativeAliases: ImmutableList<RoomAlias>,
|
||||
val currentUserMembership: CurrentUserMembership,
|
||||
/**
|
||||
* Member who invited the current user to a room that's in the invited
|
||||
* state.
|
||||
*
|
||||
* Can be missing if the room membership invite event is missing from the
|
||||
* store.
|
||||
*/
|
||||
val inviter: RoomMember?,
|
||||
val activeMembersCount: Long,
|
||||
val invitedMembersCount: Long,
|
||||
|
|
@ -43,7 +50,26 @@ data class MatrixRoomInfo(
|
|||
val userDefinedNotificationMode: RoomNotificationMode?,
|
||||
val hasRoomCall: Boolean,
|
||||
val activeRoomCallParticipants: ImmutableList<UserId>,
|
||||
val isMarkedUnread: Boolean,
|
||||
/**
|
||||
* "Interesting" messages received in that room, independently of the
|
||||
* notification settings.
|
||||
*/
|
||||
val numUnreadMessages: Long,
|
||||
/**
|
||||
* Events that will notify the user, according to their
|
||||
* notification settings.
|
||||
*/
|
||||
val numUnreadNotifications: Long,
|
||||
/**
|
||||
* Events causing mentions/highlights for the user, according to their
|
||||
* notification settings.
|
||||
*/
|
||||
val numUnreadMentions: Long,
|
||||
val heroes: ImmutableList<MatrixUser>,
|
||||
val pinnedEventIds: ImmutableList<EventId>,
|
||||
val creator: UserId?,
|
||||
)
|
||||
) {
|
||||
val aliases: List<RoomAlias>
|
||||
get() = listOfNotNull(canonicalAlias) + alternativeAliases
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,35 +7,14 @@
|
|||
|
||||
package io.element.android.libraries.matrix.api.roomlist
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
data class RoomSummary(
|
||||
val roomId: RoomId,
|
||||
val name: String?,
|
||||
val canonicalAlias: RoomAlias?,
|
||||
val alternativeAliases: List<RoomAlias>,
|
||||
val isDirect: Boolean,
|
||||
val avatarUrl: String?,
|
||||
val info: MatrixRoomInfo,
|
||||
val lastMessage: RoomMessage?,
|
||||
val numUnreadMessages: Int,
|
||||
val numUnreadMentions: Int,
|
||||
val numUnreadNotifications: Int,
|
||||
val isMarkedUnread: Boolean,
|
||||
val inviter: RoomMember?,
|
||||
val userDefinedNotificationMode: RoomNotificationMode?,
|
||||
val hasRoomCall: Boolean,
|
||||
val isDm: Boolean,
|
||||
val isFavorite: Boolean,
|
||||
val currentUserMembership: CurrentUserMembership,
|
||||
val heroes: List<MatrixUser>,
|
||||
) {
|
||||
val roomId = info.id
|
||||
val lastMessageTimestamp = lastMessage?.originServerTs
|
||||
val aliases: List<RoomAlias>
|
||||
get() = listOfNotNull(canonicalAlias) + alternativeAliases
|
||||
val isOneToOne get() = info.activeMembersCount == 2L
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
|
|||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.InvitedRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
|
||||
|
|
@ -84,8 +83,8 @@ import kotlinx.coroutines.flow.buffer
|
|||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
|
@ -105,8 +104,8 @@ import org.matrix.rustcomponents.sdk.use
|
|||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.util.Optional
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.INFINITE
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import org.matrix.rustcomponents.sdk.CreateRoomParameters as RustCreateRoomParameters
|
||||
import org.matrix.rustcomponents.sdk.RoomPreset as RustRoomPreset
|
||||
|
|
@ -262,21 +261,14 @@ class RustMatrixClient(
|
|||
* @param timeout the timeout to wait for the room to be available
|
||||
* @throws TimeoutCancellationException if the room is not available after the timeout
|
||||
*/
|
||||
private suspend fun awaitJoinedRoom(roomIdOrAlias: RoomIdOrAlias, timeout: Duration): RoomSummary {
|
||||
val predicate: (List<RoomSummary>) -> Boolean = when (roomIdOrAlias) {
|
||||
is RoomIdOrAlias.Alias -> { roomSummaries: List<RoomSummary> ->
|
||||
val found = roomSummaries.find { it.aliases.contains(roomIdOrAlias.roomAlias) }
|
||||
found != null && found.currentUserMembership == CurrentUserMembership.JOINED
|
||||
}
|
||||
is RoomIdOrAlias.Id -> { roomSummaries: List<RoomSummary> ->
|
||||
val found = roomSummaries.find { it.roomId == roomIdOrAlias.roomId }
|
||||
found != null && found.currentUserMembership == CurrentUserMembership.JOINED
|
||||
}
|
||||
}
|
||||
private suspend fun awaitJoinedRoom(
|
||||
roomIdOrAlias: RoomIdOrAlias,
|
||||
timeout: Duration
|
||||
): RoomSummary {
|
||||
return withTimeout(timeout) {
|
||||
roomListService.allRooms.summaries
|
||||
.filter(predicate)
|
||||
.first()
|
||||
getRoomSummaryFlow(roomIdOrAlias)
|
||||
.mapNotNull { optionalRoomSummary -> optionalRoomSummary.getOrNull() }
|
||||
.filter { roomSummary -> roomSummary.info.currentUserMembership == CurrentUserMembership.JOINED }
|
||||
.first()
|
||||
// Ensure that the room is ready
|
||||
.also { client.awaitRoomRemoteEcho(it.roomId.value) }
|
||||
|
|
@ -568,20 +560,21 @@ class RustMatrixClient(
|
|||
|
||||
override fun roomMembershipObserver(): RoomMembershipObserver = roomMembershipObserver
|
||||
|
||||
override fun getRoomInfoFlow(roomId: RoomId): Flow<Optional<MatrixRoomInfo>> {
|
||||
return flow {
|
||||
var room = getRoom(roomId)
|
||||
if (room == null) {
|
||||
emit(Optional.empty())
|
||||
awaitJoinedRoom(roomId.toRoomIdOrAlias(), INFINITE)
|
||||
room = getRoom(roomId)
|
||||
override fun getRoomSummaryFlow(roomIdOrAlias: RoomIdOrAlias): Flow<Optional<RoomSummary>> {
|
||||
val predicate: (RoomSummary) -> Boolean = when (roomIdOrAlias) {
|
||||
is RoomIdOrAlias.Alias -> { roomSummary ->
|
||||
roomSummary.info.aliases.contains(roomIdOrAlias.roomAlias)
|
||||
}
|
||||
room?.use {
|
||||
room.roomInfoFlow
|
||||
.map { roomInfo -> Optional.of(roomInfo) }
|
||||
.collect(this)
|
||||
is RoomIdOrAlias.Id -> { roomSummary ->
|
||||
roomSummary.roomId == roomIdOrAlias.roomId
|
||||
}
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
return roomListService.allRooms.summaries
|
||||
.map { roomSummaries ->
|
||||
val roomSummary = roomSummaries.firstOrNull(predicate)
|
||||
Optional.ofNullable(roomSummary)
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override suspend fun setAllSendQueuesEnabled(enabled: Boolean) = withContext(sessionDispatcher) {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@ class MatrixRoomInfoMapper {
|
|||
activeRoomCallParticipants = it.activeRoomCallParticipants.map(::UserId).toImmutableList(),
|
||||
heroes = it.elementHeroes().toImmutableList(),
|
||||
pinnedEventIds = it.pinnedEventIds.map(::EventId).toImmutableList(),
|
||||
isMarkedUnread = it.isMarkedUnread,
|
||||
numUnreadMessages = it.numUnreadMessages.toLong(),
|
||||
numUnreadMentions = it.numUnreadMentions.toLong(),
|
||||
numUnreadNotifications = it.numUnreadNotifications.toLong(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ internal class RoomListFactory(
|
|||
private val innerRoomListService: RoomListService,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
) {
|
||||
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory()
|
||||
private val roomSummaryDetailsFactory: RoomSummaryFactory = RoomSummaryFactory()
|
||||
|
||||
/**
|
||||
* Creates a room list that can be used to load more rooms and filter them dynamically.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
package io.element.android.libraries.matrix.impl.roomlist
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
|
||||
|
|
@ -17,19 +18,19 @@ val RoomListFilter.predicate
|
|||
is RoomListFilter.Any -> { _: RoomSummary -> true }
|
||||
RoomListFilter.None -> { _: RoomSummary -> false }
|
||||
RoomListFilter.Category.Group -> { roomSummary: RoomSummary ->
|
||||
!roomSummary.isDm && !roomSummary.isInvited()
|
||||
!roomSummary.info.isDm && !roomSummary.isInvited()
|
||||
}
|
||||
RoomListFilter.Category.People -> { roomSummary: RoomSummary ->
|
||||
roomSummary.isDm && !roomSummary.isInvited()
|
||||
roomSummary.info.isDm && !roomSummary.isInvited()
|
||||
}
|
||||
RoomListFilter.Favorite -> { roomSummary: RoomSummary ->
|
||||
roomSummary.isFavorite && !roomSummary.isInvited()
|
||||
roomSummary.info.isFavorite && !roomSummary.isInvited()
|
||||
}
|
||||
RoomListFilter.Unread -> { roomSummary: RoomSummary ->
|
||||
!roomSummary.isInvited() && (roomSummary.numUnreadNotifications > 0 || roomSummary.isMarkedUnread)
|
||||
!roomSummary.isInvited() && (roomSummary.info.numUnreadNotifications > 0 || roomSummary.info.isMarkedUnread)
|
||||
}
|
||||
is RoomListFilter.NormalizedMatchRoomName -> { roomSummary: RoomSummary ->
|
||||
roomSummary.name.orEmpty().contains(pattern, ignoreCase = true)
|
||||
roomSummary.info.name.orEmpty().contains(pattern, ignoreCase = true)
|
||||
}
|
||||
RoomListFilter.Invite -> { roomSummary: RoomSummary ->
|
||||
roomSummary.isInvited()
|
||||
|
|
@ -50,4 +51,4 @@ fun List<RoomSummary>.filter(filter: RoomListFilter): List<RoomSummary> {
|
|||
}
|
||||
}
|
||||
|
||||
private fun RoomSummary.isInvited() = currentUserMembership == CurrentUserMembership.INVITED
|
||||
private fun RoomSummary.isInvited() = info.currentUserMembership == CurrentUserMembership.INVITED
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.roomlist
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.impl.notificationsettings.RoomNotificationSettingsMapper
|
||||
import io.element.android.libraries.matrix.impl.room.elementHeroes
|
||||
import io.element.android.libraries.matrix.impl.room.map
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
|
||||
import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory
|
||||
import org.matrix.rustcomponents.sdk.RoomListItem
|
||||
import org.matrix.rustcomponents.sdk.use
|
||||
|
||||
class RoomSummaryDetailsFactory(
|
||||
private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory(),
|
||||
) {
|
||||
suspend fun create(roomListItem: RoomListItem): RoomSummary {
|
||||
val roomInfo = roomListItem.roomInfo()
|
||||
val latestRoomMessage = roomListItem.latestEvent().use { event ->
|
||||
roomMessageFactory.create(event)
|
||||
}
|
||||
return RoomSummary(
|
||||
roomId = RoomId(roomInfo.id),
|
||||
name = roomInfo.displayName,
|
||||
canonicalAlias = roomInfo.canonicalAlias?.let(::RoomAlias),
|
||||
alternativeAliases = roomInfo.alternativeAliases.map(::RoomAlias),
|
||||
isDirect = roomInfo.isDirect,
|
||||
avatarUrl = roomInfo.avatarUrl,
|
||||
numUnreadMentions = roomInfo.numUnreadMentions.toInt(),
|
||||
numUnreadMessages = roomInfo.numUnreadMessages.toInt(),
|
||||
numUnreadNotifications = roomInfo.numUnreadNotifications.toInt(),
|
||||
isMarkedUnread = roomInfo.isMarkedUnread,
|
||||
lastMessage = latestRoomMessage,
|
||||
inviter = roomInfo.inviter?.let(RoomMemberMapper::map),
|
||||
userDefinedNotificationMode = roomInfo.cachedUserDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode),
|
||||
hasRoomCall = roomInfo.hasRoomCall,
|
||||
isDm = isDm(isDirect = roomInfo.isDirect, activeMembersCount = roomInfo.activeMembersCount.toInt()),
|
||||
isFavorite = roomInfo.isFavourite,
|
||||
currentUserMembership = roomInfo.membership.map(),
|
||||
heroes = roomInfo.elementHeroes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.roomlist
|
||||
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.impl.room.MatrixRoomInfoMapper
|
||||
import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory
|
||||
import org.matrix.rustcomponents.sdk.RoomListItem
|
||||
import org.matrix.rustcomponents.sdk.use
|
||||
|
||||
class RoomSummaryFactory(
|
||||
private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory(),
|
||||
private val roomInfoMapper: MatrixRoomInfoMapper = MatrixRoomInfoMapper(),
|
||||
) {
|
||||
suspend fun create(roomListItem: RoomListItem): RoomSummary {
|
||||
val roomInfo = roomListItem.roomInfo().let(roomInfoMapper::map)
|
||||
val latestRoomMessage = roomListItem.latestEvent().use { event ->
|
||||
roomMessageFactory.create(event)
|
||||
}
|
||||
return RoomSummary(
|
||||
info = roomInfo,
|
||||
lastMessage = latestRoomMessage,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ class RoomSummaryListProcessor(
|
|||
private val roomSummaries: MutableSharedFlow<List<RoomSummary>>,
|
||||
private val roomListService: RoomListServiceInterface,
|
||||
private val coroutineContext: CoroutineContext,
|
||||
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
|
||||
private val roomSummaryDetailsFactory: RoomSummaryFactory = RoomSummaryFactory(),
|
||||
) {
|
||||
private val roomSummariesByIdentifier = HashMap<String, RoomSummary>()
|
||||
private val mutex = Mutex()
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ class MatrixRoomInfoMapperTest {
|
|||
).toImmutableList(),
|
||||
pinnedEventIds = listOf(AN_EVENT_ID).toPersistentList(),
|
||||
creator = A_USER_ID,
|
||||
isMarkedUnread = false,
|
||||
numUnreadMessages = 12L,
|
||||
numUnreadNotifications = 13L,
|
||||
numUnreadMentions = 14L,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -174,6 +178,10 @@ class MatrixRoomInfoMapperTest {
|
|||
heroes = emptyList<MatrixUser>().toImmutableList(),
|
||||
pinnedEventIds = emptyList<EventId>().toPersistentList(),
|
||||
creator = null,
|
||||
isMarkedUnread = true,
|
||||
numUnreadMessages = 12L,
|
||||
numUnreadNotifications = 13L,
|
||||
numUnreadMentions = 14L,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
|||
import io.element.android.libraries.matrix.test.A_SERVER_LIST
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
|
|
@ -29,7 +29,7 @@ import org.junit.Test
|
|||
class DefaultJoinRoomTest {
|
||||
@Test
|
||||
fun `when using roomId and there is no server names, the classic join room API is used`() = runTest {
|
||||
val roomSummary = aRoomSummaryFilled()
|
||||
val roomSummary = aRoomSummary()
|
||||
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
|
||||
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
|
||||
val roomResult = FakeMatrixRoom()
|
||||
|
|
@ -64,7 +64,7 @@ class DefaultJoinRoomTest {
|
|||
|
||||
@Test
|
||||
fun `when using roomId and server names are available, joinRoomByIdOrAlias API is used`() = runTest {
|
||||
val roomSummary = aRoomSummaryFilled()
|
||||
val roomSummary = aRoomSummary()
|
||||
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
|
||||
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
|
||||
val roomResult = FakeMatrixRoom()
|
||||
|
|
@ -100,7 +100,7 @@ class DefaultJoinRoomTest {
|
|||
|
||||
@Test
|
||||
fun `when using roomAlias, joinRoomByIdOrAlias API is used`() = runTest {
|
||||
val roomSummary = aRoomSummaryFilled()
|
||||
val roomSummary = aRoomSummary()
|
||||
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
|
||||
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
|
||||
val roomResult = FakeMatrixRoom()
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@ import org.junit.Test
|
|||
|
||||
class RoomListFilterTest {
|
||||
private val regularRoom = aRoomSummary(
|
||||
isDm = false
|
||||
isDirect = false,
|
||||
)
|
||||
private val dmRoom = aRoomSummary(
|
||||
isDm = true
|
||||
isDirect = true,
|
||||
activeMembersCount = 2
|
||||
)
|
||||
private val favoriteRoom = aRoomSummary(
|
||||
isFavorite = true
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
|||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_3
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
|
|
@ -40,7 +39,7 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `PushBack adds a new entry at the end of the list`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled())
|
||||
summaries.value = listOf(aRoomSummary())
|
||||
val processor = createProcessor()
|
||||
processor.postUpdate(listOf(RoomListEntriesUpdate.PushBack(FakeRustRoomListItem(A_ROOM_ID_2))))
|
||||
|
||||
|
|
@ -50,7 +49,7 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `PushFront inserts a new entry at the start of the list`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled())
|
||||
summaries.value = listOf(aRoomSummary())
|
||||
val processor = createProcessor()
|
||||
processor.postUpdate(listOf(RoomListEntriesUpdate.PushFront(FakeRustRoomListItem(A_ROOM_ID_2))))
|
||||
|
||||
|
|
@ -60,7 +59,7 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `Set replaces an entry at some index`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled())
|
||||
summaries.value = listOf(aRoomSummary())
|
||||
val processor = createProcessor()
|
||||
val index = 0
|
||||
|
||||
|
|
@ -72,7 +71,7 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `Insert inserts a new entry at the provided index`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled())
|
||||
summaries.value = listOf(aRoomSummary())
|
||||
val processor = createProcessor()
|
||||
val index = 0
|
||||
|
||||
|
|
@ -84,7 +83,10 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `Remove removes an entry at some index`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2))
|
||||
summaries.value = listOf(
|
||||
aRoomSummary(roomId = A_ROOM_ID),
|
||||
aRoomSummary(A_ROOM_ID_2)
|
||||
)
|
||||
val processor = createProcessor()
|
||||
val index = 0
|
||||
|
||||
|
|
@ -96,7 +98,10 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `PopBack removes an entry at the end of the list`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2))
|
||||
summaries.value = listOf(
|
||||
aRoomSummary(roomId = A_ROOM_ID),
|
||||
aRoomSummary(A_ROOM_ID_2)
|
||||
)
|
||||
val processor = createProcessor()
|
||||
val index = 0
|
||||
|
||||
|
|
@ -108,7 +113,10 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `PopFront removes an entry at the start of the list`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2))
|
||||
summaries.value = listOf(
|
||||
aRoomSummary(roomId = A_ROOM_ID),
|
||||
aRoomSummary(A_ROOM_ID_2)
|
||||
)
|
||||
val processor = createProcessor()
|
||||
val index = 0
|
||||
|
||||
|
|
@ -120,7 +128,10 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `Clear removes all the entries`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2))
|
||||
summaries.value = listOf(
|
||||
aRoomSummary(roomId = A_ROOM_ID),
|
||||
aRoomSummary(A_ROOM_ID_2)
|
||||
)
|
||||
val processor = createProcessor()
|
||||
|
||||
processor.postUpdate(listOf(RoomListEntriesUpdate.Clear))
|
||||
|
|
@ -130,7 +141,10 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `Truncate removes all entries after the provided length`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2))
|
||||
summaries.value = listOf(
|
||||
aRoomSummary(roomId = A_ROOM_ID),
|
||||
aRoomSummary(A_ROOM_ID_2)
|
||||
)
|
||||
val processor = createProcessor()
|
||||
val index = 0
|
||||
|
||||
|
|
@ -142,7 +156,10 @@ class RoomSummaryListProcessorTest {
|
|||
|
||||
@Test
|
||||
fun `Reset removes all entries and add the provided ones`() = runTest {
|
||||
summaries.value = listOf(aRoomSummaryFilled(roomId = A_ROOM_ID), aRoomSummaryFilled(A_ROOM_ID_2))
|
||||
summaries.value = listOf(
|
||||
aRoomSummary(roomId = A_ROOM_ID),
|
||||
aRoomSummary(A_ROOM_ID_2)
|
||||
)
|
||||
val processor = createProcessor()
|
||||
val index = 0
|
||||
|
||||
|
|
@ -156,6 +173,6 @@ class RoomSummaryListProcessorTest {
|
|||
summaries,
|
||||
FakeRustRoomListService(),
|
||||
coroutineContext = StandardTestDispatcher(testScheduler),
|
||||
roomSummaryDetailsFactory = RoomSummaryDetailsFactory(),
|
||||
roomSummaryDetailsFactory = RoomSummaryFactory(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
|||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.InvitedRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
|
||||
|
|
@ -118,8 +117,8 @@ class FakeMatrixClient(
|
|||
var knockRoomLambda: (RoomId) -> Result<Unit> = {
|
||||
Result.success(Unit)
|
||||
}
|
||||
var getRoomInfoFlowLambda = { _: RoomId ->
|
||||
flowOf<Optional<MatrixRoomInfo>>(Optional.empty())
|
||||
var getRoomSummaryFlowLambda = { _: RoomIdOrAlias ->
|
||||
flowOf<Optional<RoomSummary>>(Optional.empty())
|
||||
}
|
||||
var logoutLambda: (Boolean, Boolean) -> String? = { _, _ ->
|
||||
null
|
||||
|
|
@ -316,7 +315,7 @@ class FakeMatrixClient(
|
|||
return Result.success(visitedRoomsId)
|
||||
}
|
||||
|
||||
override fun getRoomInfoFlow(roomId: RoomId) = getRoomInfoFlowLambda(roomId)
|
||||
override fun getRoomSummaryFlow(roomIdOrAlias: RoomIdOrAlias) = getRoomSummaryFlowLambda(roomIdOrAlias)
|
||||
|
||||
var setAllSendQueuesEnabledLambda = lambdaRecorder(ensureNeverCalled = true) { _: Boolean ->
|
||||
// no-op
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
|||
import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.IntentionalMention
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
|
|
@ -32,7 +31,6 @@ import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
|||
import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
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.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
|
|
@ -40,21 +38,15 @@ import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerL
|
|||
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler
|
||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -527,62 +519,6 @@ class FakeMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
fun aRoomInfo(
|
||||
id: RoomId = A_ROOM_ID,
|
||||
name: String? = A_ROOM_NAME,
|
||||
rawName: String? = name,
|
||||
topic: String? = "A topic",
|
||||
avatarUrl: String? = AN_AVATAR_URL,
|
||||
isDirect: Boolean = false,
|
||||
isPublic: Boolean = true,
|
||||
isSpace: Boolean = false,
|
||||
isTombstoned: Boolean = false,
|
||||
isFavorite: Boolean = false,
|
||||
canonicalAlias: RoomAlias? = null,
|
||||
alternativeAliases: List<RoomAlias> = emptyList(),
|
||||
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
|
||||
inviter: RoomMember? = null,
|
||||
activeMembersCount: Long = 1,
|
||||
invitedMembersCount: Long = 0,
|
||||
joinedMembersCount: Long = 1,
|
||||
highlightCount: Long = 0,
|
||||
notificationCount: Long = 0,
|
||||
userDefinedNotificationMode: RoomNotificationMode? = null,
|
||||
hasRoomCall: Boolean = false,
|
||||
userPowerLevels: ImmutableMap<UserId, Long> = persistentMapOf(),
|
||||
activeRoomCallParticipants: List<UserId> = emptyList(),
|
||||
heroes: List<MatrixUser> = emptyList(),
|
||||
pinnedEventIds: List<EventId> = emptyList(),
|
||||
roomCreator: UserId? = null,
|
||||
) = MatrixRoomInfo(
|
||||
id = id,
|
||||
name = name,
|
||||
rawName = rawName,
|
||||
topic = topic,
|
||||
avatarUrl = avatarUrl,
|
||||
isDirect = isDirect,
|
||||
isPublic = isPublic,
|
||||
isSpace = isSpace,
|
||||
isTombstoned = isTombstoned,
|
||||
isFavorite = isFavorite,
|
||||
canonicalAlias = canonicalAlias,
|
||||
alternativeAliases = alternativeAliases.toImmutableList(),
|
||||
currentUserMembership = currentUserMembership,
|
||||
inviter = inviter,
|
||||
activeMembersCount = activeMembersCount,
|
||||
invitedMembersCount = invitedMembersCount,
|
||||
joinedMembersCount = joinedMembersCount,
|
||||
highlightCount = highlightCount,
|
||||
notificationCount = notificationCount,
|
||||
userDefinedNotificationMode = userDefinedNotificationMode,
|
||||
hasRoomCall = hasRoomCall,
|
||||
userPowerLevels = userPowerLevels,
|
||||
activeRoomCallParticipants = activeRoomCallParticipants.toImmutableList(),
|
||||
heroes = heroes.toImmutableList(),
|
||||
pinnedEventIds = pinnedEventIds.toImmutableList(),
|
||||
creator = roomCreator,
|
||||
)
|
||||
|
||||
fun defaultRoomPowerLevels() = MatrixRoomPowerLevels(
|
||||
ban = 50,
|
||||
invite = 0,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.test.room
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_RAW_NAME
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
fun aRoomInfo(
|
||||
id: RoomId = A_ROOM_ID,
|
||||
name: String? = A_ROOM_NAME,
|
||||
rawName: String? = A_ROOM_RAW_NAME,
|
||||
topic: String? = A_ROOM_TOPIC,
|
||||
avatarUrl: String? = AN_AVATAR_URL,
|
||||
isDirect: Boolean = false,
|
||||
isPublic: Boolean = true,
|
||||
isSpace: Boolean = false,
|
||||
isTombstoned: Boolean = false,
|
||||
isFavorite: Boolean = false,
|
||||
canonicalAlias: RoomAlias? = null,
|
||||
alternativeAliases: List<RoomAlias> = emptyList(),
|
||||
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
|
||||
inviter: RoomMember? = null,
|
||||
activeMembersCount: Long = 1,
|
||||
invitedMembersCount: Long = 0,
|
||||
joinedMembersCount: Long = 1,
|
||||
highlightCount: Long = 0,
|
||||
notificationCount: Long = 0,
|
||||
userDefinedNotificationMode: RoomNotificationMode? = null,
|
||||
hasRoomCall: Boolean = false,
|
||||
userPowerLevels: ImmutableMap<UserId, Long> = persistentMapOf(),
|
||||
activeRoomCallParticipants: List<UserId> = emptyList(),
|
||||
heroes: List<MatrixUser> = emptyList(),
|
||||
pinnedEventIds: List<EventId> = emptyList(),
|
||||
roomCreator: UserId? = null,
|
||||
isMarkedUnread: Boolean = false,
|
||||
numUnreadMessages: Long = 0,
|
||||
numUnreadNotifications: Long = 0,
|
||||
numUnreadMentions: Long = 0,
|
||||
) = MatrixRoomInfo(
|
||||
id = id,
|
||||
name = name,
|
||||
rawName = rawName,
|
||||
topic = topic,
|
||||
avatarUrl = avatarUrl,
|
||||
isDirect = isDirect,
|
||||
isPublic = isPublic,
|
||||
isSpace = isSpace,
|
||||
isTombstoned = isTombstoned,
|
||||
isFavorite = isFavorite,
|
||||
canonicalAlias = canonicalAlias,
|
||||
alternativeAliases = alternativeAliases.toImmutableList(),
|
||||
currentUserMembership = currentUserMembership,
|
||||
inviter = inviter,
|
||||
activeMembersCount = activeMembersCount,
|
||||
invitedMembersCount = invitedMembersCount,
|
||||
joinedMembersCount = joinedMembersCount,
|
||||
highlightCount = highlightCount,
|
||||
notificationCount = notificationCount,
|
||||
userDefinedNotificationMode = userDefinedNotificationMode,
|
||||
hasRoomCall = hasRoomCall,
|
||||
userPowerLevels = userPowerLevels,
|
||||
activeRoomCallParticipants = activeRoomCallParticipants.toImmutableList(),
|
||||
heroes = heroes.toImmutableList(),
|
||||
pinnedEventIds = pinnedEventIds.toImmutableList(),
|
||||
creator = roomCreator,
|
||||
isMarkedUnread = isMarkedUnread,
|
||||
numUnreadMessages = numUnreadMessages,
|
||||
numUnreadNotifications = numUnreadNotifications,
|
||||
numUnreadMentions = numUnreadMentions,
|
||||
)
|
||||
|
|
@ -12,6 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||
|
|
@ -21,69 +22,88 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
|
|||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_RAW_NAME
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
fun aRoomSummaryFilled(
|
||||
roomId: RoomId = A_ROOM_ID,
|
||||
name: String = A_ROOM_NAME,
|
||||
isDirect: Boolean = false,
|
||||
avatarUrl: String? = null,
|
||||
fun aRoomSummary(
|
||||
info: MatrixRoomInfo = aRoomInfo(),
|
||||
lastMessage: RoomMessage? = aRoomMessage(),
|
||||
numUnreadMentions: Int = 0,
|
||||
numUnreadMessages: Int = 0,
|
||||
notificationMode: RoomNotificationMode? = null,
|
||||
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
|
||||
) = aRoomSummary(
|
||||
roomId = roomId,
|
||||
name = name,
|
||||
isDirect = isDirect,
|
||||
avatarUrl = avatarUrl,
|
||||
) = RoomSummary(
|
||||
info = info,
|
||||
lastMessage = lastMessage,
|
||||
numUnreadMentions = numUnreadMentions,
|
||||
numUnreadMessages = numUnreadMessages,
|
||||
notificationMode = notificationMode,
|
||||
currentUserMembership = currentUserMembership,
|
||||
)
|
||||
|
||||
fun aRoomSummary(
|
||||
roomId: RoomId = A_ROOM_ID,
|
||||
name: String? = A_ROOM_NAME,
|
||||
isDirect: Boolean = false,
|
||||
rawName: String? = A_ROOM_RAW_NAME,
|
||||
topic: String? = A_ROOM_TOPIC,
|
||||
avatarUrl: String? = null,
|
||||
lastMessage: RoomMessage? = aRoomMessage(),
|
||||
numUnreadMentions: Int = 0,
|
||||
numUnreadMessages: Int = 0,
|
||||
numUnreadNotifications: Int = 0,
|
||||
isMarkedUnread: Boolean = false,
|
||||
notificationMode: RoomNotificationMode? = null,
|
||||
inviter: RoomMember? = null,
|
||||
isDirect: Boolean = false,
|
||||
isPublic: Boolean = true,
|
||||
isSpace: Boolean = false,
|
||||
isTombstoned: Boolean = false,
|
||||
isFavorite: Boolean = false,
|
||||
canonicalAlias: RoomAlias? = null,
|
||||
alternativeAliases: List<RoomAlias> = emptyList(),
|
||||
hasRoomCall: Boolean = false,
|
||||
isDm: Boolean = false,
|
||||
isFavorite: Boolean = false,
|
||||
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
|
||||
inviter: RoomMember? = null,
|
||||
activeMembersCount: Long = 1,
|
||||
invitedMembersCount: Long = 0,
|
||||
joinedMembersCount: Long = 1,
|
||||
highlightCount: Long = 0,
|
||||
notificationCount: Long = 0,
|
||||
userDefinedNotificationMode: RoomNotificationMode? = null,
|
||||
hasRoomCall: Boolean = false,
|
||||
userPowerLevels: ImmutableMap<UserId, Long> = persistentMapOf(),
|
||||
activeRoomCallParticipants: List<UserId> = emptyList(),
|
||||
heroes: List<MatrixUser> = emptyList(),
|
||||
pinnedEventIds: List<EventId> = emptyList(),
|
||||
roomCreator: UserId? = null,
|
||||
isMarkedUnread: Boolean = false,
|
||||
numUnreadMessages: Long = 0,
|
||||
numUnreadNotifications: Long = 0,
|
||||
numUnreadMentions: Long = 0,
|
||||
lastMessage: RoomMessage? = aRoomMessage(),
|
||||
) = RoomSummary(
|
||||
roomId = roomId,
|
||||
name = name,
|
||||
isDirect = isDirect,
|
||||
avatarUrl = avatarUrl,
|
||||
info = MatrixRoomInfo(
|
||||
id = roomId,
|
||||
name = name,
|
||||
rawName = rawName,
|
||||
topic = topic,
|
||||
avatarUrl = avatarUrl,
|
||||
isDirect = isDirect,
|
||||
isPublic = isPublic,
|
||||
isSpace = isSpace,
|
||||
isTombstoned = isTombstoned,
|
||||
isFavorite = isFavorite,
|
||||
canonicalAlias = canonicalAlias,
|
||||
alternativeAliases = alternativeAliases.toPersistentList(),
|
||||
currentUserMembership = currentUserMembership,
|
||||
inviter = inviter,
|
||||
activeMembersCount = activeMembersCount,
|
||||
invitedMembersCount = invitedMembersCount,
|
||||
joinedMembersCount = joinedMembersCount,
|
||||
userPowerLevels = userPowerLevels,
|
||||
highlightCount = highlightCount,
|
||||
notificationCount = notificationCount,
|
||||
userDefinedNotificationMode = userDefinedNotificationMode,
|
||||
hasRoomCall = hasRoomCall,
|
||||
activeRoomCallParticipants = activeRoomCallParticipants.toPersistentList(),
|
||||
heroes = heroes.toPersistentList(),
|
||||
pinnedEventIds = pinnedEventIds.toPersistentList(),
|
||||
creator = roomCreator,
|
||||
isMarkedUnread = isMarkedUnread,
|
||||
numUnreadMessages = numUnreadMessages,
|
||||
numUnreadNotifications = numUnreadNotifications,
|
||||
numUnreadMentions = numUnreadMentions,
|
||||
),
|
||||
lastMessage = lastMessage,
|
||||
numUnreadMentions = numUnreadMentions,
|
||||
numUnreadMessages = numUnreadMessages,
|
||||
numUnreadNotifications = numUnreadNotifications,
|
||||
isMarkedUnread = isMarkedUnread,
|
||||
userDefinedNotificationMode = notificationMode,
|
||||
inviter = inviter,
|
||||
canonicalAlias = canonicalAlias,
|
||||
alternativeAliases = alternativeAliases,
|
||||
hasRoomCall = hasRoomCall,
|
||||
isDm = isDm,
|
||||
isFavorite = isFavorite,
|
||||
currentUserMembership = currentUserMembership,
|
||||
heroes = heroes,
|
||||
)
|
||||
|
||||
fun aRoomMessage(
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.ui.components
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
open class RoomSummaryDetailsProvider : PreviewParameterProvider<RoomSummary> {
|
||||
override val values: Sequence<RoomSummary>
|
||||
get() = sequenceOf(
|
||||
aRoomSummaryDetails(),
|
||||
aRoomSummaryDetails(name = null),
|
||||
)
|
||||
}
|
||||
|
||||
fun aRoomSummaryDetails(
|
||||
roomId: RoomId = RoomId("!room:domain"),
|
||||
name: String? = "roomName",
|
||||
canonicalAlias: RoomAlias? = null,
|
||||
alternativeAliases: List<RoomAlias> = emptyList(),
|
||||
isDirect: Boolean = true,
|
||||
avatarUrl: String? = null,
|
||||
lastMessage: RoomMessage? = null,
|
||||
inviter: RoomMember? = null,
|
||||
notificationMode: RoomNotificationMode? = null,
|
||||
hasRoomCall: Boolean = false,
|
||||
isDm: Boolean = false,
|
||||
numUnreadMentions: Int = 0,
|
||||
numUnreadMessages: Int = 0,
|
||||
numUnreadNotifications: Int = 0,
|
||||
isMarkedUnread: Boolean = false,
|
||||
isFavorite: Boolean = false,
|
||||
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
|
||||
heroes: List<MatrixUser> = emptyList(),
|
||||
) = RoomSummary(
|
||||
roomId = roomId,
|
||||
name = name,
|
||||
canonicalAlias = canonicalAlias,
|
||||
alternativeAliases = alternativeAliases,
|
||||
isDirect = isDirect,
|
||||
avatarUrl = avatarUrl,
|
||||
lastMessage = lastMessage,
|
||||
inviter = inviter,
|
||||
userDefinedNotificationMode = notificationMode,
|
||||
hasRoomCall = hasRoomCall,
|
||||
isDm = isDm,
|
||||
numUnreadMentions = numUnreadMentions,
|
||||
numUnreadMessages = numUnreadMessages,
|
||||
numUnreadNotifications = numUnreadNotifications,
|
||||
isMarkedUnread = isMarkedUnread,
|
||||
isFavorite = isFavorite,
|
||||
currentUserMembership = currentUserMembership,
|
||||
heroes = heroes,
|
||||
)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.ui.components
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
class SelectRoomInfoProvider : PreviewParameterProvider<SelectRoomInfo> {
|
||||
override val values: Sequence<SelectRoomInfo>
|
||||
get() = sequenceOf(
|
||||
aSelectRoomInfo(roomId = RoomId("!room1:domain")),
|
||||
aSelectRoomInfo(roomId = RoomId("!room2:domain"), name = "Room with a name"),
|
||||
aSelectRoomInfo(roomId = RoomId("!room3:domain"), name = "Room with a name and alias", canonicalAlias = RoomAlias("#alias:domain")),
|
||||
)
|
||||
}
|
||||
|
||||
fun aSelectRoomInfo(
|
||||
roomId: RoomId,
|
||||
name: String? = null,
|
||||
canonicalAlias: RoomAlias? = null,
|
||||
avatarUrl: String? = null,
|
||||
heroes: ImmutableList<MatrixUser> = persistentListOf(),
|
||||
) = SelectRoomInfo(
|
||||
roomId = roomId,
|
||||
name = name,
|
||||
canonicalAlias = canonicalAlias,
|
||||
avatarUrl = avatarUrl,
|
||||
heroes = heroes,
|
||||
)
|
||||
|
|
@ -34,15 +34,15 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Composable
|
||||
fun SelectedRoom(
|
||||
roomSummary: RoomSummary,
|
||||
onRemoveRoom: (RoomSummary) -> Unit,
|
||||
roomInfo: SelectRoomInfo,
|
||||
onRemoveRoom: (SelectRoomInfo) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
|
|
@ -53,14 +53,12 @@ fun SelectedRoom(
|
|||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CompositeAvatar(
|
||||
avatarData = roomSummary.getAvatarData(size = AvatarSize.SelectedRoom),
|
||||
heroes = roomSummary.heroes.map { user ->
|
||||
user.getAvatarData(size = AvatarSize.SelectedRoom)
|
||||
}.toImmutableList()
|
||||
avatarData = roomInfo.getAvatarData(AvatarSize.SelectedRoom),
|
||||
heroes = roomInfo.heroes.map { it.getAvatarData(AvatarSize.SelectedRoom) }.toImmutableList(),
|
||||
)
|
||||
Text(
|
||||
// If name is null, we do not have space to render "No room name", so just use `#` here.
|
||||
text = roomSummary.name ?: "#",
|
||||
text = roomInfo.name ?: "#",
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
|
|
@ -69,14 +67,14 @@ fun SelectedRoom(
|
|||
Surface(
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.size(20.dp)
|
||||
.align(Alignment.TopEnd)
|
||||
.clickable(
|
||||
indication = ripple(),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { onRemoveRoom(roomSummary) }
|
||||
),
|
||||
.clip(CircleShape)
|
||||
.size(20.dp)
|
||||
.align(Alignment.TopEnd)
|
||||
.clickable(
|
||||
indication = ripple(),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { onRemoveRoom(roomInfo) }
|
||||
),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.Close(),
|
||||
|
|
@ -91,10 +89,10 @@ fun SelectedRoom(
|
|||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun SelectedRoomPreview(
|
||||
@PreviewParameter(RoomSummaryDetailsProvider::class) roomSummary: RoomSummary
|
||||
@PreviewParameter(SelectRoomInfoProvider::class) roomInfo: SelectRoomInfo
|
||||
) = ElementPreview {
|
||||
SelectedRoom(
|
||||
roomSummary = roomSummary,
|
||||
roomInfo = roomInfo,
|
||||
onRemoveRoom = {},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ package io.element.android.libraries.matrix.ui.model
|
|||
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
|
||||
fun RoomSummary.getAvatarData(size: AvatarSize) = AvatarData(
|
||||
id = roomId.value,
|
||||
fun MatrixRoomInfo.getAvatarData(size: AvatarSize) = AvatarData(
|
||||
id = id.value,
|
||||
name = name,
|
||||
url = avatarUrl,
|
||||
size = size,
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.ui.model
|
||||
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class SelectRoomInfo(
|
||||
val roomId: RoomId,
|
||||
val name: String?,
|
||||
val canonicalAlias: RoomAlias?,
|
||||
val avatarUrl: String?,
|
||||
val heroes: ImmutableList<MatrixUser>,
|
||||
) {
|
||||
fun getAvatarData(size: AvatarSize) = AvatarData(
|
||||
id = roomId.value,
|
||||
name = name,
|
||||
url = avatarUrl,
|
||||
size = size,
|
||||
)
|
||||
}
|
||||
|
||||
fun RoomSummary.toSelectRoomInfo() = SelectRoomInfo(
|
||||
roomId = roomId,
|
||||
name = info.name,
|
||||
avatarUrl = info.avatarUrl,
|
||||
heroes = info.heroes,
|
||||
canonicalAlias = info.canonicalAlias,
|
||||
)
|
||||
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
|
||||
sealed interface RoomSelectEvents {
|
||||
data class SetSelectedRoom(val room: RoomSummary) : RoomSelectEvents
|
||||
data class SetSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvents
|
||||
|
||||
// TODO remove to restore multi-selection
|
||||
data object RemoveSelectedRoom : RoomSelectEvents
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import dagger.assisted.AssistedFactory
|
|||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -36,7 +36,7 @@ class RoomSelectPresenter @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun present(): RoomSelectState {
|
||||
var selectedRooms by remember { mutableStateOf(persistentListOf<RoomSummary>()) }
|
||||
var selectedRooms by remember { mutableStateOf(persistentListOf<SelectRoomInfo>()) }
|
||||
var searchQuery by remember { mutableStateOf("") }
|
||||
var isSearchActive by remember { mutableStateOf(false) }
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ class RoomSelectPresenter @AssistedInject constructor(
|
|||
dataSource.setSearchQuery(searchQuery)
|
||||
}
|
||||
|
||||
val roomSummaryDetailsList by dataSource.roomSummaries.collectAsState(initial = persistentListOf())
|
||||
val roomSummaryDetailsList by dataSource.roomInfoList.collectAsState(initial = persistentListOf())
|
||||
|
||||
val searchResults by remember {
|
||||
derivedStateOf {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
|||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
|
@ -38,11 +39,12 @@ class RoomSelectSearchDataSource @Inject constructor(
|
|||
source = RoomList.Source.All,
|
||||
)
|
||||
|
||||
val roomSummaries: Flow<PersistentList<RoomSummary>> = roomList.filteredSummaries
|
||||
val roomInfoList: Flow<PersistentList<SelectRoomInfo>> = roomList.filteredSummaries
|
||||
.map { roomSummaries ->
|
||||
roomSummaries
|
||||
.filter { it.currentUserMembership == CurrentUserMembership.JOINED }
|
||||
.filter { it.info.currentUserMembership == CurrentUserMembership.JOINED }
|
||||
.distinctBy { it.roomId } // This should be removed once we're sure no duplicate Rooms can be received
|
||||
.map { roomSummary -> roomSummary.toSelectRoomInfo() }
|
||||
.toPersistentList()
|
||||
}
|
||||
.flowOn(coroutineDispatchers.computation)
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@
|
|||
package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class RoomSelectState(
|
||||
val mode: RoomSelectMode,
|
||||
val resultState: SearchBarResultState<ImmutableList<RoomSummary>>,
|
||||
val resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>>,
|
||||
val query: String,
|
||||
val isSearchActive: Boolean,
|
||||
val selectedRooms: ImmutableList<RoomSummary>,
|
||||
val selectedRooms: ImmutableList<SelectRoomInfo>,
|
||||
val eventSink: (RoomSelectEvents) -> Unit
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails
|
||||
import io.element.android.libraries.matrix.ui.components.aSelectRoomInfo
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -32,7 +32,7 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
|
|||
resultState = SearchBarResultState.Results(aRoomSelectRoomList()),
|
||||
query = "Test",
|
||||
isSearchActive = true,
|
||||
selectedRooms = persistentListOf(aRoomSummaryDetails(roomId = RoomId("!room2:domain")))
|
||||
selectedRooms = aRoomSelectRoomList().subList(0, 1),
|
||||
),
|
||||
aRoomSelectState(
|
||||
mode = RoomSelectMode.Share,
|
||||
|
|
@ -43,10 +43,10 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
|
|||
|
||||
private fun aRoomSelectState(
|
||||
mode: RoomSelectMode = RoomSelectMode.Forward,
|
||||
resultState: SearchBarResultState<ImmutableList<RoomSummary>> = SearchBarResultState.Initial(),
|
||||
resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>> = SearchBarResultState.Initial(),
|
||||
query: String = "",
|
||||
isSearchActive: Boolean = false,
|
||||
selectedRooms: ImmutableList<RoomSummary> = persistentListOf(),
|
||||
selectedRooms: ImmutableList<SelectRoomInfo> = persistentListOf(),
|
||||
) = RoomSelectState(
|
||||
mode = mode,
|
||||
resultState = resultState,
|
||||
|
|
@ -57,14 +57,16 @@ private fun aRoomSelectState(
|
|||
)
|
||||
|
||||
private fun aRoomSelectRoomList() = persistentListOf(
|
||||
aRoomSummaryDetails(),
|
||||
aRoomSummaryDetails(
|
||||
aSelectRoomInfo(
|
||||
roomId = RoomId("!room1:domain"),
|
||||
name = "Room with name",
|
||||
),
|
||||
aSelectRoomInfo(
|
||||
roomId = RoomId("!room2:domain"),
|
||||
name = "Room with alias",
|
||||
canonicalAlias = RoomAlias("#alias:example.org"),
|
||||
),
|
||||
aRoomSummaryDetails(
|
||||
aSelectRoomInfo(
|
||||
roomId = RoomId("!room3:domain"),
|
||||
name = null,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
|||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.ui.components.SelectedRoom
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
|
@ -65,13 +65,13 @@ fun RoomSelectView(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun onRoomRemoved(roomSummary: RoomSummary) {
|
||||
fun onRoomRemoved(roomInfo: SelectRoomInfo) {
|
||||
// TODO toggle selection when multi-selection is enabled
|
||||
state.eventSink(RoomSelectEvents.RemoveSelectedRoom)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList<RoomSummary>) {
|
||||
fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList<SelectRoomInfo>) {
|
||||
if (isForwarding) return
|
||||
SelectedRooms(
|
||||
selectedRooms = selectedRooms,
|
||||
|
|
@ -185,8 +185,8 @@ fun RoomSelectView(
|
|||
|
||||
@Composable
|
||||
private fun SelectedRooms(
|
||||
selectedRooms: ImmutableList<RoomSummary>,
|
||||
onRemoveRoom: (RoomSummary) -> Unit,
|
||||
selectedRooms: ImmutableList<SelectRoomInfo>,
|
||||
onRemoveRoom: (SelectRoomInfo) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
LazyRow(
|
||||
|
|
@ -194,29 +194,29 @@ private fun SelectedRooms(
|
|||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(32.dp)
|
||||
) {
|
||||
items(selectedRooms, key = { it.roomId.value }) { roomSummary ->
|
||||
SelectedRoom(roomSummary = roomSummary, onRemoveRoom = onRemoveRoom)
|
||||
items(selectedRooms, key = { it.roomId.value }) { selectRoomInfo ->
|
||||
SelectedRoom(roomInfo = selectRoomInfo, onRemoveRoom = onRemoveRoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RoomSummaryView(
|
||||
summary: RoomSummary,
|
||||
roomInfo: SelectRoomInfo,
|
||||
isSelected: Boolean,
|
||||
onSelection: (RoomSummary) -> Unit,
|
||||
onSelection: (SelectRoomInfo) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable { onSelection(summary) }
|
||||
.clickable { onSelection(roomInfo) }
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, end = 4.dp)
|
||||
.heightIn(56.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CompositeAvatar(
|
||||
avatarData = summary.getAvatarData(size = AvatarSize.RoomSelectRoomListItem),
|
||||
heroes = summary.heroes.map { user ->
|
||||
avatarData = roomInfo.getAvatarData(size = AvatarSize.RoomSelectRoomListItem),
|
||||
heroes = roomInfo.heroes.map { user ->
|
||||
user.getAvatarData(size = AvatarSize.RoomSelectRoomListItem)
|
||||
}.toPersistentList()
|
||||
)
|
||||
|
|
@ -228,14 +228,14 @@ private fun RoomSummaryView(
|
|||
// Name
|
||||
Text(
|
||||
style = ElementTheme.typography.fontBodyLgRegular,
|
||||
text = summary.name ?: stringResource(id = CommonStrings.common_no_room_name),
|
||||
fontStyle = FontStyle.Italic.takeIf { summary.name == null },
|
||||
text = roomInfo.name ?: stringResource(id = CommonStrings.common_no_room_name),
|
||||
fontStyle = FontStyle.Italic.takeIf { roomInfo.name == null },
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
// Alias
|
||||
summary.canonicalAlias?.let { alias ->
|
||||
roomInfo.canonicalAlias?.let { alias ->
|
||||
Text(
|
||||
text = alias.value,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
|
|
@ -245,7 +245,7 @@ private fun RoomSummaryView(
|
|||
)
|
||||
}
|
||||
}
|
||||
RadioButton(selected = isSelected, onClick = { onSelection(summary) })
|
||||
RadioButton(selected = isSelected, onClick = { onSelection(roomInfo) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
|||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
|
|
@ -58,8 +59,9 @@ class RoomSelectPresenterTest {
|
|||
|
||||
@Test
|
||||
fun `present - update query`() = runTest {
|
||||
val roomSummary = aRoomSummary()
|
||||
val roomListService = FakeRoomListService().apply {
|
||||
postAllRooms(listOf(aRoomSummary()))
|
||||
postAllRooms(listOf(roomSummary))
|
||||
}
|
||||
val presenter = createRoomSelectPresenter(
|
||||
roomListService = roomListService
|
||||
|
|
@ -68,19 +70,10 @@ class RoomSelectPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val expectedRoomSummary = aRoomSummary()
|
||||
val expectedRoomInfo = roomSummary.toSelectRoomInfo()
|
||||
// Do not compare the lambda because they will be different. So copy the lambda from expectedRoomSummary to result
|
||||
val result = (awaitItem().resultState as SearchBarResultState.Results).results.map { roomSummary ->
|
||||
roomSummary.copy(
|
||||
lastMessage = roomSummary.lastMessage!!.copy(
|
||||
event = roomSummary.lastMessage!!.event.copy(
|
||||
debugInfoProvider = expectedRoomSummary.lastMessage!!.event.debugInfoProvider,
|
||||
messageShieldProvider = expectedRoomSummary.lastMessage!!.event.messageShieldProvider,
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
assertThat(result).isEqualTo(listOf(expectedRoomSummary))
|
||||
val result = (awaitItem().resultState as SearchBarResultState.Results).results
|
||||
assertThat(result).isEqualTo(listOf(expectedRoomInfo))
|
||||
initialState.eventSink(RoomSelectEvents.ToggleSearchActive)
|
||||
skipItems(1)
|
||||
initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained"))
|
||||
|
|
@ -99,8 +92,9 @@ class RoomSelectPresenterTest {
|
|||
|
||||
@Test
|
||||
fun `present - select and remove a room`() = runTest {
|
||||
val roomSummary = aRoomSummary()
|
||||
val roomListService = FakeRoomListService().apply {
|
||||
postAllRooms(listOf(aRoomSummary()))
|
||||
postAllRooms(listOf(roomSummary))
|
||||
}
|
||||
val presenter = createRoomSelectPresenter(
|
||||
roomListService = roomListService,
|
||||
|
|
@ -109,9 +103,9 @@ class RoomSelectPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val summary = aRoomSummary()
|
||||
initialState.eventSink(RoomSelectEvents.SetSelectedRoom(summary))
|
||||
assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(summary))
|
||||
val roomInfo = roomSummary.toSelectRoomInfo()
|
||||
initialState.eventSink(RoomSelectEvents.SetSelectedRoom(roomInfo))
|
||||
assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(roomInfo))
|
||||
initialState.eventSink(RoomSelectEvents.RemoveSelectedRoom)
|
||||
assertThat(awaitItem().selectedRooms).isEmpty()
|
||||
cancel()
|
||||
|
|
|
|||
|
|
@ -8,13 +8,27 @@
|
|||
package io.element.android.libraries.textcomposer.mentions
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
|
||||
@Immutable
|
||||
sealed interface ResolvedSuggestion {
|
||||
data object AtRoom : ResolvedSuggestion
|
||||
data class Member(val roomMember: RoomMember) : ResolvedSuggestion
|
||||
data class Alias(val roomAlias: RoomAlias, val roomSummary: RoomSummary) : ResolvedSuggestion
|
||||
data class Alias(
|
||||
val roomAlias: RoomAlias,
|
||||
val roomId: RoomId,
|
||||
val roomName: String?,
|
||||
val roomAvatarUrl: String?,
|
||||
) : ResolvedSuggestion {
|
||||
fun getAvatarData(size: AvatarSize) = AvatarData(
|
||||
id = roomId.value,
|
||||
name = roomName,
|
||||
url = roomAvatarUrl,
|
||||
size = size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
|||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||
import io.element.android.libraries.matrix.api.room.IntentionalMention
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder
|
||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.textcomposer.mentions.MentionSpan
|
||||
import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
|
||||
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
|
||||
|
|
@ -34,7 +34,7 @@ class MarkdownTextEditorStateTest {
|
|||
@Test
|
||||
fun `insertMention - room alias - getMentions return empty list`() {
|
||||
val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true)
|
||||
val suggestion = ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary(canonicalAlias = A_ROOM_ALIAS))
|
||||
val suggestion = aRoomAliasSuggestion()
|
||||
val permalinkBuilder = FakePermalinkBuilder()
|
||||
val mentionSpanProvider = aMentionSpanProvider()
|
||||
state.insertSuggestion(suggestion, mentionSpanProvider, permalinkBuilder)
|
||||
|
|
@ -46,7 +46,7 @@ class MarkdownTextEditorStateTest {
|
|||
val state = MarkdownTextEditorState(initialText = "Hello #", initialFocus = true).apply {
|
||||
currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Room, text = "")
|
||||
}
|
||||
val suggestion = ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary(canonicalAlias = A_ROOM_ALIAS))
|
||||
val suggestion = aRoomAliasSuggestion()
|
||||
val permalinkParser = FakePermalinkParser(result = { PermalinkData.RoomLink(A_ROOM_ALIAS.toRoomIdOrAlias()) })
|
||||
val permalinkBuilder = FakePermalinkBuilder(permalinkForRoomAliasLambda = { Result.failure(IllegalStateException("Failed")) })
|
||||
val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser)
|
||||
|
|
@ -58,7 +58,7 @@ class MarkdownTextEditorStateTest {
|
|||
val state = MarkdownTextEditorState(initialText = "Hello #", initialFocus = true).apply {
|
||||
currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Room, text = "")
|
||||
}
|
||||
val suggestion = ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary(canonicalAlias = A_ROOM_ALIAS))
|
||||
val suggestion = aRoomAliasSuggestion()
|
||||
val permalinkParser = FakePermalinkParser(result = { PermalinkData.RoomLink(A_ROOM_ALIAS.toRoomIdOrAlias()) })
|
||||
val permalinkBuilder = FakePermalinkBuilder(permalinkForRoomAliasLambda = { Result.success("https://matrix.to/#/${A_ROOM_ALIAS.value}") })
|
||||
val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser)
|
||||
|
|
@ -202,4 +202,13 @@ class MarkdownTextEditorStateTest {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun aRoomAliasSuggestion(): ResolvedSuggestion.Alias {
|
||||
return ResolvedSuggestion.Alias(
|
||||
roomAlias = A_ROOM_ALIAS,
|
||||
roomId = A_ROOM_ID,
|
||||
roomName = null,
|
||||
roomAvatarUrl = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7d984f18fc4abf9fe56afc74f094aaacfb6926642b37d2d5fc11568707e3f331
|
||||
size 22296
|
||||
oid sha256:19f6f6dcdf49e9ffd2fbb0ea81c3fe0374faf79cecccc812ea1e1d8c05578671
|
||||
size 22344
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:853541fe1bf56895ed286791d68e13d6f07bd8a5a1fbdaafe5354f10a916f5c0
|
||||
size 22620
|
||||
oid sha256:12266ee1fc3477aec0f47e731294ccd2f93ecf4a3a1fada6cf4cb8ba6f7430ac
|
||||
size 22661
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b6dbc970789b59a9bc7db1257a6c60b9b33b7eb7747a30482802659303582323
|
||||
size 7340
|
||||
oid sha256:cbae54843c22fdcb012d926191bc01e638ba38dc55eb4b24c9e3ad9e9a9d103a
|
||||
size 6807
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:42e59e3add65ddc468cb23d9b2bfd460d39c37b72a09deb12298a0bb28d362dc
|
||||
size 6752
|
||||
oid sha256:764de9f67cabfe22be6ad3021a8418d3677f709fce95c019cd66820e66359980
|
||||
size 7804
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ecdfbc386e865be164e34ef963330be1c8548e8d3a505f64321d6496a072896b
|
||||
size 7670
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bcbb1951463a29e167d3ae09be263461bb449ca8677229fe00f18b6a60c8c31d
|
||||
size 7535
|
||||
oid sha256:428c291e304d9f2c25658569a8ecf324eafccf4b63b31897727dda8151289d05
|
||||
size 7040
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3118842f8b80ab4ffdcfbd8124cebaf536d131700d884ec06aa6b19ce22f742c
|
||||
size 6954
|
||||
oid sha256:345cb5d50b201e957be4aaed8b2ac785cd4dfc795924e28ba45015b62bb0d1d7
|
||||
size 7707
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d0ba819713f7d3bdc667481726af1e60366a30c62148893f2eef5e503c5e1df0
|
||||
size 7827
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f7e19544c7a255dc1c52f69c1387966a806ffca809f6ad071b9bc501c86a9577
|
||||
size 30327
|
||||
oid sha256:0db3f0cdb53eb761bf3742ce94f925472a7e1b48b306d2cd81baa2c42bee6a14
|
||||
size 31142
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a417fb437c823b44a62a4e59be87f44425de32ad347115d800f74d4d2db98ecc
|
||||
size 28361
|
||||
oid sha256:d1a17ed95a976a813b541eb373e2eb1f50388f6a994da7b65a586d31be8e0d23
|
||||
size 29199
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:207aa1698d4b851d6c3b97cd99ade7499abb1882c5d8a6450c83de596430a448
|
||||
size 32767
|
||||
oid sha256:1d5390b71350b1029a153c770f1e525c6346052043583fad2b3c4aadfb694b16
|
||||
size 33441
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d8278dba6831714c5f27c8389e4dc048c6d20404bd679e888891c2053baac351
|
||||
size 27995
|
||||
oid sha256:5aa120484502f3ed14e33a7460b19bd090ac421bbb383e75127bbdf3f54f5ca3
|
||||
size 28818
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d89466ad2d6274b2def2b1354862490445bedc0d02e73aec8e9bd1fa77d7133c
|
||||
size 29405
|
||||
oid sha256:646bf7110d66643fda586c2ecd54b78f09111d0e74a531a7c1fa08e968b1abc3
|
||||
size 30217
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8bd095f282b4c40bf7f74a3487bcf3bcbea0b2c0f352f9e02400ee6312d75ed6
|
||||
size 27953
|
||||
oid sha256:594841dd922deceeee60da8bdd7228f9c685f2aa700a2ccbe0dd03bd4b9e4b98
|
||||
size 28739
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6bd6844fb58ba85693bcf3b1c443fc585c09ed410054d7c127e477527a5aed49
|
||||
size 32131
|
||||
oid sha256:6fddc7151694a9622baf4daf5387c47266f1bae4ba0a50bd7ee4435eb403a375
|
||||
size 33088
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:728d0e42d5e07b3fd47b8cf3f415f945fadc606de425dc0b1b2f65750a1c5e34
|
||||
size 27059
|
||||
oid sha256:8c44fadbdeb27169f88a2678ab8b6db9ac7a9f6b21871a436d14728eec398daf
|
||||
size 27883
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue