mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 21:32:34 +00:00
Rank the mention suggestions by how well they match what was typed
The member suggestions were emitted in whatever order the room member list happened to be in, so a member who only matches somewhere in the middle of their name could be offered above one whose name starts with the query. Matches are now ordered by how well they match: display name prefix first, then user ID localpart prefix, then any other match. The sort is stable, so members of equal rank keep the order the member list gave them. The @room suggestion was also matched case sensitively, so typing @Ro or @ROOM dropped it while @ro kept it. It now matches the query the same way the members do.
This commit is contained in:
+14
-1
@@ -115,9 +115,10 @@ class SuggestionsProcessor(
|
||||
.filterUpTo(MAX_BATCH_ITEMS) { member ->
|
||||
isJoinedMemberAndNotSelf(member) && memberMatchesQuery(member, query)
|
||||
}
|
||||
.sortedBy { member -> matchRank(member, query) }
|
||||
.map(ResolvedSuggestion::Member)
|
||||
|
||||
if ("room".contains(query) && canSendRoomMention) {
|
||||
if ("room".startsWith(query, ignoreCase = true) && canSendRoomMention) {
|
||||
listOf(ResolvedSuggestion.AtRoom) + matchingMembers
|
||||
} else {
|
||||
matchingMembers
|
||||
@@ -125,6 +126,18 @@ class SuggestionsProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Members whose display name starts with the query come first, then members whose user id
|
||||
* localpart starts with it, then the remaining matches on any other part of the name or id.
|
||||
*/
|
||||
private fun matchRank(member: RoomMember, query: String): Int {
|
||||
return when {
|
||||
member.displayName?.startsWith(query, ignoreCase = true) == true -> 0
|
||||
member.userId.extractedDisplayName.startsWith(query, ignoreCase = true) -> 1
|
||||
else -> 2
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
// We don't want to retrieve thousands of members
|
||||
private const val MAX_BATCH_ITEMS = 100
|
||||
|
||||
+42
@@ -383,6 +383,48 @@ class SuggestionsProcessorTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `processing Mention suggestion returns the members matching the start of the query first`() = runTest {
|
||||
val matchingOnAnyPart = aRoomMember(userId = UserId("@carol:server.org"), displayName = "Not Alice")
|
||||
val matchingOnUserIdStart = aRoomMember(userId = UserId("@alicia:server.org"), displayName = null)
|
||||
val matchingOnDisplayNameStart = aRoomMember(userId = UserId("@zoe:server.org"), displayName = "Alice")
|
||||
val result = suggestionsProcessor.process(
|
||||
suggestion = aMentionSuggestion("ali"),
|
||||
roomMembersState = RoomMembersState.Ready(
|
||||
persistentListOf(matchingOnAnyPart, matchingOnUserIdStart, matchingOnDisplayNameStart)
|
||||
),
|
||||
roomAliasSuggestions = emptyList(),
|
||||
currentUserId = A_USER_ID_2,
|
||||
canSendRoomMention = { false },
|
||||
isInThread = false,
|
||||
)
|
||||
assertThat(result).isEqualTo(
|
||||
listOf(
|
||||
ResolvedSuggestion.Member(matchingOnDisplayNameStart),
|
||||
ResolvedSuggestion.Member(matchingOnUserIdStart),
|
||||
ResolvedSuggestion.Member(matchingOnAnyPart),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `processing Mention suggestion returns room ignoring the case of the query`() = runTest {
|
||||
val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "alice")
|
||||
val result = suggestionsProcessor.process(
|
||||
suggestion = aMentionSuggestion("RO"),
|
||||
roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember)),
|
||||
roomAliasSuggestions = emptyList(),
|
||||
currentUserId = A_USER_ID_2,
|
||||
canSendRoomMention = { true },
|
||||
isInThread = false,
|
||||
)
|
||||
assertThat(result).isEqualTo(
|
||||
listOf(
|
||||
ResolvedSuggestion.AtRoom,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `processing Mention suggestion with return matching display name but not room if not allowed`() = runTest {
|
||||
val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "ro")
|
||||
|
||||
Reference in New Issue
Block a user