misc : remove direct usage of RoomSummary in UI and let RoomSummary use RoomInfo.
This commit is contained in:
parent
5a4e5d0575
commit
eeb6b6f4bf
47 changed files with 628 additions and 467 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,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
|
||||
|
|
@ -31,7 +30,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
|
||||
|
|
@ -39,21 +37,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
|
||||
|
|
@ -508,62 +500,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,30 @@
|
|||
/*
|
||||
* 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.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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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,8 @@ 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 kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
|
@ -38,11 +38,20 @@ 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 ->
|
||||
SelectRoomInfo(
|
||||
roomId = roomSummary.roomId,
|
||||
name = roomSummary.info.name,
|
||||
avatarUrl = roomSummary.info.avatarUrl,
|
||||
heroes = roomSummary.info.heroes,
|
||||
canonicalAlias = roomSummary.info.canonicalAlias,
|
||||
)
|
||||
}
|
||||
.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) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@ import com.google.common.truth.Truth.assertThat
|
|||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
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.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.libraries.matrix.ui.components.aSelectRoomInfo
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
|
|
@ -58,8 +60,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 +71,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 +93,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 +104,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()
|
||||
|
|
@ -128,4 +123,12 @@ class RoomSelectPresenterTest {
|
|||
coroutineDispatchers = testCoroutineDispatchers(),
|
||||
),
|
||||
)
|
||||
|
||||
private fun RoomSummary.toSelectRoomInfo() = aSelectRoomInfo(
|
||||
roomId = roomId,
|
||||
name = info.name,
|
||||
avatarUrl = info.avatarUrl,
|
||||
heroes = info.heroes,
|
||||
canonicalAlias = info.canonicalAlias,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue