diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt index f066303433..22b4ef5515 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt @@ -28,6 +28,7 @@ import com.vitorpamplona.amethyst.logTime import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.relayClient.searchCommand.SearchQueryState +import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.normalizeRelayUrlOrNull import com.vitorpamplona.quartz.nip05DnsIdentifiers.INip05Client @@ -58,10 +59,20 @@ val userUriPrefixes = DualCase("nostr:nprofile"), ) +/** + * Drives the @-mention autocomplete dropdown: searches the local cache, + * relays, and NIP-05 identifiers for the word currently being typed. + * + * [priorityPubkeys] is a live supplier of pubkeys to rank first in the + * results — pass the current conversation's participants (NIP-17 room + * users, public-chat authors, MLS group members, …) so they beat + * network-wide matches. Ranking only; it never filters anyone out. + */ @Stable class UserSuggestionState( val account: Account, val nip05Client: INip05Client, + val priorityPubkeys: () -> Set = { emptySet() }, ) { val invalidations = MutableStateFlow(0) val currentWord = MutableStateFlow("") @@ -158,7 +169,13 @@ class UserSuggestionState( } if (prefix != null) { logTime("UserSuggestionState Search $prefix version $version") { - account.cache.findUsersStartingWith(prefix, account) + val found = account.cache.findUsersStartingWith(prefix, account) + val priority = priorityPubkeys() + if (priority.isEmpty()) { + found + } else { + found.sortedByDescending { it.pubkeyHex in priority } + } } } else { emptyList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt index 16952c4a7f..b9b0f2d1c7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt @@ -190,7 +190,12 @@ fun MarmotGroupMessageComposer( val userSuggestions = remember(nostrGroupId) { - UserSuggestionState(accountViewModel.account, accountViewModel.nip05ClientBuilder()) + val group = accountViewModel.account.marmotGroupList.getOrCreateGroup(nostrGroupId) + UserSuggestionState( + accountViewModel.account, + accountViewModel.nip05ClientBuilder(), + priorityPubkeys = { group.members.value.mapTo(mutableSetOf()) { it.pubkey } }, + ) } DisposableEffect(nostrGroupId) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt index 45d481b0af..8bbc1f2fe6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt @@ -261,7 +261,12 @@ class ChatNewMessageViewModel : this.canAddZapRaiser = hasLnAddress() this.userSuggestions?.reset() - this.userSuggestions = UserSuggestionState(accountVM.account, accountVM.nip05ClientBuilder()) + this.userSuggestions = + UserSuggestionState( + accountVM.account, + accountVM.nip05ClientBuilder(), + priorityPubkeys = { room.value?.users ?: emptySet() }, + ) this.emojiSuggestions?.reset() this.emojiSuggestions = EmojiSuggestionState(accountVM.account) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt index f826189c6d..0364ce4dcc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt @@ -188,7 +188,14 @@ open class ChannelNewMessageViewModel : this.canAddZapRaiser = hasLnAddress() this.userSuggestions?.reset() - this.userSuggestions = UserSuggestionState(accountVM.account, accountVM.nip05ClientBuilder()) + this.userSuggestions = + UserSuggestionState( + accountVM.account, + accountVM.nip05ClientBuilder(), + priorityPubkeys = { + channel?.participatingAuthors(0)?.mapTo(mutableSetOf()) { it.pubkeyHex } ?: emptySet() + }, + ) this.emojiSuggestions?.reset() this.emojiSuggestions = EmojiSuggestionState(accountVM.account) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt index 4357b1eda9..878db35bce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt @@ -194,7 +194,16 @@ open class NestNewMessageViewModel : this.canAddZapRaiser = hasLnAddress() this.userSuggestions?.reset() - this.userSuggestions = UserSuggestionState(accountVM.account, accountVM.nip05ClientBuilder()) + this.userSuggestions = + UserSuggestionState( + accountVM.account, + accountVM.nip05ClientBuilder(), + priorityPubkeys = { + (room?.event as? MeetingSpaceEvent)?.let { space -> + space.participantKeys().toMutableSet().apply { add(space.pubKey) } + } ?: emptySet() + }, + ) this.emojiSuggestions?.reset() this.emojiSuggestions = EmojiSuggestionState(accountVM.account)