Take into account homeserver capabilities (#6507)
* Take into account homeserver capabilities: add `HomeserverCapabilitiesProvider` to check if the HS allows changing the user's display name or avatar. Also, modify the edit user profile screen to reflect these values. * Add `/myavatar` command. Filter both `/nick` and `/myavatar` commands based on the homeserver capabilities. * Update screenshots * Assume the use can change their display name and avatar url if the capabilities check fails: if they try to change those, the HS will return an error anyway. * Disable also `/myroomname` and `/myroomavatar` based on the HS capabilities. --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
parent
15419bb675
commit
b66df37f3e
26 changed files with 363 additions and 14 deletions
|
|
@ -120,6 +120,15 @@ enum class Command(
|
|||
isDevCommand = true,
|
||||
isSupported = false,
|
||||
),
|
||||
CHANGE_AVATAR(
|
||||
command = "/myavatar",
|
||||
parameters = "<mxc_url>",
|
||||
description = R.string.slash_command_description_avatar,
|
||||
isAllowedInThread = false,
|
||||
// Dev command since user has to know the mxc url
|
||||
isDevCommand = true,
|
||||
isSupported = false,
|
||||
),
|
||||
CHANGE_AVATAR_FOR_ROOM(
|
||||
command = "/myroomavatar",
|
||||
parameters = "<mxc_url>",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class CommandExecutor(
|
|||
): Result<Unit> {
|
||||
return when (slashCommand) {
|
||||
is SlashCommand.BanUser -> banUser(slashCommand)
|
||||
is SlashCommand.ChangeAvatar -> changeAvatar()
|
||||
is SlashCommand.ChangeAvatarForRoom -> changeAvatarForRoom()
|
||||
is SlashCommand.ChangeDisplayName -> changeDisplayName(slashCommand)
|
||||
is SlashCommand.ChangeDisplayNameForRoom -> changeDisplayNameForRoom()
|
||||
|
|
@ -178,6 +179,10 @@ class CommandExecutor(
|
|||
return matrixClient.setDisplayName(slashCommand.displayName)
|
||||
}
|
||||
|
||||
private fun changeAvatar(): Result<Unit> {
|
||||
return Result.failure(Exception("Not yet implemented"))
|
||||
}
|
||||
|
||||
private fun changeAvatarForRoom(): Result<Unit> {
|
||||
return Result.failure(Exception("Not yet implemented"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,18 @@ class CommandParser(
|
|||
syntaxError(Command.ROOM_AVATAR)
|
||||
}
|
||||
}
|
||||
Command.CHANGE_AVATAR.matches(slashCommand) -> {
|
||||
if (messageParts.size == 2) {
|
||||
val url = messageParts[1]
|
||||
if (url.isMxcUrl()) {
|
||||
SlashCommand.ChangeAvatar(url)
|
||||
} else {
|
||||
syntaxError(Command.CHANGE_AVATAR)
|
||||
}
|
||||
} else {
|
||||
syntaxError(Command.CHANGE_AVATAR)
|
||||
}
|
||||
}
|
||||
Command.CHANGE_AVATAR_FOR_ROOM.matches(slashCommand) -> {
|
||||
if (messageParts.size == 2) {
|
||||
val url = messageParts[1]
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import dev.zacsweers.metro.ContributesBinding
|
|||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.HomeserverCapabilitiesProvider
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
import io.element.android.libraries.slashcommands.api.SlashCommand
|
||||
|
|
@ -18,6 +19,8 @@ import io.element.android.libraries.slashcommands.api.SlashCommandService
|
|||
import io.element.android.libraries.slashcommands.api.SlashCommandSuggestion
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@ContributesBinding(RoomScope::class)
|
||||
class DefaultSlashCommandService(
|
||||
|
|
@ -26,6 +29,7 @@ class DefaultSlashCommandService(
|
|||
private val stringProvider: StringProvider,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
private val capabilitiesProvider: HomeserverCapabilitiesProvider,
|
||||
) : SlashCommandService {
|
||||
override suspend fun getSuggestions(
|
||||
text: String,
|
||||
|
|
@ -33,19 +37,41 @@ class DefaultSlashCommandService(
|
|||
): List<SlashCommandSuggestion> {
|
||||
if (!featureFlagService.isFeatureEnabled(FeatureFlags.SlashCommand)) return emptyList()
|
||||
val isDeveloperModeEnabled = appPreferencesStore.isDeveloperModeEnabledFlow().first()
|
||||
return Command.entries.filter {
|
||||
it.startsWith(text)
|
||||
}.filter {
|
||||
!isInThread || it.isAllowedInThread
|
||||
}.filter {
|
||||
!it.isDevCommand || isDeveloperModeEnabled
|
||||
}.map {
|
||||
SlashCommandSuggestion(
|
||||
command = it.command,
|
||||
parameters = it.parameters,
|
||||
description = stringProvider.getString(it.description),
|
||||
)
|
||||
}
|
||||
return Command.entries
|
||||
.asSequence()
|
||||
.filter { it.startsWith(text) }
|
||||
.filter { !isInThread || it.isAllowedInThread }
|
||||
.filter { !it.isDevCommand || isDeveloperModeEnabled }
|
||||
// Don't include the change display name commands if the user can't change their display name
|
||||
.run {
|
||||
val canUserChangeDisplayName = withTimeoutOrNull(5.seconds) {
|
||||
capabilitiesProvider.canChangeDisplayName().getOrNull()
|
||||
} ?: false
|
||||
if (!canUserChangeDisplayName) {
|
||||
filterNot { it == Command.CHANGE_DISPLAY_NAME || it == Command.CHANGE_DISPLAY_NAME_FOR_ROOM }
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
// Don't include the change avatar commands if the user can't change their avatar url
|
||||
.run {
|
||||
val canUserChangeAvatar = withTimeoutOrNull(5.seconds) {
|
||||
capabilitiesProvider.canChangeAvatarUrl().getOrNull()
|
||||
} ?: false
|
||||
if (!canUserChangeAvatar) {
|
||||
filterNot { it == Command.CHANGE_AVATAR || it == Command.CHANGE_AVATAR_FOR_ROOM }
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
.map {
|
||||
SlashCommandSuggestion(
|
||||
command = it.command,
|
||||
parameters = it.parameters,
|
||||
description = stringProvider.getString(it.description),
|
||||
)
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
|
||||
override suspend fun parse(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
<string name="slash_command_description_topic">Set the room topic</string>
|
||||
<string name="slash_command_description_remove_user">Removes user with given id from this room</string>
|
||||
<string name="slash_command_description_nick">Changes your display nickname</string>
|
||||
<string name="slash_command_description_avatar">Changes your profile picture in all rooms</string>
|
||||
<string name="slash_command_confetti">Sends the given message with confetti</string>
|
||||
<string name="slash_command_snow">Sends the given message with snowfall</string>
|
||||
<string name="slash_command_description_plain">Sends a message as plain text, without interpreting it as markdown</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue