Merge pull request #4158 from vector-im/feature/bma/new_commands
Handle new commands
This commit is contained in:
commit
7ebdd7830a
1
changelog.d/4158.feature
Normal file
1
changelog.d/4158.feature
Normal file
@ -0,0 +1 @@
|
||||
Handle 8 new slash commands: `/ignore`, `/unignore`, `/roomname`, `/myroomnick`, `/roomavatar`, `/myroomavatar`, `/lenny`, `/whois`.
|
1
changelog.d/4158.removal
Normal file
1
changelog.d/4158.removal
Normal file
@ -0,0 +1 @@
|
||||
Create extension `String.isMxcUrl()`
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 org.matrix.android.sdk.api
|
||||
|
||||
/**
|
||||
* This class contains pattern to match Matrix Url, aka mxc urls
|
||||
*/
|
||||
object MatrixUrls {
|
||||
const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
|
||||
|
||||
fun String.isMxcUrl() = startsWith(MATRIX_CONTENT_URI_SCHEME)
|
||||
}
|
@ -16,14 +16,14 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.content
|
||||
|
||||
import org.matrix.android.sdk.api.MatrixUrls
|
||||
import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl
|
||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||
import org.matrix.android.sdk.api.session.content.ContentUrlResolver
|
||||
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||
import org.matrix.android.sdk.internal.util.ensureTrailingSlash
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
|
||||
|
||||
internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectionConfig: HomeServerConnectionConfig) : ContentUrlResolver {
|
||||
|
||||
private val baseUrl = homeServerConnectionConfig.homeServerUriBase.toString().ensureTrailingSlash()
|
||||
@ -33,7 +33,7 @@ internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectio
|
||||
override fun resolveFullSize(contentUrl: String?): String? {
|
||||
return contentUrl
|
||||
// do not allow non-mxc content URLs
|
||||
?.takeIf { it.isValidMatrixContentUrl() }
|
||||
?.takeIf { it.isMxcUrl() }
|
||||
?.let {
|
||||
resolve(
|
||||
contentUrl = it,
|
||||
@ -45,7 +45,7 @@ internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectio
|
||||
override fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ContentUrlResolver.ThumbnailMethod): String? {
|
||||
return contentUrl
|
||||
// do not allow non-mxc content URLs
|
||||
?.takeIf { it.isValidMatrixContentUrl() }
|
||||
?.takeIf { it.isMxcUrl() }
|
||||
?.let {
|
||||
resolve(
|
||||
contentUrl = it,
|
||||
@ -58,7 +58,7 @@ internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectio
|
||||
private fun resolve(contentUrl: String,
|
||||
prefix: String,
|
||||
params: String = ""): String? {
|
||||
var serverAndMediaId = contentUrl.removePrefix(MATRIX_CONTENT_URI_SCHEME)
|
||||
var serverAndMediaId = contentUrl.removePrefix(MatrixUrls.MATRIX_CONTENT_URI_SCHEME)
|
||||
val fragmentOffset = serverAndMediaId.indexOf("#")
|
||||
var fragment = ""
|
||||
if (fragmentOffset >= 0) {
|
||||
@ -68,8 +68,4 @@ internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectio
|
||||
|
||||
return baseUrl + prefix + serverAndMediaId + params + fragment
|
||||
}
|
||||
|
||||
private fun String.isValidMatrixContentUrl(): Boolean {
|
||||
return startsWith(MATRIX_CONTENT_URI_SCHEME)
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage
|
||||
@ -130,7 +131,7 @@ internal class DefaultSendService @AssistedInject constructor(
|
||||
val messageContent = clearContent?.toModel<MessageContent>() as? MessageWithAttachmentContent ?: return NoOpCancellable
|
||||
|
||||
val url = messageContent.getFileUrl() ?: return NoOpCancellable
|
||||
if (url.startsWith("mxc://")) {
|
||||
if (url.isMxcUrl()) {
|
||||
// We need to resend only the message as the attachment is ok
|
||||
localEchoRepository.updateSendState(localEcho.eventId, roomId, SendState.UNSENT)
|
||||
return sendEvent(localEcho.root)
|
||||
|
@ -28,14 +28,20 @@ enum class Command(val command: String, val parameters: String, @StringRes val d
|
||||
EMOTE("/me", "<message>", R.string.command_description_emote, false),
|
||||
BAN_USER("/ban", "<user-id> [reason]", R.string.command_description_ban_user, false),
|
||||
UNBAN_USER("/unban", "<user-id> [reason]", R.string.command_description_unban_user, false),
|
||||
IGNORE_USER("/ignore", "<user-id> [reason]", R.string.command_description_ignore_user, false),
|
||||
UNIGNORE_USER("/unignore", "<user-id>", R.string.command_description_unignore_user, false),
|
||||
SET_USER_POWER_LEVEL("/op", "<user-id> [<power-level>]", R.string.command_description_op_user, false),
|
||||
RESET_USER_POWER_LEVEL("/deop", "<user-id>", R.string.command_description_deop_user, false),
|
||||
ROOM_NAME("/roomname", "<name>", R.string.command_description_room_name, false),
|
||||
INVITE("/invite", "<user-id> [reason]", R.string.command_description_invite_user, false),
|
||||
JOIN_ROOM("/join", "<room-alias> [reason]", R.string.command_description_join_room, false),
|
||||
PART("/part", "<room-alias> [reason]", R.string.command_description_part_room, false),
|
||||
TOPIC("/topic", "<topic>", R.string.command_description_topic, false),
|
||||
KICK_USER("/kick", "<user-id> [reason]", R.string.command_description_kick_user, false),
|
||||
CHANGE_DISPLAY_NAME("/nick", "<display-name>", R.string.command_description_nick, false),
|
||||
CHANGE_DISPLAY_NAME_FOR_ROOM("/myroomnick", "<display-name>", R.string.command_description_nick_for_room, false),
|
||||
ROOM_AVATAR("/roomavatar", "<mxc_url>", R.string.command_description_room_avatar, true /* Since user has to know the mxc url */),
|
||||
CHANGE_AVATAR_FOR_ROOM("/myroomavatar", "<mxc_url>", R.string.command_description_avatar_for_room, true /* Since user has to know the mxc url */),
|
||||
MARKDOWN("/markdown", "<on|off>", R.string.command_description_markdown, false),
|
||||
RAINBOW("/rainbow", "<message>", R.string.command_description_rainbow, false),
|
||||
RAINBOW_EMOTE("/rainbowme", "<message>", R.string.command_description_rainbow_emote, false),
|
||||
@ -43,11 +49,13 @@ enum class Command(val command: String, val parameters: String, @StringRes val d
|
||||
SPOILER("/spoiler", "<message>", R.string.command_description_spoiler, false),
|
||||
POLL("/poll", "Question | Option 1 | Option 2 ...", R.string.command_description_poll, false),
|
||||
SHRUG("/shrug", "<message>", R.string.command_description_shrug, false),
|
||||
LENNY("/lenny", "<message>", R.string.command_description_lenny, false),
|
||||
PLAIN("/plain", "<message>", R.string.command_description_plain, false),
|
||||
WHOIS("/whois", "<user-id>", R.string.command_description_whois, false),
|
||||
DISCARD_SESSION("/discardsession", "", R.string.command_description_discard_session, false),
|
||||
CONFETTI("/confetti", "<message>", R.string.command_confetti, false),
|
||||
SNOWFALL("/snowfall", "<message>", R.string.command_snow, false),
|
||||
CREATE_SPACE("/createspace", "<name> <invitee>*", R.string.command_description_create_space, true),
|
||||
CREATE_SPACE("/createspace", "<name> <invitee>*", R.string.command_description_create_space, true),
|
||||
ADD_TO_SPACE("/addToSpace", "spaceId", R.string.command_description_add_to_space, true),
|
||||
JOIN_SPACE("/joinSpace", "spaceId", R.string.command_description_join_space, true),
|
||||
LEAVE_ROOM("/leave", "<roomId?>", R.string.command_description_leave_room, true),
|
||||
|
@ -20,6 +20,7 @@ import im.vector.app.core.extensions.isEmail
|
||||
import im.vector.app.core.extensions.isMsisdn
|
||||
import im.vector.app.features.home.room.detail.ChatEffect
|
||||
import org.matrix.android.sdk.api.MatrixPatterns
|
||||
import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import timber.log.Timber
|
||||
|
||||
@ -61,7 +62,7 @@ object CommandParser {
|
||||
}
|
||||
|
||||
return when (val slashCommand = messageParts.first()) {
|
||||
Command.PLAIN.command -> {
|
||||
Command.PLAIN.command -> {
|
||||
val text = textMessage.substring(Command.PLAIN.command.length).trim()
|
||||
|
||||
if (text.isNotEmpty()) {
|
||||
@ -70,7 +71,7 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.PLAIN)
|
||||
}
|
||||
}
|
||||
Command.CHANGE_DISPLAY_NAME.command -> {
|
||||
Command.CHANGE_DISPLAY_NAME.command -> {
|
||||
val newDisplayName = textMessage.substring(Command.CHANGE_DISPLAY_NAME.command.length).trim()
|
||||
|
||||
if (newDisplayName.isNotEmpty()) {
|
||||
@ -79,7 +80,42 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.CHANGE_DISPLAY_NAME)
|
||||
}
|
||||
}
|
||||
Command.TOPIC.command -> {
|
||||
Command.CHANGE_DISPLAY_NAME_FOR_ROOM.command -> {
|
||||
val newDisplayName = textMessage.substring(Command.CHANGE_DISPLAY_NAME_FOR_ROOM.command.length).trim()
|
||||
|
||||
if (newDisplayName.isNotEmpty()) {
|
||||
ParsedCommand.ChangeDisplayNameForRoom(newDisplayName)
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.CHANGE_DISPLAY_NAME_FOR_ROOM)
|
||||
}
|
||||
}
|
||||
Command.ROOM_AVATAR.command -> {
|
||||
if (messageParts.size == 2) {
|
||||
val url = messageParts[1]
|
||||
|
||||
if (url.isMxcUrl()) {
|
||||
ParsedCommand.ChangeRoomAvatar(url)
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.ROOM_AVATAR)
|
||||
}
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.ROOM_AVATAR)
|
||||
}
|
||||
}
|
||||
Command.CHANGE_AVATAR_FOR_ROOM.command -> {
|
||||
if (messageParts.size == 2) {
|
||||
val url = messageParts[1]
|
||||
|
||||
if (url.isMxcUrl()) {
|
||||
ParsedCommand.ChangeAvatarForRoom(url)
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.CHANGE_AVATAR_FOR_ROOM)
|
||||
}
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.CHANGE_AVATAR_FOR_ROOM)
|
||||
}
|
||||
}
|
||||
Command.TOPIC.command -> {
|
||||
val newTopic = textMessage.substring(Command.TOPIC.command.length).trim()
|
||||
|
||||
if (newTopic.isNotEmpty()) {
|
||||
@ -88,22 +124,22 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.TOPIC)
|
||||
}
|
||||
}
|
||||
Command.EMOTE.command -> {
|
||||
Command.EMOTE.command -> {
|
||||
val message = textMessage.subSequence(Command.EMOTE.command.length, textMessage.length).trim()
|
||||
|
||||
ParsedCommand.SendEmote(message)
|
||||
}
|
||||
Command.RAINBOW.command -> {
|
||||
Command.RAINBOW.command -> {
|
||||
val message = textMessage.subSequence(Command.RAINBOW.command.length, textMessage.length).trim()
|
||||
|
||||
ParsedCommand.SendRainbow(message)
|
||||
}
|
||||
Command.RAINBOW_EMOTE.command -> {
|
||||
Command.RAINBOW_EMOTE.command -> {
|
||||
val message = textMessage.subSequence(Command.RAINBOW_EMOTE.command.length, textMessage.length).trim()
|
||||
|
||||
ParsedCommand.SendRainbowEmote(message)
|
||||
}
|
||||
Command.JOIN_ROOM.command -> {
|
||||
Command.JOIN_ROOM.command -> {
|
||||
if (messageParts.size >= 2) {
|
||||
val roomAlias = messageParts[1]
|
||||
|
||||
@ -121,7 +157,7 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.JOIN_ROOM)
|
||||
}
|
||||
}
|
||||
Command.PART.command -> {
|
||||
Command.PART.command -> {
|
||||
if (messageParts.size >= 2) {
|
||||
val roomAlias = messageParts[1]
|
||||
|
||||
@ -139,7 +175,16 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.PART)
|
||||
}
|
||||
}
|
||||
Command.INVITE.command -> {
|
||||
Command.ROOM_NAME.command -> {
|
||||
val newRoomName = textMessage.substring(Command.ROOM_NAME.command.length).trim()
|
||||
|
||||
if (newRoomName.isNotEmpty()) {
|
||||
ParsedCommand.ChangeRoomName(newRoomName)
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.ROOM_NAME)
|
||||
}
|
||||
}
|
||||
Command.INVITE.command -> {
|
||||
if (messageParts.size >= 2) {
|
||||
val userId = messageParts[1]
|
||||
|
||||
@ -166,7 +211,7 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.INVITE)
|
||||
}
|
||||
}
|
||||
Command.KICK_USER.command -> {
|
||||
Command.KICK_USER.command -> {
|
||||
if (messageParts.size >= 2) {
|
||||
val userId = messageParts[1]
|
||||
|
||||
@ -184,7 +229,7 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.KICK_USER)
|
||||
}
|
||||
}
|
||||
Command.BAN_USER.command -> {
|
||||
Command.BAN_USER.command -> {
|
||||
if (messageParts.size >= 2) {
|
||||
val userId = messageParts[1]
|
||||
|
||||
@ -202,7 +247,7 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.BAN_USER)
|
||||
}
|
||||
}
|
||||
Command.UNBAN_USER.command -> {
|
||||
Command.UNBAN_USER.command -> {
|
||||
if (messageParts.size >= 2) {
|
||||
val userId = messageParts[1]
|
||||
|
||||
@ -220,7 +265,33 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.UNBAN_USER)
|
||||
}
|
||||
}
|
||||
Command.SET_USER_POWER_LEVEL.command -> {
|
||||
Command.IGNORE_USER.command -> {
|
||||
if (messageParts.size == 2) {
|
||||
val userId = messageParts[1]
|
||||
|
||||
if (MatrixPatterns.isUserId(userId)) {
|
||||
ParsedCommand.IgnoreUser(userId)
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.IGNORE_USER)
|
||||
}
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.IGNORE_USER)
|
||||
}
|
||||
}
|
||||
Command.UNIGNORE_USER.command -> {
|
||||
if (messageParts.size == 2) {
|
||||
val userId = messageParts[1]
|
||||
|
||||
if (MatrixPatterns.isUserId(userId)) {
|
||||
ParsedCommand.UnignoreUser(userId)
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.UNIGNORE_USER)
|
||||
}
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.UNIGNORE_USER)
|
||||
}
|
||||
}
|
||||
Command.SET_USER_POWER_LEVEL.command -> {
|
||||
if (messageParts.size == 3) {
|
||||
val userId = messageParts[1]
|
||||
if (MatrixPatterns.isUserId(userId)) {
|
||||
@ -240,7 +311,7 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.SET_USER_POWER_LEVEL)
|
||||
}
|
||||
}
|
||||
Command.RESET_USER_POWER_LEVEL.command -> {
|
||||
Command.RESET_USER_POWER_LEVEL.command -> {
|
||||
if (messageParts.size == 2) {
|
||||
val userId = messageParts[1]
|
||||
|
||||
@ -253,7 +324,7 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.SET_USER_POWER_LEVEL)
|
||||
}
|
||||
}
|
||||
Command.MARKDOWN.command -> {
|
||||
Command.MARKDOWN.command -> {
|
||||
if (messageParts.size == 2) {
|
||||
when {
|
||||
"on".equals(messageParts[1], true) -> ParsedCommand.SetMarkdown(true)
|
||||
@ -264,23 +335,28 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.MARKDOWN)
|
||||
}
|
||||
}
|
||||
Command.CLEAR_SCALAR_TOKEN.command -> {
|
||||
Command.CLEAR_SCALAR_TOKEN.command -> {
|
||||
if (messageParts.size == 1) {
|
||||
ParsedCommand.ClearScalarToken
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.CLEAR_SCALAR_TOKEN)
|
||||
}
|
||||
}
|
||||
Command.SPOILER.command -> {
|
||||
Command.SPOILER.command -> {
|
||||
val message = textMessage.substring(Command.SPOILER.command.length).trim()
|
||||
ParsedCommand.SendSpoiler(message)
|
||||
}
|
||||
Command.SHRUG.command -> {
|
||||
Command.SHRUG.command -> {
|
||||
val message = textMessage.substring(Command.SHRUG.command.length).trim()
|
||||
|
||||
ParsedCommand.SendShrug(message)
|
||||
}
|
||||
Command.POLL.command -> {
|
||||
Command.LENNY.command -> {
|
||||
val message = textMessage.substring(Command.LENNY.command.length).trim()
|
||||
|
||||
ParsedCommand.SendLenny(message)
|
||||
}
|
||||
Command.POLL.command -> {
|
||||
val rawCommand = textMessage.substring(Command.POLL.command.length).trim()
|
||||
val split = rawCommand.split("|").map { it.trim() }
|
||||
if (split.size > 2) {
|
||||
@ -289,18 +365,31 @@ object CommandParser {
|
||||
ParsedCommand.ErrorSyntax(Command.POLL)
|
||||
}
|
||||
}
|
||||
Command.DISCARD_SESSION.command -> {
|
||||
Command.DISCARD_SESSION.command -> {
|
||||
ParsedCommand.DiscardSession
|
||||
}
|
||||
Command.CONFETTI.command -> {
|
||||
Command.WHOIS.command -> {
|
||||
if (messageParts.size == 2) {
|
||||
val userId = messageParts[1]
|
||||
|
||||
if (MatrixPatterns.isUserId(userId)) {
|
||||
ParsedCommand.ShowUser(userId)
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.WHOIS)
|
||||
}
|
||||
} else {
|
||||
ParsedCommand.ErrorSyntax(Command.WHOIS)
|
||||
}
|
||||
}
|
||||
Command.CONFETTI.command -> {
|
||||
val message = textMessage.substring(Command.CONFETTI.command.length).trim()
|
||||
ParsedCommand.SendChatEffect(ChatEffect.CONFETTI, message)
|
||||
}
|
||||
Command.SNOWFALL.command -> {
|
||||
Command.SNOWFALL.command -> {
|
||||
val message = textMessage.substring(Command.SNOWFALL.command.length).trim()
|
||||
ParsedCommand.SendChatEffect(ChatEffect.SNOWFALL, message)
|
||||
}
|
||||
Command.CREATE_SPACE.command -> {
|
||||
Command.CREATE_SPACE.command -> {
|
||||
val rawCommand = textMessage.substring(Command.CREATE_SPACE.command.length).trim()
|
||||
val split = rawCommand.split(" ").map { it.trim() }
|
||||
if (split.isEmpty()) {
|
||||
@ -312,25 +401,25 @@ object CommandParser {
|
||||
)
|
||||
}
|
||||
}
|
||||
Command.ADD_TO_SPACE.command -> {
|
||||
Command.ADD_TO_SPACE.command -> {
|
||||
val rawCommand = textMessage.substring(Command.ADD_TO_SPACE.command.length).trim()
|
||||
ParsedCommand.AddToSpace(
|
||||
rawCommand
|
||||
)
|
||||
}
|
||||
Command.JOIN_SPACE.command -> {
|
||||
Command.JOIN_SPACE.command -> {
|
||||
val spaceIdOrAlias = textMessage.substring(Command.JOIN_SPACE.command.length).trim()
|
||||
ParsedCommand.JoinSpace(
|
||||
spaceIdOrAlias
|
||||
)
|
||||
}
|
||||
Command.LEAVE_ROOM.command -> {
|
||||
Command.LEAVE_ROOM.command -> {
|
||||
val spaceIdOrAlias = textMessage.substring(Command.LEAVE_ROOM.command.length).trim()
|
||||
ParsedCommand.LeaveRoom(
|
||||
spaceIdOrAlias
|
||||
)
|
||||
}
|
||||
Command.UPGRADE_ROOM.command -> {
|
||||
Command.UPGRADE_ROOM.command -> {
|
||||
val newVersion = textMessage.substring(Command.UPGRADE_ROOM.command.length).trim()
|
||||
if (newVersion.isEmpty()) {
|
||||
ParsedCommand.ErrorSyntax(Command.UPGRADE_ROOM)
|
||||
@ -338,7 +427,7 @@ object CommandParser {
|
||||
ParsedCommand.UpgradeRoom(newVersion)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
else -> {
|
||||
// Unknown command
|
||||
ParsedCommand.ErrorUnknownSlashCommand(slashCommand)
|
||||
}
|
||||
|
@ -42,7 +42,10 @@ sealed class ParsedCommand {
|
||||
class SendRainbowEmote(val message: CharSequence) : ParsedCommand()
|
||||
class BanUser(val userId: String, val reason: String?) : ParsedCommand()
|
||||
class UnbanUser(val userId: String, val reason: String?) : ParsedCommand()
|
||||
class IgnoreUser(val userId: String) : ParsedCommand()
|
||||
class UnignoreUser(val userId: String) : ParsedCommand()
|
||||
class SetUserPowerLevel(val userId: String, val powerLevel: Int?) : ParsedCommand()
|
||||
class ChangeRoomName(val name: String) : ParsedCommand()
|
||||
class Invite(val userId: String, val reason: String?) : ParsedCommand()
|
||||
class Invite3Pid(val threePid: ThreePid) : ParsedCommand()
|
||||
class JoinRoom(val roomAlias: String, val reason: String?) : ParsedCommand()
|
||||
@ -50,12 +53,17 @@ sealed class ParsedCommand {
|
||||
class ChangeTopic(val topic: String) : ParsedCommand()
|
||||
class KickUser(val userId: String, val reason: String?) : ParsedCommand()
|
||||
class ChangeDisplayName(val displayName: String) : ParsedCommand()
|
||||
class ChangeDisplayNameForRoom(val displayName: String) : ParsedCommand()
|
||||
class ChangeRoomAvatar(val url: String) : ParsedCommand()
|
||||
class ChangeAvatarForRoom(val url: String) : ParsedCommand()
|
||||
class SetMarkdown(val enable: Boolean) : ParsedCommand()
|
||||
object ClearScalarToken : ParsedCommand()
|
||||
class SendSpoiler(val message: String) : ParsedCommand()
|
||||
class SendShrug(val message: CharSequence) : ParsedCommand()
|
||||
class SendLenny(val message: CharSequence) : ParsedCommand()
|
||||
class SendPoll(val question: String, val options: List<String>) : ParsedCommand()
|
||||
object DiscardSession : ParsedCommand()
|
||||
class ShowUser(val userId: String) : ParsedCommand()
|
||||
class SendChatEffect(val chatEffect: ChatEffect, val message: String) : ParsedCommand()
|
||||
class CreateSpace(val name: String, val invitees: List<String>) : ParsedCommand()
|
||||
class AddToSpace(val spaceId: String) : ParsedCommand()
|
||||
|
@ -413,11 +413,12 @@ class RoomDetailFragment @Inject constructor(
|
||||
|
||||
textComposerViewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is TextComposerViewEvents.JoinRoomCommandSuccess -> handleJoinedToAnotherRoom(it)
|
||||
is TextComposerViewEvents.SendMessageResult -> renderSendMessageResult(it)
|
||||
is TextComposerViewEvents.ShowMessage -> showSnackWithMessage(it.message)
|
||||
is TextComposerViewEvents.JoinRoomCommandSuccess -> handleJoinedToAnotherRoom(it)
|
||||
is TextComposerViewEvents.SendMessageResult -> renderSendMessageResult(it)
|
||||
is TextComposerViewEvents.ShowMessage -> showSnackWithMessage(it.message)
|
||||
is TextComposerViewEvents.ShowRoomUpgradeDialog -> handleShowRoomUpgradeDialog(it)
|
||||
is TextComposerViewEvents.AnimateSendButtonVisibility -> handleSendButtonVisibilityChanged(it)
|
||||
is TextComposerViewEvents.OpenRoomMemberProfile -> openRoomMemberProfile(it.userId)
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,6 @@ import im.vector.app.features.createdirect.DirectRoomHelper
|
||||
import im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy
|
||||
import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider
|
||||
import im.vector.app.features.home.room.detail.composer.VoiceMessageHelper
|
||||
import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator
|
||||
import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandler
|
||||
import im.vector.app.features.home.room.detail.timeline.factory.TimelineFactory
|
||||
import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever
|
||||
@ -104,7 +103,6 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
private val vectorDataStore: VectorDataStore,
|
||||
private val stringProvider: StringProvider,
|
||||
private val rainbowGenerator: RainbowGenerator,
|
||||
private val session: Session,
|
||||
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider,
|
||||
private val stickerPickerActionHandler: StickerPickerActionHandler,
|
||||
|
@ -36,6 +36,8 @@ sealed class TextComposerViewEvents : VectorViewEvents {
|
||||
object SlashCommandResultOk : SendMessageResult()
|
||||
class SlashCommandResultError(val throwable: Throwable) : SendMessageResult()
|
||||
|
||||
data class OpenRoomMemberProfile(val userId: String) : TextComposerViewEvents()
|
||||
|
||||
// TODO Remove
|
||||
object SlashCommandNotImplemented : SendMessageResult()
|
||||
|
||||
|
@ -40,11 +40,14 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.commonmark.parser.Parser
|
||||
import org.commonmark.renderer.html.HtmlRenderer
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.OptionItem
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
@ -175,6 +178,10 @@ class TextComposerViewModel @AssistedInject constructor(
|
||||
_viewEvents.post(TextComposerViewEvents.MessageSent)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.ChangeRoomName -> {
|
||||
handleChangeRoomNameSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.Invite -> {
|
||||
handleInviteSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
@ -197,12 +204,20 @@ class TextComposerViewModel @AssistedInject constructor(
|
||||
if (slashCommandResult.enable) R.string.markdown_has_been_enabled else R.string.markdown_has_been_disabled))
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.BanUser -> {
|
||||
handleBanSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.UnbanUser -> {
|
||||
handleUnbanSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.BanUser -> {
|
||||
handleBanSlashCommand(slashCommandResult)
|
||||
is ParsedCommand.IgnoreUser -> {
|
||||
handleIgnoreSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.UnignoreUser -> {
|
||||
handleUnignoreSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.KickUser -> {
|
||||
@ -245,14 +260,12 @@ class TextComposerViewModel @AssistedInject constructor(
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.SendShrug -> {
|
||||
val sequence = buildString {
|
||||
append("¯\\_(ツ)_/¯")
|
||||
if (slashCommandResult.message.isNotEmpty()) {
|
||||
append(" ")
|
||||
append(slashCommandResult.message)
|
||||
}
|
||||
}
|
||||
room.sendTextMessage(sequence)
|
||||
sendPrefixedMessage("¯\\_(ツ)_/¯", slashCommandResult.message)
|
||||
_viewEvents.post(TextComposerViewEvents.SlashCommandHandled())
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.SendLenny -> {
|
||||
sendPrefixedMessage("( ͡° ͜ʖ ͡°)", slashCommandResult.message)
|
||||
_viewEvents.post(TextComposerViewEvents.SlashCommandHandled())
|
||||
popDraft()
|
||||
}
|
||||
@ -274,6 +287,23 @@ class TextComposerViewModel @AssistedInject constructor(
|
||||
handleChangeDisplayNameSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.ChangeDisplayNameForRoom -> {
|
||||
handleChangeDisplayNameForRoomSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.ChangeRoomAvatar -> {
|
||||
handleChangeRoomAvatarSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.ChangeAvatarForRoom -> {
|
||||
handleChangeAvatarForRoomSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.ShowUser -> {
|
||||
_viewEvents.post(TextComposerViewEvents.SlashCommandHandled())
|
||||
handleWhoisSlashCommand(slashCommandResult)
|
||||
popDraft()
|
||||
}
|
||||
is ParsedCommand.DiscardSession -> {
|
||||
if (room.isEncrypted()) {
|
||||
session.cryptoService().discardOutboundSession(room.roomId)
|
||||
@ -570,6 +600,73 @@ class TextComposerViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleChangeRoomNameSlashCommand(changeRoomName: ParsedCommand.ChangeRoomName) {
|
||||
launchSlashCommandFlowSuspendable {
|
||||
room.updateName(changeRoomName.name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMyRoomMemberContent(): RoomMemberContent? {
|
||||
return room.getStateEvent(EventType.STATE_ROOM_MEMBER, QueryStringValue.Equals(session.myUserId))
|
||||
?.content
|
||||
?.toModel<RoomMemberContent>()
|
||||
}
|
||||
|
||||
private fun handleChangeDisplayNameForRoomSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayNameForRoom) {
|
||||
launchSlashCommandFlowSuspendable {
|
||||
getMyRoomMemberContent()
|
||||
?.copy(displayName = changeDisplayName.displayName)
|
||||
?.toContent()
|
||||
?.let {
|
||||
room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleChangeRoomAvatarSlashCommand(changeAvatar: ParsedCommand.ChangeRoomAvatar) {
|
||||
launchSlashCommandFlowSuspendable {
|
||||
room.sendStateEvent(EventType.STATE_ROOM_AVATAR, null, RoomAvatarContent(changeAvatar.url).toContent())
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleChangeAvatarForRoomSlashCommand(changeAvatar: ParsedCommand.ChangeAvatarForRoom) {
|
||||
launchSlashCommandFlowSuspendable {
|
||||
getMyRoomMemberContent()
|
||||
?.copy(avatarUrl = changeAvatar.url)
|
||||
?.toContent()
|
||||
?.let {
|
||||
room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIgnoreSlashCommand(ignore: ParsedCommand.IgnoreUser) {
|
||||
launchSlashCommandFlowSuspendable {
|
||||
session.ignoreUserIds(listOf(ignore.userId))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUnignoreSlashCommand(unignore: ParsedCommand.UnignoreUser) {
|
||||
launchSlashCommandFlowSuspendable {
|
||||
session.unIgnoreUserIds(listOf(unignore.userId))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleWhoisSlashCommand(whois: ParsedCommand.ShowUser) {
|
||||
_viewEvents.post(TextComposerViewEvents.OpenRoomMemberProfile(whois.userId))
|
||||
}
|
||||
|
||||
private fun sendPrefixedMessage(prefix: String, message: CharSequence) {
|
||||
val sequence = buildString {
|
||||
append(prefix)
|
||||
if (message.isNotEmpty()) {
|
||||
append(" ")
|
||||
append(message)
|
||||
}
|
||||
}
|
||||
room.sendTextMessage(sequence)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a send mode to a draft and save the draft
|
||||
*/
|
||||
|
@ -69,6 +69,7 @@ import im.vector.app.features.media.ImageContentRenderer
|
||||
import im.vector.app.features.media.VideoContentRenderer
|
||||
import me.gujun.android.span.span
|
||||
import org.commonmark.node.Document
|
||||
import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.RelationType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
@ -213,7 +214,7 @@ class MessageItemFactory @Inject constructor(
|
||||
if (informationData.sentByMe && !informationData.sendState.isSent()) {
|
||||
it
|
||||
} else {
|
||||
it.takeIf { it.startsWith("mxc://") }
|
||||
it.takeIf { it.isMxcUrl() }
|
||||
}
|
||||
} ?: ""
|
||||
return MessageFileItem_()
|
||||
@ -244,7 +245,7 @@ class MessageItemFactory @Inject constructor(
|
||||
if (informationData.sentByMe && !informationData.sendState.isSent()) {
|
||||
it
|
||||
} else {
|
||||
it.takeIf { it.startsWith("mxc://") }
|
||||
it.takeIf { it.isMxcUrl() }
|
||||
}
|
||||
} ?: ""
|
||||
|
||||
|
@ -1831,16 +1831,23 @@
|
||||
<string name="command_description_emote">Displays action</string>
|
||||
<string name="command_description_ban_user">Bans user with given id</string>
|
||||
<string name="command_description_unban_user">Unbans user with given id</string>
|
||||
<string name="command_description_ignore_user">Ignores a user, hiding their messages from you</string>
|
||||
<string name="command_description_unignore_user">Stops ignoring a user, showing their messages going forward</string>
|
||||
<string name="command_description_op_user">Define the power level of a user</string>
|
||||
<string name="command_description_deop_user">Deops user with given id</string>
|
||||
<string name="command_description_room_name">Sets the room name</string>
|
||||
<string name="command_description_invite_user">Invites user with given id to current room</string>
|
||||
<string name="command_description_join_room">Joins room with given alias</string>
|
||||
<string name="command_description_part_room">Leave room</string>
|
||||
<string name="command_description_topic">Set the room topic</string>
|
||||
<string name="command_description_kick_user">Kicks user with given id</string>
|
||||
<string name="command_description_nick">Changes your display nickname</string>
|
||||
<string name="command_description_nick_for_room">Changes your display nickname in the current room only</string>
|
||||
<string name="command_description_room_avatar">Changes the avatar of the current room</string>
|
||||
<string name="command_description_avatar_for_room">Changes your avatar in this current room only</string>
|
||||
<string name="command_description_markdown">On/Off markdown</string>
|
||||
<string name="command_description_clear_scalar_token">To fix Matrix Apps management</string>
|
||||
<string name="command_description_whois">Displays information about a user</string>
|
||||
|
||||
<string name="markdown_has_been_enabled">Markdown has been enabled.</string>
|
||||
<string name="markdown_has_been_disabled">Markdown has been disabled.</string>
|
||||
@ -2671,6 +2678,7 @@
|
||||
<string name="settings_developer_mode_show_info_on_screen_summary">Show some useful info to help debugging the application</string>
|
||||
|
||||
<string name="command_description_shrug">Prepends ¯\\_(ツ)_/¯ to a plain-text message</string>
|
||||
<string name="command_description_lenny">Prepends ( ͡° ͜ʖ ͡°) to a plain-text message</string>
|
||||
|
||||
<string name="create_room_encryption_title">"Enable encryption"</string>
|
||||
<string name="create_room_encryption_description">"Once enabled, encryption cannot be disabled."</string>
|
||||
|
Loading…
Reference in New Issue
Block a user