@@ -40,7 +40,7 @@ import im.vector.app.features.analytics.plan.Interaction
4040import io.element.android.features.messages.impl.attachments.Attachment
4141import io.element.android.features.messages.impl.attachments.preview.error.sendAttachmentError
4242import io.element.android.features.messages.impl.draft.ComposerDraftService
43- import io.element.android.features.messages.impl.mentions.MentionSuggestionsProcessor
43+ import io.element.android.features.messages.impl.messagecomposer.suggestions.SuggestionsProcessor
4444import io.element.android.features.messages.impl.timeline.TimelineController
4545import io.element.android.features.messages.impl.utils.TextPillificationHelper
4646import io.element.android.libraries.architecture.Presenter
@@ -55,8 +55,8 @@ import io.element.android.libraries.matrix.api.core.UserId
5555import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
5656import io.element.android.libraries.matrix.api.permalink.PermalinkData
5757import io.element.android.libraries.matrix.api.permalink.PermalinkParser
58+ import io.element.android.libraries.matrix.api.room.IntentionalMention
5859import io.element.android.libraries.matrix.api.room.MatrixRoom
59- import io.element.android.libraries.matrix.api.room.Mention
6060import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
6161import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType
6262import io.element.android.libraries.matrix.api.room.isDm
@@ -72,7 +72,7 @@ import io.element.android.libraries.permissions.api.PermissionsPresenter
7272import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
7373import io.element.android.libraries.textcomposer.mentions.LocalMentionSpanTheme
7474import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
75- import io.element.android.libraries.textcomposer.mentions.ResolvedMentionSuggestion
75+ import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
7676import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState
7777import io.element.android.libraries.textcomposer.model.Message
7878import io.element.android.libraries.textcomposer.model.MessageComposerMode
@@ -117,6 +117,7 @@ class MessageComposerPresenter @Inject constructor(
117117 private val analyticsService : AnalyticsService ,
118118 private val messageComposerContext : DefaultMessageComposerContext ,
119119 private val richTextEditorStateFactory : RichTextEditorStateFactory ,
120+ private val roomAliasSuggestionsDataSource : RoomAliasSuggestionsDataSource ,
120121 private val permalinkParser : PermalinkParser ,
121122 private val permalinkBuilder : PermalinkBuilder ,
122123 permissionsPresenterFactory : PermissionsPresenter .Factory ,
@@ -125,6 +126,7 @@ class MessageComposerPresenter @Inject constructor(
125126 private val mentionSpanProvider : MentionSpanProvider ,
126127 private val pillificationHelper : TextPillificationHelper ,
127128 private val roomMemberProfilesCache : RoomMemberProfilesCache ,
129+ private val suggestionsProcessor : SuggestionsProcessor ,
128130) : Presenter<MessageComposerState> {
129131 private val cameraPermissionPresenter = permissionsPresenterFactory.create(Manifest .permission.CAMERA )
130132 private var pendingEvent: MessageComposerEvents ? = null
@@ -149,8 +151,10 @@ class MessageComposerPresenter @Inject constructor(
149151 }
150152 val markdownTextEditorState = rememberMarkdownTextEditorState(initialText = null , initialFocus = false )
151153 var isMentionsEnabled by remember { mutableStateOf(false ) }
154+ var isRoomAliasSuggestionsEnabled by remember { mutableStateOf(false ) }
152155 LaunchedEffect (Unit ) {
153156 isMentionsEnabled = featureFlagService.isFeatureEnabled(FeatureFlags .Mentions )
157+ isRoomAliasSuggestionsEnabled = featureFlagService.isFeatureEnabled(FeatureFlags .RoomAliasSuggestions )
154158 }
155159
156160 val cameraPermissionState = cameraPermissionPresenter.present()
@@ -189,6 +193,8 @@ class MessageComposerPresenter @Inject constructor(
189193
190194 val sendTypingNotifications by sessionPreferencesStore.isSendTypingNotificationsEnabled().collectAsState(initial = true )
191195
196+ val roomAliasSuggestions by roomAliasSuggestionsDataSource.getAllRoomAliasSuggestions().collectAsState(initial = emptyList())
197+
192198 LaunchedEffect (attachmentsState.value) {
193199 when (val attachmentStateValue = attachmentsState.value) {
194200 is AttachmentsState .Sending .Processing -> {
@@ -212,7 +218,7 @@ class MessageComposerPresenter @Inject constructor(
212218 }
213219 }
214220
215- val memberSuggestions = remember { mutableStateListOf<ResolvedMentionSuggestion >() }
221+ val suggestions = remember { mutableStateListOf<ResolvedSuggestion >() }
216222 LaunchedEffect (isMentionsEnabled) {
217223 if (! isMentionsEnabled) return @LaunchedEffect
218224 val currentUserId = room.sessionId
@@ -228,15 +234,16 @@ class MessageComposerPresenter @Inject constructor(
228234 val mentionCompletionTrigger = suggestionSearchTrigger.debounce(0.3 .seconds).filter { ! it?.text.isNullOrEmpty() }
229235 merge(mentionStartTrigger, mentionCompletionTrigger)
230236 .combine(room.membersStateFlow) { suggestion, roomMembersState ->
231- memberSuggestions .clear()
232- val result = MentionSuggestionsProcessor .process(
237+ suggestions .clear()
238+ val result = suggestionsProcessor .process(
233239 suggestion = suggestion,
234240 roomMembersState = roomMembersState,
241+ roomAliasSuggestions = if (isRoomAliasSuggestionsEnabled) roomAliasSuggestions else emptyList(),
235242 currentUserId = currentUserId,
236243 canSendRoomMention = ::canSendRoomMention,
237244 )
238245 if (result.isNotEmpty()) {
239- memberSuggestions .addAll(result)
246+ suggestions .addAll(result)
240247 }
241248 }
242249 .collect()
@@ -362,22 +369,27 @@ class MessageComposerPresenter @Inject constructor(
362369 is MessageComposerEvents .SuggestionReceived -> {
363370 suggestionSearchTrigger.value = event.suggestion
364371 }
365- is MessageComposerEvents .InsertMention -> {
372+ is MessageComposerEvents .InsertSuggestion -> {
366373 localCoroutineScope.launch {
367374 if (showTextFormatting) {
368- when (val mention = event.mention ) {
369- is ResolvedMentionSuggestion .AtRoom -> {
375+ when (val suggestion = event.resolvedSuggestion ) {
376+ is ResolvedSuggestion .AtRoom -> {
370377 richTextEditorState.insertAtRoomMentionAtSuggestion()
371378 }
372- is ResolvedMentionSuggestion .Member -> {
373- val text = mention.roomMember.userId.value
374- val link = permalinkBuilder.permalinkForUser(mention.roomMember.userId).getOrNull() ? : return @launch
379+ is ResolvedSuggestion .Member -> {
380+ val text = suggestion.roomMember.userId.value
381+ val link = permalinkBuilder.permalinkForUser(suggestion.roomMember.userId).getOrNull() ? : return @launch
382+ richTextEditorState.insertMentionAtSuggestion(text = text, link = link)
383+ }
384+ is ResolvedSuggestion .Alias -> {
385+ val text = suggestion.roomAlias.value
386+ val link = permalinkBuilder.permalinkForRoomAlias(suggestion.roomAlias).getOrNull() ? : return @launch
375387 richTextEditorState.insertMentionAtSuggestion(text = text, link = link)
376388 }
377389 }
378- } else if (markdownTextEditorState.currentMentionSuggestion != null ) {
379- markdownTextEditorState.insertMention (
380- mention = event.mention ,
390+ } else if (markdownTextEditorState.currentSuggestion != null ) {
391+ markdownTextEditorState.insertSuggestion (
392+ resolvedSuggestion = event.resolvedSuggestion ,
381393 mentionSpanProvider = mentionSpanProvider,
382394 permalinkBuilder = permalinkBuilder,
383395 )
@@ -417,7 +429,7 @@ class MessageComposerPresenter @Inject constructor(
417429 canShareLocation = canShareLocation.value,
418430 canCreatePoll = canCreatePoll.value,
419431 attachmentsState = attachmentsState.value,
420- memberSuggestions = memberSuggestions .toPersistentList(),
432+ suggestions = suggestions .toPersistentList(),
421433 resolveMentionDisplay = resolveMentionDisplay,
422434 eventSink = { handleEvents(it) },
423435 )
@@ -432,25 +444,29 @@ class MessageComposerPresenter @Inject constructor(
432444 // Reset composer right away
433445 resetComposer(markdownTextEditorState, richTextEditorState, fromEdit = capturedMode is MessageComposerMode .Edit )
434446 when (capturedMode) {
435- is MessageComposerMode .Normal -> room.sendMessage(body = message.markdown, htmlBody = message.html, mentions = message.mentions)
447+ is MessageComposerMode .Normal -> room.sendMessage(
448+ body = message.markdown,
449+ htmlBody = message.html,
450+ intentionalMentions = message.intentionalMentions
451+ )
436452 is MessageComposerMode .Edit -> {
437453 val eventId = capturedMode.eventId
438454 val transactionId = capturedMode.transactionId
439455 timelineController.invokeOnCurrentTimeline {
440456 // First try to edit the message in the current timeline
441- editMessage(eventId, transactionId, message.markdown, message.html, message.mentions )
457+ editMessage(eventId, transactionId, message.markdown, message.html, message.intentionalMentions )
442458 .onFailure { cause ->
443459 if (cause is TimelineException .EventNotFound && eventId != null ) {
444460 // if the event is not found in the timeline, try to edit the message directly
445- room.editMessage(eventId, message.markdown, message.html, message.mentions )
461+ room.editMessage(eventId, message.markdown, message.html, message.intentionalMentions )
446462 }
447463 }
448464 }
449465 }
450466
451467 is MessageComposerMode .Reply -> {
452468 timelineController.invokeOnCurrentTimeline {
453- replyMessage(capturedMode.eventId, message.markdown, message.html, message.mentions )
469+ replyMessage(capturedMode.eventId, message.markdown, message.html, message.intentionalMentions )
454470 }
455471 }
456472 }
@@ -623,23 +639,23 @@ class MessageComposerPresenter @Inject constructor(
623639 ?.let { state ->
624640 buildList {
625641 if (state.hasAtRoomMention) {
626- add(Mention . AtRoom )
642+ add(IntentionalMention . Room )
627643 }
628644 for (userId in state.userIds) {
629- add(Mention .User (UserId (userId)))
645+ add(IntentionalMention .User (UserId (userId)))
630646 }
631647 }
632648 }
633649 .orEmpty()
634- Message (html = html, markdown = markdown, mentions = mentions)
650+ Message (html = html, markdown = markdown, intentionalMentions = mentions)
635651 } else {
636652 val markdown = markdownTextEditorState.getMessageMarkdown(permalinkBuilder)
637653 val mentions = if (withMentions) {
638654 markdownTextEditorState.getMentions()
639655 } else {
640656 emptyList()
641657 }
642- Message (html = null , markdown = markdown, mentions = mentions)
658+ Message (html = null , markdown = markdown, intentionalMentions = mentions)
643659 }
644660 }
645661
0 commit comments