Skip to content

Add composer autocomplete for enhanced mentions in Compose SDK#6503

Open
gpunto wants to merge 1 commit into
developfrom
pr4-enhanced-mentions-compose-composer
Open

Add composer autocomplete for enhanced mentions in Compose SDK#6503
gpunto wants to merge 1 commit into
developfrom
pr4-enhanced-mentions-compose-composer

Conversation

@gpunto

@gpunto gpunto commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Goal

Offer @channel, @here, role, and user-group suggestions in the Compose composer alongside user mentions, gated by channel capabilities.

This is PR 4 in the enhanced-mentions series.

Part of AND-1175

Implementation

  • New ChannelCapabilities gate each mention type: CREATE_MENTION, NOTIFY_CHANNEL, NOTIFY_HERE, NOTIFY_ROLE, NOTIFY_GROUP.
  • MentionLookupHandler aggregates users, roles, and groups for a given query.
  • Compose: UserSuggestionItem becomes MentionSuggestionItem, rendering every mention type; exposed as a ChatComponentFactory slot.

UI Changes

Before After
Screenshot_20260617_125735 Screenshot_20260617_125618

Testing

  • MentionLookupHandlerTest covers capability gating, ordering, query matching, and empty paths.
  • MessageComposerControllerTest covers the new filterMentions survival rules across every mention type.
  • MessageComposerViewModelTest exercises the suggestion-list flow end to end.
  • Paparazzi: new MentionSuggestionListTest baseline; refreshed MessageComposerTest snapshots that now render the broader suggestion item.

Manual (on a channel with the new capabilities granted, e.g. any messaging channel in the demo app):

  1. Open the Compose sample and tap the composer.
  2. Type @ and confirm @channel and @here appear at the top.
  3. Type a few more characters and confirm matching roles, groups, and users show up.
  4. Pick one of each type and confirm the inserted token survives Send.

Summary by CodeRabbit

  • New Features

    • Message composer mention suggestions now support @channel, @here, role-based, and group mentions alongside user mentions.
  • Documentation

    • Added localized UI labels for mention suggestion types in Spanish, French, Hindi, Indonesian, Italian, Japanese, and Korean.

@gpunto gpunto added the pr:new-feature New feature label Jun 17, 2026
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.90 MB 5.90 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.14 MB 11.14 MB 0.00 MB 🟢
stream-chat-android-compose 12.58 MB 12.60 MB 0.02 MB 🟢

@gpunto gpunto force-pushed the pr4-enhanced-mentions-compose-composer branch 3 times, most recently from 7aa6cf5 to 6e8179d Compare June 17, 2026 12:05
@gpunto gpunto changed the title Add Compose composer autocomplete for enhanced mentions Add composer autocomplete for enhanced mentions in Compose SDK Jun 17, 2026
@gpunto gpunto force-pushed the pr4-enhanced-mentions-compose-composer branch from 6e8179d to e9c80ac Compare June 17, 2026 13:03
@gpunto gpunto force-pushed the pr4-enhanced-mentions-compose-composer branch from e9c80ac to 612a70a Compare June 17, 2026 14:00
@sonarqubecloud

Copy link
Copy Markdown

@gpunto

gpunto commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Extends the message composer to support unified mention suggestions beyond users: channels, @here, roles, and user groups. Adds new ChannelCapabilities constants, a MentionLookupHandler, refactored MessageComposerController filtering, new MentionSuggestionItem Compose UI replacing the old user-only item, updated ChatComponentFactory slots, MessageComposerState.suggestedMentions, and localized subtitle strings across 8 languages.

Changes

Unified Mention Suggestions

