diff --git a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/typing/TypingSuggester.kt b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/typing/TypingSuggester.kt index b32e18fcd39..02c7f8681ee 100644 --- a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/typing/TypingSuggester.kt +++ b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/typing/TypingSuggester.kt @@ -58,6 +58,11 @@ internal class TypingSuggester(private val options: TypingSuggestionOptions) { } val suggestionText = text.substring(suggestionStart, caretLocation) + // A suggestion cannot start with whitespace: typing a space right after the symbol ends it (e.g. "@ "), + // while internal spaces stay allowed so multi-word names like "@John Doe" remain searchable. + if (suggestionText.firstOrNull()?.isWhitespace() == true) { + return null + } if (suggestionText.length < options.minimumRequiredCharacters) { return null } diff --git a/stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/typing/TypingSuggesterTest.kt b/stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/typing/TypingSuggesterTest.kt new file mode 100644 index 00000000000..bf4b278b15c --- /dev/null +++ b/stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/typing/TypingSuggesterTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * 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.getstream.chat.android.ui.common.feature.messages.composer.typing + +import org.amshove.kluent.`should be equal to` +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource + +internal class TypingSuggesterTest { + + private val suggester = TypingSuggester(TypingSuggestionOptions(symbol = "@")) + + @ParameterizedTest(name = "[{index}] text=\"{0}\" -> {1}") + @MethodSource("provideCases") + fun `typingSuggestion resolves the mention token`(text: String, expected: TypingSuggestion?) { + val suggestion = suggester.typingSuggestion(text) + + suggestion `should be equal to` expected + } + + companion object { + + @JvmStatic + fun provideCases(): List = listOf( + Arguments.of("@", TypingSuggestion("", IntRange(1, 0))), + Arguments.of("@john", TypingSuggestion("john", 1 until 5)), + Arguments.of("Hello @john", TypingSuggestion("john", 7 until 11)), + Arguments.of("@John Doe", TypingSuggestion("John Doe", 1 until 9)), + Arguments.of("@john ", TypingSuggestion("john ", 1 until 6)), + Arguments.of("@ ", null), + Arguments.of("@ john", null), + Arguments.of("Hello@john", null), + ) + } +}