feat: mention autocomplete
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
924568a7b3
commit
6ac347ef07
|
|
@ -38,4 +38,10 @@ class Members {
|
|||
member.nickname?.let { userId to member.nickname }
|
||||
}?.toMap() ?: emptyMap()
|
||||
}
|
||||
|
||||
fun filterNamesFor(serverId: String, query: String): List<Member> {
|
||||
return memberCache[serverId]?.values?.filter { member ->
|
||||
member.nickname?.contains(query, ignoreCase = true) ?: false
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ import chat.revolt.api.REVOLT_FILES
|
|||
import chat.revolt.api.schemas.ChannelType
|
||||
import chat.revolt.api.schemas.Member
|
||||
import chat.revolt.components.generic.RemoteImage
|
||||
import chat.revolt.components.generic.UserAvatar
|
||||
import chat.revolt.components.screens.chat.ChannelIcon
|
||||
import chat.revolt.internals.Autocomplete
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
@ -155,9 +157,9 @@ fun NativeMessageField(
|
|||
modifier: Modifier = Modifier,
|
||||
forceSendButton: Boolean = false,
|
||||
disabled: Boolean = false,
|
||||
editMode: Boolean = false,
|
||||
serverId: String? = null,
|
||||
channelId: String? = null,
|
||||
editMode: Boolean = false,
|
||||
cancelEdit: () -> Unit = {},
|
||||
onFocusChange: (Boolean) -> Unit = {},
|
||||
onSelectionChange: (Pair<Int, Int>) -> Unit = {}
|
||||
|
|
@ -247,10 +249,15 @@ fun NativeMessageField(
|
|||
},
|
||||
label = { Text("@${item.user.username}#${item.user.discriminator}") },
|
||||
icon = {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_human_greeting_variant_24dp),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(SuggestionChipDefaults.IconSize)
|
||||
UserAvatar(
|
||||
username = item.user.username
|
||||
?: stringResource(R.string.unknown),
|
||||
userId = item.user.id ?: "",
|
||||
avatar = item.user.avatar,
|
||||
rawUrl = item.member?.avatar?.id?.let {
|
||||
"$REVOLT_FILES/avatars/$it?max_side=64"
|
||||
},
|
||||
size = SuggestionChipDefaults.IconSize,
|
||||
)
|
||||
},
|
||||
modifier = Modifier
|
||||
|
|
@ -270,11 +277,7 @@ fun NativeMessageField(
|
|||
},
|
||||
label = { Text("#${item.channel.name}") },
|
||||
icon = {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_pound_24dp),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(SuggestionChipDefaults.IconSize)
|
||||
)
|
||||
item.channel.channelType?.let { type -> ChannelIcon(channelType = type) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.animateItemPlacement()
|
||||
|
|
@ -360,6 +363,8 @@ fun NativeMessageField(
|
|||
AndroidView(
|
||||
factory = { context ->
|
||||
object : androidx.appcompat.widget.AppCompatEditText(context) {
|
||||
var serverId: String? = null
|
||||
|
||||
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
|
||||
var ic = super.onCreateInputConnection(outAttrs)
|
||||
EditorInfoCompat.setContentMimeTypes(
|
||||
|
|
@ -402,6 +407,17 @@ fun NativeMessageField(
|
|||
Autocomplete.emoji(lastWord.substring(1))
|
||||
)
|
||||
}
|
||||
|
||||
lastWord.startsWith('@') -> {
|
||||
if (channelId == null) return
|
||||
autocompleteSuggestions.addAll(
|
||||
Autocomplete.user(
|
||||
channelId,
|
||||
this.serverId,
|
||||
lastWord.substring(1)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.apply {
|
||||
|
|
@ -489,6 +505,7 @@ fun NativeMessageField(
|
|||
it.setSelection(value.length)
|
||||
}
|
||||
it.hint = it.context.getString(placeholderResource, channelName)
|
||||
it.serverId = serverId
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package chat.revolt.internals
|
||||
|
||||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.api.schemas.ChannelType
|
||||
import chat.revolt.components.chat.AutocompleteSuggestion
|
||||
|
||||
object Autocomplete {
|
||||
|
|
@ -33,4 +34,104 @@ object Autocomplete {
|
|||
|
||||
return (unicodeResults + customResults)
|
||||
}
|
||||
|
||||
fun user(
|
||||
channelId: String,
|
||||
serverId: String? = null,
|
||||
query: String
|
||||
): List<AutocompleteSuggestion.User> {
|
||||
val channel = RevoltAPI.channelCache[channelId] ?: return emptyList()
|
||||
|
||||
return when (channel.channelType) {
|
||||
ChannelType.DirectMessage -> {
|
||||
val otherUser = channel.recipients?.find { it != RevoltAPI.selfId }
|
||||
if (otherUser != null) {
|
||||
val user = RevoltAPI.userCache[otherUser]
|
||||
if (user != null && user.username?.contains(query) == true) {
|
||||
listOf(
|
||||
AutocompleteSuggestion.User(
|
||||
user,
|
||||
null,
|
||||
query
|
||||
)
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
ChannelType.Group -> {
|
||||
val users =
|
||||
channel.recipients?.mapNotNull { RevoltAPI.userCache[it] } ?: emptyList()
|
||||
users
|
||||
.filter { it.username?.contains(query) ?: false }
|
||||
.map {
|
||||
AutocompleteSuggestion.User(
|
||||
it,
|
||||
null,
|
||||
query
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ChannelType.SavedMessages -> {
|
||||
val user = RevoltAPI.userCache[RevoltAPI.selfId]
|
||||
return if (user != null && user.username?.contains(query) == true) {
|
||||
listOf(
|
||||
AutocompleteSuggestion.User(
|
||||
user,
|
||||
null,
|
||||
query
|
||||
)
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
ChannelType.TextChannel, ChannelType.VoiceChannel -> {
|
||||
if (serverId == null) return emptyList()
|
||||
if (query.length < 2) return emptyList()
|
||||
|
||||
val byNickname = RevoltAPI.members.filterNamesFor(serverId, query)
|
||||
.map { m -> m to RevoltAPI.userCache[m.id?.user] }.filter { (_, u) ->
|
||||
u != null
|
||||
}.map { (m, u) ->
|
||||
m to u!!
|
||||
}
|
||||
val byUsername = RevoltAPI.userCache.values.filter {
|
||||
it.username?.contains(
|
||||
query,
|
||||
ignoreCase = true
|
||||
) ?: false
|
||||
}.mapNotNull {
|
||||
it.id?.let { _ ->
|
||||
RevoltAPI.members.getMember(
|
||||
serverId,
|
||||
it.id
|
||||
) to it
|
||||
}
|
||||
}.filter { (member, _) ->
|
||||
member != null
|
||||
}.map { (member, user) ->
|
||||
member!! to user
|
||||
}
|
||||
|
||||
val all = (byNickname + byUsername).distinctBy { it.first.id }
|
||||
|
||||
all.map {
|
||||
AutocompleteSuggestion.User(
|
||||
it.second,
|
||||
it.first,
|
||||
query
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
null -> emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -519,6 +519,8 @@ fun ChannelScreen(
|
|||
),
|
||||
forceSendButton = viewModel.pendingAttachments.isNotEmpty(),
|
||||
disabled = viewModel.pendingAttachments.isNotEmpty() && viewModel.isSendingMessage,
|
||||
channelId = channelId,
|
||||
serverId = channel?.server,
|
||||
editMode = viewModel.editingMessage != null,
|
||||
cancelEdit = viewModel::cancelEditingMessage,
|
||||
onFocusChange = { nowFocused ->
|
||||
|
|
|
|||
Loading…
Reference in New Issue