Suggestion for room alias.

Rename `Mention` to `IntentionalMention` for clarity
Remove dead code, there is no intentional mention for Room or RoomAlias.
Rename `IntentionalMention.AtRoom` to `IntentionalMention.Room` to match Rust naming
This commit is contained in:
Benoit Marty 2024-08-21 14:09:29 +02:00
parent 4385a7779c
commit 4b8985e501
34 changed files with 399 additions and 222 deletions

View file

@ -66,7 +66,7 @@ import io.element.android.features.messages.impl.actionlist.ActionListEvents
import io.element.android.features.messages.impl.actionlist.ActionListView
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
import io.element.android.features.messages.impl.attachments.Attachment
import io.element.android.features.messages.impl.mentions.MentionSuggestionsPickerView
import io.element.android.features.messages.impl.mentions.SuggestionsPickerView
import io.element.android.features.messages.impl.messagecomposer.AttachmentsBottomSheet
import io.element.android.features.messages.impl.messagecomposer.AttachmentsState
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
@ -377,7 +377,7 @@ private fun MessagesViewContent(
@Composable {}
},
sheetSwipeEnabled = state.composerState.showTextFormatting,
sheetShape = if (state.composerState.showTextFormatting || state.composerState.memberSuggestions.isNotEmpty()) {
sheetShape = if (state.composerState.showTextFormatting || state.composerState.suggestions.isNotEmpty()) {
MaterialTheme.shapes.large
} else {
RectangleShape
@ -427,7 +427,7 @@ private fun MessagesViewContent(
},
sheetContentKey = sheetResizeContentKey.intValue,
sheetTonalElevation = 0.dp,
sheetShadowElevation = if (state.composerState.memberSuggestions.isNotEmpty()) 16.dp else 0.dp,
sheetShadowElevation = if (state.composerState.suggestions.isNotEmpty()) 16.dp else 0.dp,
)
}
}
@ -439,7 +439,7 @@ private fun MessagesViewComposerBottomSheetContents(
) {
if (state.userEventPermissions.canSendMessage) {
Column(modifier = Modifier.fillMaxWidth()) {
MentionSuggestionsPickerView(
SuggestionsPickerView(
modifier = Modifier
.heightIn(max = 230.dp)
// Consume all scrolling, preventing the bottom sheet from being dragged when interacting with the list of suggestions
@ -451,9 +451,9 @@ private fun MessagesViewComposerBottomSheetContents(
roomId = state.roomId,
roomName = state.roomName.dataOrNull(),
roomAvatarData = state.roomAvatar.dataOrNull(),
memberSuggestions = state.composerState.memberSuggestions,
suggestions = state.composerState.suggestions,
onSelectSuggestion = {
state.composerState.eventSink(MessageComposerEvents.InsertMention(it))
state.composerState.eventSink(MessageComposerEvents.InsertSuggestion(it))
}
)
MessageComposerView(

View file

@ -16,13 +16,14 @@
package io.element.android.features.messages.impl.mentions
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
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.roomMembers
import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
import io.element.android.libraries.textcomposer.model.Suggestion
import io.element.android.libraries.textcomposer.model.SuggestionType
@ -37,6 +38,7 @@ object MentionSuggestionsProcessor {
* Process the mention suggestions.
* @param suggestion The current suggestion input
* @param roomMembersState The room members state, it contains the current users in the room
* @param roomAliasSuggestions The available room alias suggestions
* @param currentUserId The current user id
* @param canSendRoomMention Should return true if the current user can send room mentions
* @return The list of mentions to display
@ -44,9 +46,10 @@ object MentionSuggestionsProcessor {
suspend fun process(
suggestion: Suggestion?,
roomMembersState: MatrixRoomMembersState,
roomAliasSuggestions: List<RoomAliasSuggestion>,
currentUserId: UserId,
canSendRoomMention: suspend () -> Boolean,
): List<ResolvedMentionSuggestion> {
): List<ResolvedSuggestion> {
val members = roomMembersState.roomMembers()
return when {
members.isNullOrEmpty() || suggestion == null -> {
@ -65,6 +68,11 @@ object MentionSuggestionsProcessor {
)
matchingMembers
}
SuggestionType.Room -> {
roomAliasSuggestions
.filter { it.roomAlias.value.contains(suggestion.text, ignoreCase = true) }
.map { ResolvedSuggestion.Alias(it.roomAlias, it.roomSummary) }
}
else -> {
// Clear suggestions
emptyList()
@ -79,7 +87,7 @@ object MentionSuggestionsProcessor {
roomMembers: List<RoomMember>?,
currentUserId: UserId,
canSendRoomMention: Boolean,
): List<ResolvedMentionSuggestion> {
): List<ResolvedSuggestion> {
return if (roomMembers.isNullOrEmpty()) {
emptyList()
} else {
@ -97,10 +105,10 @@ object MentionSuggestionsProcessor {
.filterUpTo(MAX_BATCH_ITEMS) { member ->
isJoinedMemberAndNotSelf(member) && memberMatchesQuery(member, query)
}
.map(ResolvedMentionSuggestion::Member)
.map(ResolvedSuggestion::Member)
if ("room".contains(query) && canSendRoomMention) {
listOf(ResolvedMentionSuggestion.AtRoom) + matchingMembers
listOf(ResolvedSuggestion.AtRoom) + matchingMembers
} else {
matchingMembers
}

View file

@ -25,6 +25,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -39,38 +40,41 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
import io.element.android.libraries.designsystem.theme.components.Text
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.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@Composable
fun MentionSuggestionsPickerView(
fun SuggestionsPickerView(
roomId: RoomId,
roomName: String?,
roomAvatarData: AvatarData?,
memberSuggestions: ImmutableList<ResolvedMentionSuggestion>,
onSelectSuggestion: (ResolvedMentionSuggestion) -> Unit,
suggestions: ImmutableList<ResolvedSuggestion>,
onSelectSuggestion: (ResolvedSuggestion) -> Unit,
modifier: Modifier = Modifier,
) {
LazyColumn(
modifier = modifier.fillMaxWidth(),
) {
items(
memberSuggestions,
suggestions,
key = { suggestion ->
when (suggestion) {
is ResolvedMentionSuggestion.AtRoom -> "@room"
is ResolvedMentionSuggestion.Member -> suggestion.roomMember.userId.value
is ResolvedSuggestion.AtRoom -> "@room"
is ResolvedSuggestion.Member -> suggestion.roomMember.userId.value
is ResolvedSuggestion.Alias -> suggestion.roomAlias.value
}
}
) {
Column(modifier = Modifier.fillParentMaxWidth()) {
RoomMemberSuggestionItemView(
memberSuggestion = it,
SuggestionItemView(
suggestion = it,
roomId = roomId.value,
roomName = roomName,
roomAvatar = roomAvatarData,
@ -84,33 +88,44 @@ fun MentionSuggestionsPickerView(
}
@Composable
private fun RoomMemberSuggestionItemView(
memberSuggestion: ResolvedMentionSuggestion,
private fun SuggestionItemView(
suggestion: ResolvedSuggestion,
roomId: String,
roomName: String?,
roomAvatar: AvatarData?,
onSelectSuggestion: (ResolvedMentionSuggestion) -> Unit,
onSelectSuggestion: (ResolvedSuggestion) -> Unit,
modifier: Modifier = Modifier,
) {
Row(modifier = modifier.clickable { onSelectSuggestion(memberSuggestion) }, horizontalArrangement = Arrangement.spacedBy(16.dp)) {
val avatarData = when (memberSuggestion) {
is ResolvedMentionSuggestion.AtRoom -> roomAvatar?.copy(size = AvatarSize.Suggestion)
?: AvatarData(roomId, roomName, null, AvatarSize.Suggestion)
is ResolvedMentionSuggestion.Member -> AvatarData(
id = memberSuggestion.roomMember.userId.value,
name = memberSuggestion.roomMember.displayName,
url = memberSuggestion.roomMember.avatarUrl,
size = AvatarSize.Suggestion,
Row(
modifier = modifier.clickable { onSelectSuggestion(suggestion) },
horizontalArrangement = Arrangement.spacedBy(16.dp),
) {
val avatarSize = AvatarSize.Suggestion
val avatarData = when (suggestion) {
is ResolvedSuggestion.AtRoom -> roomAvatar?.copy(size = avatarSize) ?: AvatarData(roomId, roomName, null, avatarSize)
is ResolvedSuggestion.Member -> AvatarData(
suggestion.roomMember.userId.value,
suggestion.roomMember.displayName,
suggestion.roomMember.avatarUrl,
avatarSize,
)
is ResolvedSuggestion.Alias -> AvatarData(
suggestion.roomSummary.roomId.value,
suggestion.roomSummary.name,
suggestion.roomSummary.avatarUrl,
avatarSize,
)
}
val title = when (memberSuggestion) {
is ResolvedMentionSuggestion.AtRoom -> stringResource(R.string.screen_room_mentions_at_room_title)
is ResolvedMentionSuggestion.Member -> memberSuggestion.roomMember.displayName
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
}
val subtitle = when (memberSuggestion) {
is ResolvedMentionSuggestion.AtRoom -> "@room"
is ResolvedMentionSuggestion.Member -> memberSuggestion.roomMember.userId.value
val subtitle = when (suggestion) {
is ResolvedSuggestion.AtRoom -> "@room"
is ResolvedSuggestion.Member -> suggestion.roomMember.userId.value
is ResolvedSuggestion.Alias -> suggestion.roomAlias.value
}
Avatar(avatarData = avatarData, modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 12.dp))
@ -142,7 +157,7 @@ private fun RoomMemberSuggestionItemView(
@PreviewsDayNight
@Composable
internal fun MentionSuggestionsPickerViewPreview() {
internal fun SuggestionsPickerViewPreview() {
ElementPreview {
val roomMember = RoomMember(
userId = UserId("@alice:server.org"),
@ -155,14 +170,24 @@ internal fun MentionSuggestionsPickerViewPreview() {
isIgnored = false,
role = RoomMember.Role.USER,
)
MentionSuggestionsPickerView(
val anAlias = remember { RoomAlias("#room:domain.org") }
val roomSummaryDetails = remember {
aRoomSummaryDetails(
name = "My room",
)
}
SuggestionsPickerView(
roomId = RoomId("!room:matrix.org"),
roomName = "Room",
roomAvatarData = null,
memberSuggestions = persistentListOf(
ResolvedMentionSuggestion.AtRoom,
ResolvedMentionSuggestion.Member(roomMember),
ResolvedMentionSuggestion.Member(roomMember.copy(userId = UserId("@bob:server.org"), displayName = "Bob")),
suggestions = persistentListOf(
ResolvedSuggestion.AtRoom,
ResolvedSuggestion.Member(roomMember),
ResolvedSuggestion.Member(roomMember.copy(userId = UserId("@bob:server.org"), displayName = "Bob")),
ResolvedSuggestion.Alias(
anAlias,
roomSummaryDetails,
)
),
onSelectSuggestion = {}
)

View file

@ -18,7 +18,7 @@ package io.element.android.features.messages.impl.messagecomposer
import android.net.Uri
import androidx.compose.runtime.Immutable
import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.textcomposer.model.Suggestion
@ -44,6 +44,6 @@ sealed interface MessageComposerEvents {
data class Error(val error: Throwable) : MessageComposerEvents
data class TypingNotice(val isTyping: Boolean) : MessageComposerEvents
data class SuggestionReceived(val suggestion: Suggestion?) : MessageComposerEvents
data class InsertMention(val mention: ResolvedMentionSuggestion) : MessageComposerEvents
data class InsertSuggestion(val resolvedSuggestion: ResolvedSuggestion) : MessageComposerEvents
data object SaveDraft : MessageComposerEvents
}

View file

@ -55,8 +55,8 @@ import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
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.Mention
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType
import io.element.android.libraries.matrix.api.room.isDm
@ -72,7 +72,7 @@ import io.element.android.libraries.permissions.api.PermissionsPresenter
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
import io.element.android.libraries.textcomposer.mentions.LocalMentionSpanTheme
import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState
import io.element.android.libraries.textcomposer.model.Message
import io.element.android.libraries.textcomposer.model.MessageComposerMode
@ -117,6 +117,7 @@ class MessageComposerPresenter @Inject constructor(
private val analyticsService: AnalyticsService,
private val messageComposerContext: DefaultMessageComposerContext,
private val richTextEditorStateFactory: RichTextEditorStateFactory,
private val roomAliasSuggestionsDataSource: RoomAliasSuggestionsDataSource,
private val permalinkParser: PermalinkParser,
private val permalinkBuilder: PermalinkBuilder,
permissionsPresenterFactory: PermissionsPresenter.Factory,
@ -189,6 +190,8 @@ class MessageComposerPresenter @Inject constructor(
val sendTypingNotifications by sessionPreferencesStore.isSendTypingNotificationsEnabled().collectAsState(initial = true)
val roomAliasSuggestions by roomAliasSuggestionsDataSource.getAllRoomAliasSuggestions().collectAsState(initial = emptyList())
LaunchedEffect(attachmentsState.value) {
when (val attachmentStateValue = attachmentsState.value) {
is AttachmentsState.Sending.Processing -> {
@ -212,7 +215,7 @@ class MessageComposerPresenter @Inject constructor(
}
}
val memberSuggestions = remember { mutableStateListOf<ResolvedMentionSuggestion>() }
val suggestions = remember { mutableStateListOf<ResolvedSuggestion>() }
LaunchedEffect(isMentionsEnabled) {
if (!isMentionsEnabled) return@LaunchedEffect
val currentUserId = room.sessionId
@ -228,15 +231,16 @@ class MessageComposerPresenter @Inject constructor(
val mentionCompletionTrigger = suggestionSearchTrigger.debounce(0.3.seconds).filter { !it?.text.isNullOrEmpty() }
merge(mentionStartTrigger, mentionCompletionTrigger)
.combine(room.membersStateFlow) { suggestion, roomMembersState ->
memberSuggestions.clear()
suggestions.clear()
val result = MentionSuggestionsProcessor.process(
suggestion = suggestion,
roomMembersState = roomMembersState,
roomAliasSuggestions = roomAliasSuggestions,
currentUserId = currentUserId,
canSendRoomMention = ::canSendRoomMention,
)
if (result.isNotEmpty()) {
memberSuggestions.addAll(result)
suggestions.addAll(result)
}
}
.collect()
@ -362,22 +366,27 @@ class MessageComposerPresenter @Inject constructor(
is MessageComposerEvents.SuggestionReceived -> {
suggestionSearchTrigger.value = event.suggestion
}
is MessageComposerEvents.InsertMention -> {
is MessageComposerEvents.InsertSuggestion -> {
localCoroutineScope.launch {
if (showTextFormatting) {
when (val mention = event.mention) {
is ResolvedMentionSuggestion.AtRoom -> {
when (val suggestion = event.resolvedSuggestion) {
is ResolvedSuggestion.AtRoom -> {
richTextEditorState.insertAtRoomMentionAtSuggestion()
}
is ResolvedMentionSuggestion.Member -> {
val text = mention.roomMember.userId.value
val link = permalinkBuilder.permalinkForUser(mention.roomMember.userId).getOrNull() ?: return@launch
is ResolvedSuggestion.Member -> {
val text = suggestion.roomMember.userId.value
val link = permalinkBuilder.permalinkForUser(suggestion.roomMember.userId).getOrNull() ?: return@launch
richTextEditorState.insertMentionAtSuggestion(text = text, link = link)
}
is ResolvedSuggestion.Alias -> {
val text = suggestion.roomAlias.value
val link = permalinkBuilder.permalinkForRoomAlias(suggestion.roomAlias).getOrNull() ?: return@launch
richTextEditorState.insertMentionAtSuggestion(text = text, link = link)
}
}
} else if (markdownTextEditorState.currentMentionSuggestion != null) {
markdownTextEditorState.insertMention(
mention = event.mention,
} else if (markdownTextEditorState.currentSuggestion != null) {
markdownTextEditorState.insertSuggestion(
resolvedSuggestion = event.resolvedSuggestion,
mentionSpanProvider = mentionSpanProvider,
permalinkBuilder = permalinkBuilder,
)
@ -417,7 +426,7 @@ class MessageComposerPresenter @Inject constructor(
canShareLocation = canShareLocation.value,
canCreatePoll = canCreatePoll.value,
attachmentsState = attachmentsState.value,
memberSuggestions = memberSuggestions.toPersistentList(),
suggestions = suggestions.toPersistentList(),
resolveMentionDisplay = resolveMentionDisplay,
eventSink = { handleEvents(it) },
)
@ -432,17 +441,21 @@ class MessageComposerPresenter @Inject constructor(
// Reset composer right away
resetComposer(markdownTextEditorState, richTextEditorState, fromEdit = capturedMode is MessageComposerMode.Edit)
when (capturedMode) {
is MessageComposerMode.Normal -> room.sendMessage(body = message.markdown, htmlBody = message.html, mentions = message.mentions)
is MessageComposerMode.Normal -> room.sendMessage(
body = message.markdown,
htmlBody = message.html,
intentionalMentions = message.intentionalMentions
)
is MessageComposerMode.Edit -> {
val eventId = capturedMode.eventId
val transactionId = capturedMode.transactionId
timelineController.invokeOnCurrentTimeline {
// First try to edit the message in the current timeline
editMessage(eventId, transactionId, message.markdown, message.html, message.mentions)
editMessage(eventId, transactionId, message.markdown, message.html, message.intentionalMentions)
.onFailure { cause ->
if (cause is TimelineException.EventNotFound && eventId != null) {
// if the event is not found in the timeline, try to edit the message directly
room.editMessage(eventId, message.markdown, message.html, message.mentions)
room.editMessage(eventId, message.markdown, message.html, message.intentionalMentions)
}
}
}
@ -450,7 +463,7 @@ class MessageComposerPresenter @Inject constructor(
is MessageComposerMode.Reply -> {
timelineController.invokeOnCurrentTimeline {
replyMessage(capturedMode.eventId, message.markdown, message.html, message.mentions)
replyMessage(capturedMode.eventId, message.markdown, message.html, message.intentionalMentions)
}
}
}
@ -623,15 +636,15 @@ class MessageComposerPresenter @Inject constructor(
?.let { state ->
buildList {
if (state.hasAtRoomMention) {
add(Mention.AtRoom)
add(IntentionalMention.Room)
}
for (userId in state.userIds) {
add(Mention.User(UserId(userId)))
add(IntentionalMention.User(UserId(userId)))
}
}
}
.orEmpty()
Message(html = html, markdown = markdown, mentions = mentions)
Message(html = html, markdown = markdown, intentionalMentions = mentions)
} else {
val markdown = markdownTextEditorState.getMessageMarkdown(permalinkBuilder)
val mentions = if (withMentions) {
@ -639,7 +652,7 @@ class MessageComposerPresenter @Inject constructor(
} else {
emptyList()
}
Message(html = null, markdown = markdown, mentions = mentions)
Message(html = null, markdown = markdown, intentionalMentions = mentions)
}
}

View file

@ -19,7 +19,7 @@ package io.element.android.features.messages.impl.messagecomposer
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import io.element.android.features.messages.impl.attachments.Attachment
import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.textcomposer.model.TextEditorState
import io.element.android.wysiwyg.display.TextDisplay
@ -35,7 +35,7 @@ data class MessageComposerState(
val canShareLocation: Boolean,
val canCreatePoll: Boolean,
val attachmentsState: AttachmentsState,
val memberSuggestions: ImmutableList<ResolvedMentionSuggestion>,
val suggestions: ImmutableList<ResolvedSuggestion>,
val resolveMentionDisplay: (String, String) -> TextDisplay,
val eventSink: (MessageComposerEvents) -> Unit,
)

View file

@ -18,7 +18,7 @@ package io.element.android.features.messages.impl.messagecomposer
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.textcomposer.aRichTextEditorState
import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.textcomposer.model.TextEditorState
import io.element.android.wysiwyg.display.TextDisplay
@ -41,7 +41,7 @@ fun aMessageComposerState(
canShareLocation: Boolean = true,
canCreatePoll: Boolean = true,
attachmentsState: AttachmentsState = AttachmentsState.None,
memberSuggestions: ImmutableList<ResolvedMentionSuggestion> = persistentListOf(),
suggestions: ImmutableList<ResolvedSuggestion> = persistentListOf(),
) = MessageComposerState(
textEditorState = textEditorState,
isFullScreen = isFullScreen,
@ -51,7 +51,7 @@ fun aMessageComposerState(
canShareLocation = canShareLocation,
canCreatePoll = canCreatePoll,
attachmentsState = attachmentsState,
memberSuggestions = memberSuggestions,
suggestions = suggestions,
resolveMentionDisplay = { _, _ -> TextDisplay.Plain },
eventSink = {},
)

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.messages.impl.messagecomposer
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.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,
)
interface RoomAliasSuggestionsDataSource {
fun getAllRoomAliasSuggestions(): Flow<List<RoomAliasSuggestion>>
}
@ContributesBinding(SessionScope::class)
class DefaultRoomAliasSuggestionsDataSource @Inject constructor(
private val roomListService: RoomListService,
) : RoomAliasSuggestionsDataSource {
override fun getAllRoomAliasSuggestions(): Flow<List<RoomAliasSuggestion>> {
return roomListService
.allRooms
.filteredSummaries
.map { roomSummaries ->
roomSummaries
.mapNotNull { roomSummary ->
roomSummary.canonicalAlias?.let { roomAlias ->
RoomAliasSuggestion(
roomAlias = roomAlias,
roomSummary = roomSummary,
)
}
}
}
}
}