Layer / File(s) Summary
ChannelCapabilities constants and MessageComposerState contract
stream-chat-android-core/.../ChannelCapabilities.kt, stream-chat-android-core/api/stream-chat-android-core.api, stream-chat-android-ui-common/.../MessageComposerState.kt, stream-chat-android-ui-common/api/stream-chat-android-ui-common.api
Adds CREATE_MENTION, NOTIFY_CHANNEL, NOTIFY_HERE, NOTIFY_ROLE, NOTIFY_GROUP capability constants. Extends MessageComposerState with suggestedMentions: List<Mention> and deprecates the user-only mentionSuggestions.
MessageComposerParams and suggestion item param contracts
stream-chat-android-compose/.../ChatComponentFactoryParams.kt, stream-chat-android-compose/api/stream-chat-android-compose.api
Adds onMentionSelected to MessageComposerParams (deprecating onUserSelected) and introduces four new data classes (MessageComposerSuggestionItemParams, ...LeadingContentParams, ...CenterContentParams, ...TrailingContentParams).
MentionLookupHandler and LocalUserLookupHandler IO dispatch
stream-chat-android-ui-common/.../mention/MentionLookupHandler.kt, stream-chat-android-ui-common/.../mention/LocalUserLookupHandler.kt, stream-chat-android-ui-common/.../mention/UserLookupHandler.kt, stream-chat-android-ui-common/.../query/filter/DefaultUserQueryFilter.kt
Adds MentionLookupHandler that concurrently fetches roles, groups, and users gated by channel capabilities and assembles an ordered List<Mention>. Moves LocalUserLookupHandler onto DispatcherProvider.IO. Rewrites DefaultUserQueryFilter with whitespace-token prefix matching and alphabetical sorting.
MessageComposerController mention filtering and suggestion pipeline
stream-chat-android-ui-common/.../MessageComposerController.kt
Wires MentionLookupHandler, adds mentionSuggestionJob for cancellable resolution, refactors handleMentionSuggestions to populate both suggestedMentions and mentionSuggestions, and rewrites filterMentions/buildNewMessage to produce structured mention metadata (channel/here/roles/groups).
MentionSuggestionItem, SuggestionItemRow, and MentionSuggestionList Compose UI
stream-chat-android-compose/.../suggestions/MentionSuggestionItem.kt, stream-chat-android-compose/.../suggestions/UserSuggestionList.kt, stream-chat-android-ui-common/src/main/res/drawable/stream_design_ic_megaphone.xml, stream-chat-android-ui-common/src/main/res/drawable/stream_design_ic_role.xml, stream-chat-android-compose/src/main/res/values*/strings.xml
Adds MentionSuggestionItem/UserSuggestionItem/SuggestionItemRow composables; removes UserSuggestionItem.kt; replaces UserSuggestionList with MentionSuggestionList. Adds megaphone and role vector drawables. Adds localized subtitle strings for channel/here/role mentions across 8 locales.
ChatComponentFactory mention suggestion item routing and deprecations
stream-chat-android-compose/.../ChatComponentFactory.kt
Adds MessageComposerSuggestionItem dispatching Mention.User to the legacy item and other types to MentionSuggestionItem. Deprecates MessageComposerUserSuggestionItem* variants with delegation to generic mention content functions. Wires onMentionSelected from MessageComposerParams.
MessageComposer composable onMentionSelected wiring
stream-chat-android-compose/.../MessageComposer.kt, stream-chat-android-docs/.../MessageComposer.kt
Adds onMentionSelected parameter to both MessageComposer overloads, switches suggestion rendering to MentionSuggestionList with fallback from legacy mentionSuggestions, extends messageResOrNull for CancelCommandRequired, and updates preview fixtures and docs.
Tests
stream-chat-android-ui-common/src/test/.../mention/MentionLookupHandlerTest.kt, stream-chat-android-ui-common/src/test/.../MessageComposerControllerTest.kt, stream-chat-android-ui-common/src/test/.../query/filter/DefaultUserQueryFilterTest.kt, stream-chat-android-compose/src/test/.../MessageComposerViewModelTest.kt, stream-chat-android-compose/src/test/.../MentionSuggestionListTest.kt, stream-chat-android-ui-components/src/test/.../MessageComposerViewModelTest.kt
Adds MentionLookupHandlerTest covering capability gating and concurrent sources. Adds controller tests for buildNewMessage mention fields. Refactors DefaultUserQueryFilterTest to parameterized token-based cases. Updates view model tests with CREATE_MENTION capabilities and non-user mention cases. Renames snapshot test to MentionSuggestionListTest.
E2E test tag and cosmetic edits
stream-chat-android-compose-sample/.../MessageListPage.kt, stream-chat-android-compose-sample/.../ChatsActivity.kt
Updates E2E UI Automator selector from Stream_UserSuggestionItem to Stream_SuggestionItem. Inserts a blank line in ChatsActivity.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant MessageComposer
  participant MessageComposerController
  participant MentionLookupHandler
  participant ChatClient

  User->>MessageComposer: types `@query`
  MessageComposer->>MessageComposerController: input change (debounced)
  MessageComposerController->>MentionLookupHandler: handleMentionLookup(query)
  par concurrent fetches
    MentionLookupHandler->>ChatClient: searchRoles(query)
    MentionLookupHandler->>ChatClient: searchUserGroups(query, team?)
    MentionLookupHandler->>MentionLookupHandler: userLookupHandler(query)
  end
  MentionLookupHandler-->>MessageComposerController: List~Mention~ [channel, here, roles, groups, users]
  MessageComposerController-->>MessageComposer: state(suggestedMentions, mentionSuggestions)
  MessageComposer->>MessageComposer: render MentionSuggestionList
  User->>MessageComposer: selects mention
  MessageComposer->>MessageComposerController: onMentionSelected(mention)
  MessageComposerController->>MessageComposerController: filterMentions → FilteredMentions
  MessageComposerController-->>MessageComposer: buildNewMessage with mention fields
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • GetStream/stream-chat-android#6501: Also updates MessageComposerParams/getOnMentionSelected and introduces MessageComposerSuggestionItem* params on the same compose-side mention composer API changed here.

Suggested reviewers

  • andremion
  • aleksandar-apostolov

🐇 Hippity hop, the mentions now fly,
@channel, @here, and roles in the sky!
MentionLookupHandler searches with glee,
Roles, groups, and users — all found by me!
No more just users, we fetch them all right,
Stream Chat hops forward, suggestions delight! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add composer autocomplete for enhanced mentions in Compose SDK' clearly and specifically describes the main feature addition, aligning well with the PR's primary objective of enabling enhanced mention suggestions.
Description check ✅ Passed The PR description follows the template structure with Goal, Implementation, UI Changes, and Testing sections fully completed with relevant details and screenshots.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr4-enhanced-mentions-compose-composer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/LocalUserLookupHandler.kt (1)

44-63: ⚠️ Potential issue | 🟠 Major

Re-throw coroutine cancellation in user lookup.

Wrapping the function in withContext(DispatcherProvider.IO) introduces a cancellation point. However, the broad catch (e: Exception) on line 60 catches CancellationException as well, preventing cancellation from propagating. This allows canceled lookup operations to return emptyList() instead of propagating the cancellation, potentially causing stale results to race newer UI updates.

Suggested fix
+import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.withContext
@@
-        } catch (e: Exception) {
+        } catch (e: CancellationException) {
+            throw e
+        } catch (e: Exception) {
             logger.e(e) { "[handleUserLookup] failed: $e" }
             emptyList()
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/LocalUserLookupHandler.kt`
around lines 44 - 63, In the handleUserLookup function, modify the catch block
to re-throw CancellationException after catching it. The broad catch (e:
Exception) block currently catches CancellationException which prevents
coroutine cancellation from propagating properly. Add a check inside the catch
block to detect if the caught exception is a CancellationException, and if so,
re-throw it immediately before logging and returning emptyList() for other
exception types. This ensures that when the lookup operation is cancelled, the
cancellation propagates correctly instead of returning stale results.
🧹 Nitpick comments (2)
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/composer/internal/suggestions/MentionSuggestionListTest.kt (1)

40-47: ⚡ Quick win

Add a group mention row to this snapshot.

This baseline covers channel/here/user/role, but not Mention.Group, which is part of the new mention surface.

Suggested patch
 import io.getstream.chat.android.previewdata.PreviewUserData
+import io.getstream.chat.android.models.UserGroup
 import io.getstream.chat.android.ui.common.feature.messages.composer.mention.Mention
@@
                 mentions = listOf(
                     Mention.Channel,
                     Mention.Here,
                     Mention.User(PreviewUserData.user1),
                     Mention.User(PreviewUserData.user2),
                     Mention.User(PreviewUserData.user3),
                     Mention.Role("admin"),
+                    Mention.Group(UserGroup(id = "g1", name = "platform")),
                 ),
             )

As per coding guidelines stream-chat-android-compose/**/*{Test,Snapshot}.kt: add Paparazzi snapshots for Compose UI regressions and run verifyPaparazziDebug.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/composer/internal/suggestions/MentionSuggestionListTest.kt`
around lines 40 - 47, The mentions list in MentionSuggestionListTest.kt is
missing a Mention.Group entry, which is part of the new mention surface. Add a
Mention.Group instance to the mentions list alongside the existing
Mention.Channel, Mention.Here, Mention.User, and Mention.Role entries to ensure
the snapshot test covers all mention types.

Source: Coding guidelines

stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/MentionLookupHandler.kt (1)

46-78: 💤 Low value

Consider extracting helper functions to reduce cognitive complexity.

SonarCloud flags this method's cognitive complexity at 18 (limit 15). While the logic is correct and readable, extracting the capability-gated async launches and the buildList assembly into small private helpers would lower the metric and improve testability.

♻️ Suggested refactor
 suspend fun handleMentionLookup(query: String): List<Mention> = coroutineScope {
     val capabilities = channelState.value?.channelData?.value?.ownCapabilities.orEmpty()
-    val getGroups = async {
-        if (ChannelCapabilities.NOTIFY_GROUP in capabilities) searchGroups(query) else emptyList()
-    }
-    val getUsers = async {
-        if (ChannelCapabilities.CREATE_MENTION in capabilities) {
-            userLookupHandler.handleUserLookup(query)
-        } else {
-            emptyList()
-        }
-    }
-    val getRoles = async {
-        if (ChannelCapabilities.NOTIFY_ROLE in capabilities) searchRoles(query) else emptyList()
-    }
-
-    buildList {
-        if (ChannelCapabilities.NOTIFY_CHANNEL in capabilities &&
-            Mention.Channel.display.matchesMentionQuery(query)
-        ) {
-            add(Mention.Channel)
-        }
-        if (ChannelCapabilities.NOTIFY_HERE in capabilities &&
-            Mention.Here.display.matchesMentionQuery(query)
-        ) {
-            add(Mention.Here)
-        }
-
-        getRoles.await().forEach { add(Mention.Role(it)) }
-        getGroups.await().forEach { add(Mention.Group(it)) }
-        getUsers.await().forEach { add(Mention.User(it)) }
-    }
+    val (roles, groups, users) = fetchMentionSources(capabilities, query)
+    assembleMentions(capabilities, query, roles, groups, users)
 }
+
+private suspend fun CoroutineScope.fetchMentionSources(
+    capabilities: Set<String>,
+    query: String,
+): Triple<List<String>, List<UserGroup>, List<User>> {
+    val getRoles = async {
+        if (ChannelCapabilities.NOTIFY_ROLE in capabilities) searchRoles(query) else emptyList()
+    }
+    val getGroups = async {
+        if (ChannelCapabilities.NOTIFY_GROUP in capabilities) searchGroups(query) else emptyList()
+    }
+    val getUsers = async {
+        if (ChannelCapabilities.CREATE_MENTION in capabilities) {
+            userLookupHandler.handleUserLookup(query)
+        } else {
+            emptyList()
+        }
+    }
+    return Triple(getRoles.await(), getGroups.await(), getUsers.await())
+}
+
+private fun assembleMentions(
+    capabilities: Set<String>,
+    query: String,
+    roles: List<String>,
+    groups: List<UserGroup>,
+    users: List<User>,
+): List<Mention> = buildList {
+    if (ChannelCapabilities.NOTIFY_CHANNEL in capabilities &&
+        Mention.Channel.display.matchesMentionQuery(query)
+    ) add(Mention.Channel)
+    if (ChannelCapabilities.NOTIFY_HERE in capabilities &&
+        Mention.Here.display.matchesMentionQuery(query)
+    ) add(Mention.Here)
+    roles.forEach { add(Mention.Role(it)) }
+    groups.forEach { add(Mention.Group(it)) }
+    users.forEach { add(Mention.User(it)) }
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/MentionLookupHandler.kt`
around lines 46 - 78, The handleMentionLookup method has cognitive complexity of
18, exceeding the limit of 15. Extract two private helper functions to reduce
complexity: first, create a helper function to manage the three async operations
(getGroups, getUsers, getRoles launches) that returns their results, and second,
create another helper function that takes those async results and the query
parameter to build and return the final list of Mention objects using the
buildList logic. This refactoring will lower cognitive complexity and improve
testability while keeping the handleMentionLookup method as a coordinator that
calls these helpers.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/LocalUserLookupHandler.kt`:
- Around line 44-63: In the handleUserLookup function, modify the catch block to
re-throw CancellationException after catching it. The broad catch (e: Exception)
block currently catches CancellationException which prevents coroutine
cancellation from propagating properly. Add a check inside the catch block to
detect if the caught exception is a CancellationException, and if so, re-throw
it immediately before logging and returning emptyList() for other exception
types. This ensures that when the lookup operation is cancelled, the
cancellation propagates correctly instead of returning stale results.

---

Nitpick comments:
In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/composer/internal/suggestions/MentionSuggestionListTest.kt`:
- Around line 40-47: The mentions list in MentionSuggestionListTest.kt is
missing a Mention.Group entry, which is part of the new mention surface. Add a
Mention.Group instance to the mentions list alongside the existing
Mention.Channel, Mention.Here, Mention.User, and Mention.Role entries to ensure
the snapshot test covers all mention types.

In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/MentionLookupHandler.kt`:
- Around line 46-78: The handleMentionLookup method has cognitive complexity of
18, exceeding the limit of 15. Extract two private helper functions to reduce
complexity: first, create a helper function to manage the three async operations
(getGroups, getUsers, getRoles launches) that returns their results, and second,
create another helper function that takes those async results and the query
parameter to build and return the final list of Mention objects using the
buildList logic. This refactoring will lower cognitive complexity and improve
testability while keeping the handleMentionLookup method as a coordinator that
calls these helpers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 38f1b34c-edfb-4955-98e0-aae5f89339bd

📥 Commits

Reviewing files that changed from the base of the PR and between 73f5f7e and 612a70a.

⛔ Files ignored due to path filters (4)
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.composer.internal.suggestions_MentionSuggestionListTest_mention_suggestion_list.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerTest_fixed_style_with_user_suggestions.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerTest_floating_style_with_user_suggestions_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_MessageComposerTest_floating_style_with_user_suggestions_in_light_mode.png is excluded by !**/*.png
📒 Files selected for processing (35)
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/pages/MessageListPage.kt
  • stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/chats/ChatsActivity.kt
  • stream-chat-android-compose/api/stream-chat-android-compose.api
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/MessageComposer.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/suggestions/MentionSuggestionItem.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/suggestions/UserSuggestionItem.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/suggestions/UserSuggestionList.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactoryParams.kt
  • stream-chat-android-compose/src/main/res/values-es/strings.xml
  • stream-chat-android-compose/src/main/res/values-fr/strings.xml
  • stream-chat-android-compose/src/main/res/values-hi/strings.xml
  • stream-chat-android-compose/src/main/res/values-in/strings.xml
  • stream-chat-android-compose/src/main/res/values-it/strings.xml
  • stream-chat-android-compose/src/main/res/values-ja/strings.xml
  • stream-chat-android-compose/src/main/res/values-ko/strings.xml
  • stream-chat-android-compose/src/main/res/values/strings.xml
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/composer/internal/suggestions/MentionSuggestionListTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/viewmodel/messages/MessageComposerViewModelTest.kt
  • stream-chat-android-core/api/stream-chat-android-core.api
  • stream-chat-android-core/src/main/java/io/getstream/chat/android/models/ChannelCapabilities.kt
  • stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/messages/MessageComposer.kt
  • stream-chat-android-ui-common/api/stream-chat-android-ui-common.api
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/LocalUserLookupHandler.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/MentionLookupHandler.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/UserLookupHandler.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/query/filter/DefaultUserQueryFilter.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/state/messages/composer/MessageComposerState.kt
  • stream-chat-android-ui-common/src/main/res/drawable/stream_design_ic_megaphone.xml
  • stream-chat-android-ui-common/src/main/res/drawable/stream_design_ic_role.xml
  • stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerControllerTest.kt
  • stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/mention/MentionLookupHandlerTest.kt
  • stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/query/filter/DefaultUserQueryFilterTest.kt
  • stream-chat-android-ui-components/src/test/kotlin/io/getstream/chat/android/ui/viewmodels/messages/MessageComposerViewModelTest.kt
💤 Files with no reviewable changes (1)
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/composer/internal/suggestions/UserSuggestionItem.kt

@gpunto gpunto marked this pull request as ready for review June 18, 2026 12:22
@gpunto gpunto requested a review from a team as a code owner June 18, 2026 12:22

@andremion andremion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!

One small heads-up: DefaultUserQueryFilter now does word-prefix matching and sorts alphabetically, instead of substring matching sorted by match position. That seems intentional and matches the spec, so no change needed, but it does change existing user-mention results, so maybe we should call it out somewhere for integrators.

Also, left two small comments.

onLinkPreviewClick: ((LinkPreview) -> Unit)? = null,
onCancelLinkPreviewClick: (() -> Unit)? = { viewModel.cancelLinkPreview() },
onUserSelected: (User) -> Unit = { viewModel.selectMention(it) },
onUserSelected: (User) -> Unit = {},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default for onUserSelected moved from { viewModel.selectMention(it) } to {}, and onMentionSelected now defaults to viewModel::selectMention. For a caller who passes a custom onUserSelected but no onMentionSelected, the default selectMention still runs, so for user taps both their handler and selectMention fire. With selectedMentions being a Set and the text insert being idempotent this is harmless in the common case, but a caller who overrode onUserSelected to replace or suppress the default selection would now get the mention inserted anyway. Is that intended? Might be worth a note for integrators who customized onUserSelected.

is Mention.User -> "user:${mention.user.id}"
is Mention.Channel -> "channel"
is Mention.Here -> "here"
is Mention.Role -> "role:${mention.role}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

itemsIndexed throws if two items produce the same key. Roles key on name (role:<name>), so if searchRoles ever returned two entries with the same name the list would crash. Role names are unique server-side so this is low risk, but a distinct() on the role results (or folding the index into the key) would remove the chance entirely. Worth guarding?

@andremion andremion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed that this user gate looks risky for Permissions V1 apps.
By default on V1, regular members don't get create-mention in own_capabilities (only admins do). But the user mentions work fine there because the server enforces create-mention on send only under V2. So gating user suggestions on it here would hide all user-mention suggestions for regular users on every V1 app, which is a regression from the current always-show behavior.
The iOS is keeping user suggestions ungated for exactly this reason.

Maybe we could drop the create-mention gate for users (matching the other SDKs), or only apply it when we know the channel is on V2?
The @channel/@here/role/group gates are fine; the issue might be with the user gate.

@andremion andremion self-requested a review June 19, 2026 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:new-feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants