Skip to content

Add enhanced mention suggestions#1497

Merged
nuno-vieira merged 32 commits into
developfrom
add/enchanced-user-mentions-ui
Jun 23, 2026
Merged

Add enhanced mention suggestions#1497
nuno-vieira merged 32 commits into
developfrom
add/enchanced-user-mentions-ui

Conversation

@nuno-vieira

@nuno-vieira nuno-vieira commented Jun 17, 2026

Copy link
Copy Markdown
Member

🔗 Issue Links

⚠️ Depends on unreleased LLC changes. This PR temporarily resolves StreamChat from the add/enhanced-user-mentions branch of stream-chat-swift (which is itself split into the stacked PRs #4137–#4142). The dependency will be pointed to the develop branch before merging.

🎯 Goal

Bring the enhanced mentions experience to the SwiftUI SDK: in addition to user mentions, the composer can now suggest and render @here, @channel, role and group mentions.

📝 Summary

  • Adopt the new MentionSuggestionsProvider from the LLC in MentionsCommandHandler.
  • Add a new MentionSuggestionsView rendering a dedicated cell per mention type (user, here, channel, role, group).
  • Highlight all mention types in rendered messages.
  • Enable the enhanced mention provider in the demo app.

🛠 Implementation

MentionSuggestion/MentionType are now extensible value types in the LLC, so the view switches over suggestion.kind to build each cell. The composer view model mirrors the LLC's send/draft paths for the new mention types. Mention suggestion logic and configuration live in the LLC behind MentionSuggestionsProvider, so SwiftUI only wires the provider and renders results.

🧪 Manual Testing Notes

In the demo app, open a channel and type @ to see user/here/channel suggestions, and @ followed by text to see users, roles and groups. Send the message and verify the mentions are highlighted.

☑️ Contributor Checklist

  • I have signed the Stream CLA (required)
  • This change should be manually QAed
  • Changelog is updated with client-facing changes
  • Changelog is updated with new localization keys
  • New code is covered by unit tests
  • Documentation has been updated in the docs-content repo

Summary by CodeRabbit

  • New Features
    • Enhanced composer mention suggestions now support @here, @channel, roles, and groups in addition to individual users.
  • Improvements
    • Mention state is more resilient while editing; sending messages includes richer mention metadata for supported mention types.
    • Message rendering consistently links @here, @channel, roles, and groups.
    • Updated mention suggestion accessibility labels/announcements and improved suggestion overlay behavior.
  • Tests
    • Expanded coverage for mention suggestions, composer mention parsing/state updates, command handling, and message rendering.

Use a sibling stream-chat-swift checkout when present so unreleased LLC
APIs (e.g. searchRoles) are available during local development, falling
back to the released package otherwise.
Introduce typed mention suggestions (users, @here, @channel, roles and
groups) with a configurable allowed set, matching the JS SDK behaviour:
broadcasts surface on a bare @ and roles use the searchRoles API. Track
the mentioned roles, groups, here and channel so they are sent with the
message.
Render dedicated cells for user, broadcast, role and group mentions and
wire them into the suggestions container.
Add unit tests covering the mention suggestion model and configuration.
Replace continuation-based controller calls with UserSearch, RoleSearch,
and UserGroupSearch, and update mention suggestion tests for async flow.
Move the mention suggestion types and logic to the core SDK and drive the
composer through a MentionSuggestionsProvider. Remove the composer-level
mention configuration, add a provider-based initializer to
MentionsCommandHandler, and use the enhanced provider in the demo app.
Match mention suggestion variants by casting the wrapped suggestion value
instead of switching over enum cases.
Use the renamed `kind` value and namespaced variant types when matching
mention suggestions.
Highlight roles, groups, @here and @channel mentions in addition to user
mentions, with group mentions shown by name.
Include @here, @channel, role and group mentions when creating draft
messages and replies from the composer.
Drop the obsolete mention suggestions config assertions now that mention
types are derived from the channel capabilities.
Temporarily resolve StreamChat from the add/enhanced-user-mentions LLC
branch until those changes are released.
@nuno-vieira
nuno-vieira requested a review from a team as a code owner June 17, 2026 18:39
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds enhanced composer mention suggestions for @here, @channel, roles, and groups. MentionsCommandHandler refactored to use an injected MentionSuggestionsProvider instead of internal user search. New MentionSuggestionsView UI components render all mention types. MessageComposerViewModel extended with role/group/here/channel state tracking. Attributed message rendering unified through a shared mention-link helper. CommandsConfig refactored with new EnhancedCommandsConfig. Demo app wired with new factory. stream-chat-swift dependency pinned to develop branch. Comprehensive test coverage added throughout.

Changes

Enhanced Mention Suggestions Feature

Layer / File(s) Summary
MentionsCommandHandler refactored to provider-based suggestions
Sources/StreamChatSwiftUI/ChatChannel/Utils/ChatChannelExtensions.swift, Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/MentionsCommandHandler.swift
Removes ChatUser.mentionText extension. Replaces internal user-search logic with injected MentionSuggestionsProvider; initializer updated to accept optional provider; convenience initializer retained for backwards compatibility. handleCommand now requires typingSuggestion and derives insertion text from extraData["mentionSuggestion"] or falls back to extraData["chatUser"]. Suggestion fetching rewritten as async Future via makeSuggestions, which constructs request, delegates to provider, and returns empty array when channel unavailable.
MentionSuggestionsView UI components and icons
Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/MentionSuggestionsView.swift
New MentionSuggestionsView renders suggestions in scrollable list with height clamping, count-based animation, and accessibility announcements. MentionSuggestionView row with kind-specific leading view (user avatar or circular icon), title formatting (@here, @channel, @<role>, @<group>, user name/id), and optional subtitle with group member counts. MentionIconView renders circular bordered template icon. MentionSuggestion extended with accessibilityName property.
SuggestionsContainerView and mention-type localization
Sources/StreamChatSwiftUI/ChatComposer/Suggestions/SuggestionsContainerView.swift, Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings
SuggestionsContainerView updated to prefer decoding suggestions["mentions"] as [MentionSuggestion] and render MentionSuggestionsView; fallback to [ChatUser] when cast fails. Localizable.strings expanded with channel/here/role/group mention descriptions, literal suggestion text, role member notification, and group member count display.
MessageComposerViewModel extended mention state and send flows
Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift
Adds public properties mentionedRoles, mentionedGroups, mentionsHere, mentionsChannel. clearMentions() helper resets all mention state; triggered when text becomes empty. checkForMentionedUsers accepts MentionSuggestion extraData and updates state per kind. clearRemovedMentions handles roles/groups and here/channel flags. showSuggestionsOverlay detects [MentionSuggestion]. sendMessage, createNewReply, and createNewMessage now include role names, group IDs, and here/channel flags in mention metadata.
ChatMessage attributed text mention-link generation for all types
Sources/StreamChatSwiftUI/Utils/Common/ChatMessage+Extensions.swift
Refactored to call shared addMentionLink(for:mentionId:in:) helper for each user, role, group, and special mentions. Helper locates all case-insensitive @<mentionText> occurrences, percent-encodes identifiers, constructs getstream://mention/… URL, and applies link to all matched ranges.
CommandsConfig refactored with EnhancedCommandsConfig
Sources/StreamChatSwiftUI/ChatComposer/Suggestions/CommandsConfig.swift
DefaultCommandsConfig updated with documentation and refactored to delegate instant-command construction to new @MainActor static makeCommandsHandler(mentionsCommandHandler:channelController:). New public EnhancedCommandsConfig provides mention symbols and makeCommandsHandler building MentionsCommandHandler with EnhancedMentionSuggestionsProvider, then reusing DefaultCommandsConfig static factory.
Demo app AppConfiguration factory and AppDelegate integration
DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift, DemoAppSwiftUI/AppDelegate.swift
AppConfiguration.makeCommandsConfig() added as @MainActor static factory returning EnhancedCommandsConfig(). AppDelegate.didFinishLaunchingWithOptions updated to initialize Utils with commandsConfig from factory.
Package and project dependency pin to develop branch
Package.swift, StreamChatSwiftUI.xcodeproj/project.pbxproj
stream-chat-swift dependency updated from fixed version to branch: "develop". Xcode project package reference and test file-system synchronized exception set updated accordingly.
MentionsCommandHandler comprehensive test suite
StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/MentionsCommandHandler_Tests.swift
Tests for canHandleCommand (mention token detection), commandHandler(for:) (ID matching), handleCommand (text replacement for all suggestion types, graceful edge case handling), and async showSuggestions(for:) with custom provider, request recording, error handling, and unavailable-channel behavior. Includes MockMentionSuggestionsProvider, Box binding utility, and test helpers.
MentionSuggestion unit and MentionSuggestionsView snapshot tests
StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/MentionSuggestion_Tests.swift, StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/MentionSuggestionsView_Tests.swift
MentionSuggestion_Tests verifies unique id per kind, kind matching, and mentionText output. MentionSuggestionsView_Tests adds snapshot tests under regular and liquid-glass container styles. Includes UserGroup.mock helpers for test data.
CommandsHandler and MuteCommandHandler tests modernized to async/Combine
StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/CommandsHandler_Tests.swift, StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/MuteCommandHandler_Tests.swift, StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/TestCommandsConfig.swift
Converted from synchronous waitForExpectations to async pattern with Combine subscriptions. Extract ChatUser from suggestion results via users(from:) helper. TestCommandsConfig removes ChatUserSearchController_Mock setup.
MessageComposerViewModel and MessageView tests for mention handling
StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift, StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift
MessageComposerViewModel_Tests adds comprehensive mention tests: checkForMentionedUsers for all kinds with deduplication, clearRemovedMentions validation, and showSuggestionsOverlay visibility. MessageView_Tests adds attributed-text mention-link unit test and snapshot test with all mention types. Includes private helpers for UserGroup construction and state population.
Changelog
CHANGELOG.md
Updates Upcoming section: removes emoji from "Added" header; adds bullet for enhanced composer mention suggestions with PR #1497 reference.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • GetStream/stream-chat-swiftui#1454: Modifies the stream-chat-swift Swift Package dependency in Package.swift, directly related to the branch-pin change in this PR.
  • GetStream/stream-chat-swiftui#1487: Also modifies the stream-chat-swift dependency declaration in Package.swift and Xcode project package reference, overlapping with this PR's dependency update.

Suggested reviewers

  • laevandus
  • martinmitrevski

🐇 I typed @here and @channel too,
Now roles and groups get mentions true!
The provider hops in with suggestions bright,
MentionSuggestionsView—what a delight!
My paws approved each attributed link,
Enhanced mentions faster than you'd think! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.52% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add enhanced mention suggestions' clearly and concisely summarizes the main change—introducing enhanced mention suggestions supporting multiple mention types beyond just users.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add/enchanced-user-mentions-ui

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.

@github-actions

Copy link
Copy Markdown
1 Warning
⚠️ Big PR

Generated by 🚫 Danger

@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.

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (1)
Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift (1)

308-310: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Hydrate all enhanced mention fields when pre-filling composer content.

fillEditedMessage/fillDraftMessage only restore mentionedUsers. The newly added role/group/here/channel state stays empty, so a subsequent draft update/send can drop mention metadata unless the user re-selects mentions.

💡 Suggested fix
@@
         text = message.text
         mentionedUsers = message.mentionedUsers
+        mentionedRoles = Set(message.mentionedRoles)
+        mentionedGroups = message.mentionedGroups
+        mentionsHere = message.mentionedHere
+        mentionsChannel = message.mentionedChannel
         showReplyInChannel = message.showReplyInChannel
@@
         text = message.text
         mentionedUsers = message.mentionedUsers
+        mentionedRoles = Set(message.mentionedRoles)
+        mentionedGroups = message.mentionedGroups
+        mentionsHere = message.mentionedHere
+        mentionsChannel = message.mentionedChannel
         quotedMessage?.wrappedValue = message.quotedMessage

Also applies to: 323-326

🤖 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 `@Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift` around
lines 308 - 310, The fillEditedMessage and fillDraftMessage methods currently
only restore the mentionedUsers field when pre-filling the composer, but fail to
restore the newly added enhanced mention state fields (such as role, group,
here, and channel mention flags). Add assignments in both methods to restore all
enhanced mention fields from the message object to their corresponding view
model properties, ensuring complete mention metadata is preserved and not
dropped on subsequent updates or sends.
🧹 Nitpick comments (1)
StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift (1)

207-207: ⚡ Quick win

Use AssertSnapshot for this new snapshot test.

This file is under StreamChatSwiftUITests/Tests/**, and the new assertion should use the test helper wrapper for consistency with project conventions.

🔧 Suggested change
-        assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
+        AssertSnapshot(view)

As per coding guidelines: "Prefer using AssertSnapshot from StreamChatTestHelpers instead of the SnapshotTesting framework directly for snapshot tests."

🤖 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 `@StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift` at line
207, The snapshot assertion in the MessageView_Tests file is using the direct
assertSnapshot call from SnapshotTesting framework instead of the AssertSnapshot
test helper wrapper. Replace the assertSnapshot function call (which takes the
parameters matching: view and as: .image(perceptualPrecision: precision)) with
the AssertSnapshot test helper to maintain consistency with project conventions
and coding guidelines for snapshot tests in the StreamChatSwiftUITests
directory.

Source: Coding guidelines

🤖 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.

Inline comments:
In `@CHANGELOG.md`:
- Around line 6-7: The CHANGELOG.md file under the `# Upcoming` section uses
non-standard subsection headings. Replace the current `### ✅ Added` heading with
`### Added` (removing the emoji) and add the missing sibling subsections `###
Fixed` and `### Changed` to match the Keep a Changelog format exactly.
Reorganize the existing content under the appropriate subsection based on its
nature.

In `@Package.swift`:
- Around line 19-22: The temporary branch reference `add/enhanced-user-mentions`
in the stream-chat-swift package dependency is not pinned to a specific
revision, which causes non-deterministic builds as the branch can be updated
upstream. Replace the branch parameter with a revision parameter set to a
specific commit hash (e.g., `8ed426cc1808be079192143fd866bf984989d97a`) in the
.package declaration for the stream-chat-swift dependency in Package.swift.
Additionally, ensure the same commit hash revision is also updated in the Xcode
project configuration file (StreamChatSwiftUI.xcodeproj/project.pbxproj) to
maintain consistency across both dependency management systems.

In
`@Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/MentionsCommandHandler.swift`:
- Around line 132-137: In the Future closure within the method that handles
typing mentions, when the guard let self check fails, the early return statement
exits without resolving the promise, leaving subscribers waiting indefinitely.
Fix this by calling unsafePromise with either a failure result or a default
empty success value (such as SuggestionInfo with an empty suggestions array)
before the early return, ensuring the promise is always resolved regardless of
self's lifecycle state.
- Around line 28-44: The convenience initializer in MentionsCommandHandler is
accepting a userSearchController parameter but silently ignoring it, which
changes runtime behavior for existing integrators. Either pass the
userSearchController parameter to the DefaultMentionSuggestionsProvider
initialization if it supports it, or mark the userSearchController parameter as
deprecated using the `@available`(*, deprecated, message:) attribute to warn users
that it is no longer used while maintaining source compatibility.

In
`@Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/MentionSuggestionsView.swift`:
- Around line 38-44: The accessibility hint in the MentionSuggestionsView is
using a hardcoded user-specific localization string
(L10n.Composer.Suggestions.User.accessibilityLabel) with an empty label
argument, which produces incorrect VoiceOver output for non-user mentions like
`@here`, `@channel`, roles, and groups. Fix this by determining the actual
suggestion type (user, special mention, role, group, etc.) and selecting the
appropriate localization string based on that type, then pass the actual item
name or label instead of an empty string as the first argument to ensure
VoiceOver correctly identifies each mention type.

In `@Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings`:
- Around line 234-238: The accessibility announcement string for the key
"composer.suggestions.mentions.accessibility-announcement" currently says "User
list, %d results" but this is inaccurate since the suggestion types have
expanded to include channel, here, role, and group mention options in addition
to users. Update this string to reflect a more generic description of the
suggestions list that accurately conveys what the user will hear when these
expanded suggestion types appear, rather than specifically referencing just a
user list.

---

Outside diff comments:
In `@Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift`:
- Around line 308-310: The fillEditedMessage and fillDraftMessage methods
currently only restore the mentionedUsers field when pre-filling the composer,
but fail to restore the newly added enhanced mention state fields (such as role,
group, here, and channel mention flags). Add assignments in both methods to
restore all enhanced mention fields from the message object to their
corresponding view model properties, ensuring complete mention metadata is
preserved and not dropped on subsequent updates or sends.

---

Nitpick comments:
In `@StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift`:
- Line 207: The snapshot assertion in the MessageView_Tests file is using the
direct assertSnapshot call from SnapshotTesting framework instead of the
AssertSnapshot test helper wrapper. Replace the assertSnapshot function call
(which takes the parameters matching: view and as: .image(perceptualPrecision:
precision)) with the AssertSnapshot test helper to maintain consistency with
project conventions and coding guidelines for snapshot tests in the
StreamChatSwiftUITests directory.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9466f3d2-d845-4e56-befd-53753880b6a3

📥 Commits

Reviewing files that changed from the base of the PR and between b51228e and 0c7a164.

⛔ Files ignored due to path filters (10)
  • Sources/StreamChatSwiftUI/Generated/L10n.swift is excluded by !**/generated/**
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/MentionSuggestionsView_Tests/test_mentionSuggestionsView_liquidGlassStyle.default-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/MentionSuggestionsView_Tests/test_mentionSuggestionsView_liquidGlassStyle.extraExtraExtraLarge-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/MentionSuggestionsView_Tests/test_mentionSuggestionsView_liquidGlassStyle.rightToLeftLayout-default.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/MentionSuggestionsView_Tests/test_mentionSuggestionsView_liquidGlassStyle.small-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/MentionSuggestionsView_Tests/test_mentionSuggestionsView_regularStyle.default-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/MentionSuggestionsView_Tests/test_mentionSuggestionsView_regularStyle.extraExtraExtraLarge-light.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/MentionSuggestionsView_Tests/test_mentionSuggestionsView_regularStyle.rightToLeftLayout-default.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/MentionSuggestionsView_Tests/test_mentionSuggestionsView_regularStyle.small-dark.png is excluded by !**/*.png
  • StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewTextMentionAllTypes_snapshot.1.png is excluded by !**/*.png
📒 Files selected for processing (21)
  • CHANGELOG.md
  • DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift
  • DemoAppSwiftUI/AppDelegate.swift
  • Package.swift
  • Sources/StreamChatSwiftUI/ChatChannel/Utils/ChatChannelExtensions.swift
  • Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift
  • Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/MentionSuggestionsView.swift
  • Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/MentionsCommandHandler.swift
  • Sources/StreamChatSwiftUI/ChatComposer/Suggestions/SuggestionsContainerView.swift
  • Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings
  • Sources/StreamChatSwiftUI/Utils/Common/ChatMessage+Extensions.swift
  • StreamChatSwiftUI.xcodeproj/project.pbxproj
  • StreamChatSwiftUITests/Infrastructure/Mocks/ChatMessageControllerSUI_Mock.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/CommandsHandler_Tests.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/MentionSuggestion_Tests.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/MentionSuggestionsView_Tests.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/MentionsCommandHandler_Tests.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/MuteCommandHandler_Tests.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/TestCommandsConfig.swift
💤 Files with no reviewable changes (2)
  • StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/TestCommandsConfig.swift
  • Sources/StreamChatSwiftUI/ChatChannel/Utils/ChatChannelExtensions.swift

Comment thread CHANGELOG.md Outdated
Comment thread Package.swift Outdated
Comment thread Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings Outdated

@martinmitrevski martinmitrevski 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.

lgtm - just left few smaller comments

Comment thread DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift Outdated
Comment thread Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift Outdated
Replace suggestion.mentionText and suggestion.type usages with kind
type-casting. The mentionText derivation is now an instance method on
MentionsCommandHandler with localized strings for @here and @channel.
@nuno-vieira
nuno-vieira force-pushed the add/enchanced-user-mentions-ui branch from 17fd69d to 671c7a2 Compare June 19, 2026 22:10
@github-actions

Copy link
Copy Markdown

Public Interface

+ public struct MentionSuggestionView: View  
+ 
+   public var body: some View
+   
+ 
+   public init(factory: Factory = DefaultViewFactory.shared,suggestion: MentionSuggestion,suggestionSelected: @escaping (MentionSuggestion) -> Void)

+ public struct MentionSuggestionsView: View  
+ 
+   public var body: some View
+   
+ 
+   public init(factory: Factory = DefaultViewFactory.shared,suggestions: [MentionSuggestion],suggestionSelected: @escaping (MentionSuggestion) -> Void)



 @MainActor open class MessageComposerViewModel: ObservableObject  
-   public var canSendMessage: Bool
+   public var mentionedRoles
-   public var hasContent: Bool
+   public var mentionedGroups
-   public var composerInputState: MessageComposerInputState
+   public var mentionsHere
-   public var shouldShowRecordingGestureOverlay: Bool
+   public var mentionsChannel
-   public var sendInChannelShown: Bool
+   public var canSendMessage: Bool
-   public var isDirectChannel: Bool
+   public var hasContent: Bool
-   public var showSuggestionsOverlay: Bool
+   public var composerInputState: MessageComposerInputState
-   
+   public var shouldShowRecordingGestureOverlay: Bool
- 
+   public var sendInChannelShown: Bool
-   public init(channelController: ChatChannelController,messageController: ChatMessageController?,eventsController: EventsController? = nil,quotedMessage: Binding<ChatMessage?>? = nil,editedMessage: Binding<ChatMessage?>? = nil,willSendMessage: (() -> Void)? = nil)
+   public var isDirectChannel: Bool
-   
+   public var showSuggestionsOverlay: Bool
- 
+   
-   public func addFileURLs(_ urls: [URL])
+ 
-   public func fillEditedMessage(_ editedMessage: ChatMessage?)
+   public init(channelController: ChatChannelController,messageController: ChatMessageController?,eventsController: EventsController? = nil,quotedMessage: Binding<ChatMessage?>? = nil,editedMessage: Binding<ChatMessage?>? = nil,willSendMessage: (() -> Void)? = nil)
-   public func fillDraftMessage()
+   
-   public func updateDraftMessage(quotedMessage: ChatMessage?,isSilent: Bool = false,extraData: [String: RawJSON] = [:])
+ 
-   public func deleteDraftMessage()
+   public func addFileURLs(_ urls: [URL])
-   open func sendMessage(isSilent: Bool = false,skipPush: Bool = false,skipEnrichUrl: Bool = false,extraData: [String: RawJSON] = [:],completion: (@MainActor () -> Void)? = nil)
+   public func fillEditedMessage(_ editedMessage: ChatMessage?)
-   public func change(pickerState: AttachmentPickerState)
+   public func fillDraftMessage()
-   public func imageTapped(_ addedAsset: AddedAsset)
+   public func updateDraftMessage(quotedMessage: ChatMessage?,isSilent: Bool = false,extraData: [String: RawJSON] = [:])
-   public func imagePasted(_ image: UIImage)
+   public func deleteDraftMessage()
-   public func removeAttachment(with id: String)
+   open func sendMessage(isSilent: Bool = false,skipPush: Bool = false,skipEnrichUrl: Bool = false,extraData: [String: RawJSON] = [:],completion: (@MainActor () -> Void)? = nil)
-   public func cameraImageAdded(_ image: AddedAsset)
+   public func change(pickerState: AttachmentPickerState)
-   public func isImageSelected(with id: String)-> Bool
+   public func imageTapped(_ addedAsset: AddedAsset)
-   public func customAttachmentTapped(_ attachment: CustomAttachment)
+   public func imagePasted(_ image: UIImage)
-   public func isCustomAttachmentSelected(_ attachment: CustomAttachment)-> Bool
+   public func removeAttachment(with id: String)
-   public func askForPhotosPermission()
+   public func cameraImageAdded(_ image: AddedAsset)
-   public func handleCommand(for text: Binding<String>,selectedRangeLocation: Binding<Int>,command: Binding<ComposerCommand?>,extraData: [String: Any])
+   public func isImageSelected(with id: String)-> Bool
-   open func convertAddedAssetsToPayloads()throws -> [AnyAttachmentPayload]
+   public func customAttachmentTapped(_ attachment: CustomAttachment)
-   public func checkForMentionedUsers(commandId: String?,extraData: [String: Any])
+   public func isCustomAttachmentSelected(_ attachment: CustomAttachment)-> Bool
-   public func clearRemovedMentions()
+   public func askForPhotosPermission()
-   public func clearInputData()
+   public func handleCommand(for text: Binding<String>,selectedRangeLocation: Binding<Int>,command: Binding<ComposerCommand?>,extraData: [String: Any])
-   public func checkChannelCooldown()
+   open func convertAddedAssetsToPayloads()throws -> [AnyAttachmentPayload]
-   public func updateAddedAssets(_ assets: [AddedAsset])
+   public func checkForMentionedUsers(commandId: String?,extraData: [String: Any])
+   public func clearRemovedMentions()
+   public func clearInputData()
+   public func checkChannelCooldown()
+   public func updateAddedAssets(_ assets: [AddedAsset])

 public final class MentionsCommandHandler: CommandHandler  
-   public init(channelController: ChatChannelController,userSearchController: ChatUserSearchController? = nil,commandSymbol: String,mentionAllAppUsers: Bool,id: String = "mentions")
+   public convenience init(channelController: ChatChannelController,userSearchController: ChatUserSearchController? = nil,commandSymbol: String,mentionAllAppUsers: Bool,id: String = "mentions")
-   
+   public init(channelController: ChatChannelController,commandSymbol: String,provider: MentionSuggestionsProvider? = nil,id: String = "mentions")
- 
+   
-   public func canHandleCommand(in text: String,caretLocation: Int)-> ComposerCommand?
+ 
-   public func handleCommand(for text: Binding<String>,selectedRangeLocation: Binding<Int>,command: Binding<ComposerCommand?>,extraData: [String: Any])
+   public func canHandleCommand(in text: String,caretLocation: Int)-> ComposerCommand?
-   public func commandHandler(for command: ComposerCommand)-> CommandHandler?
+   public func handleCommand(for text: Binding<String>,selectedRangeLocation: Binding<Int>,command: Binding<ComposerCommand?>,extraData: [String: Any])
-   public func showSuggestions(for command: ComposerCommand)-> Future<SuggestionInfo, Error>
+   public func commandHandler(for command: ComposerCommand)-> CommandHandler?
+   public func showSuggestions(for command: ComposerCommand)-> Future<SuggestionInfo, Error>

- Use L10n strings for @here and @channel titles
- Update accessibility announcement from "User list" to "Mention suggestions"
- Use per-suggestion accessibility label with the actual item name
Move the enhanced mentions commands config from the DemoApp into the
SDK as EnhancedCommandsConfig so customers can use it directly.

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@Sources/StreamChatSwiftUI/ChatComposer/Suggestions/CommandsConfig.swift`:
- Line 89: The renaming of the public class from EnhancedCommandsConfig to
EnhancedMentionsCommandsConfig introduces a source-breaking change. Add a
deprecated typealias with the old name EnhancedCommandsConfig that points to the
new EnhancedMentionsCommandsConfig at the same scope level, and mark it with the
appropriate deprecation warning annotation to inform users of the API change
while maintaining backward compatibility for existing code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8907d4eb-9758-4208-b5a6-c1768b849b89

📥 Commits

Reviewing files that changed from the base of the PR and between 0a68f57 and 0141669.

📒 Files selected for processing (2)
  • DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift
  • Sources/StreamChatSwiftUI/ChatComposer/Suggestions/CommandsConfig.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift

Comment thread CHANGELOG.md Outdated
@nuno-vieira
nuno-vieira enabled auto-merge (squash) June 22, 2026 16:23

@martinmitrevski martinmitrevski 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.

LGTM! ✅

@nuno-vieira
nuno-vieira disabled auto-merge June 23, 2026 09:51
@nuno-vieira
nuno-vieira merged commit d593968 into develop Jun 23, 2026
6 of 8 checks passed
@nuno-vieira
nuno-vieira deleted the add/enchanced-user-mentions-ui branch June 23, 2026 09:51
@Stream-SDK-Bot

Copy link
Copy Markdown
Collaborator

SDK Size

title develop branch diff status
StreamChatSwiftUI 8.25 MB 8.33 MB +74 KB 🟢

@Stream-SDK-Bot

Copy link
Copy Markdown
Collaborator

StreamChatSwiftUI XCSize

Object Diff (bytes)
MentionSuggestionsView.o +25611
MessageComposerViewModel.o +7202
MentionsCommandHandler.o -4768
MessageItemView.o +3052
MessageComposerView.o +2036
Show 51 more objects
Object Diff (bytes)
ChatThreadListNavigatableItem.o +1688
L10n.o +1529
SuggestionsContainerView.o +1335
PinnedMessagesView.o +1320
MessageView.o +1292
MessageListView.o +1204
ChatChannelHeaderViewModifier.o +1180
ChatChannelSwipeableListItem.o +1172
ChatChannelNavigatableListItem.o +1160
ReactionsOverlayContainer.o +1060
ChatQuotedMessageView.o +1040
ReactionsOverlayView.o +972
DefaultMessageAttachmentsViewModifier.o +964
ChatChannelInfoViewModel.o -934
MessageContainerView.o +908
MessageRepliesView.o +880
PollAttachmentView.o +780
MessageTopView.o +740
ChatChannelListViewModel.o +700
ReactionsView.o +664
MediaViewer.o +564
TwoStepMentionCommand.o +524
MoreChannelActionsView.o +496
UserSuggestionsView.o -488
PollResultsView.o +476
TypingIndicatorView.o +464
MessageMediaAttachmentsContainerView.o +448
VoiceRecordingContainerView.o +400
GiphyAttachmentView.o +364
FileAttachmentView.o +364
DefaultMessageActions.o -352
ChatMessage+Extensions.o +344
ComposerQuotedMessageView.o +344
ReactionsBubbleView.o +340
AttachmentTextView.o +340
DeletedMessageView.o +332
MessageAttachmentsView.o +332
MuteCommandHandler.o +330
LinkAttachmentView.o +276
CommandsConfig.o +272
MessageAttachmentPreviewResolver.o +236
FileAttachmentsViewModel.o +220
DefaultViewFactory.o +216
StreamChat +212
ChatChannelListItemPreviewView.o +204
MessageBubble.o +188
UnmuteCommandHandler.o +160
MessageListHelperViews.o +118
DefaultChannelActions.o +96
ChatChannelInfoView.o +48
ChatThreadList.o +48

@Stream-SDK-Bot Stream-SDK-Bot mentioned this pull request Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants