From c0cf534845d55ca1572d95ee67f0a23ff17c3d84 Mon Sep 17 00:00:00 2001 From: Constantin Wartenburger Date: Sat, 10 Oct 2020 16:36:04 +0200 Subject: [PATCH 1/8] Added commands from element web --- .../im/vector/app/features/command/Command.kt | 7 +- .../app/features/command/CommandParser.kt | 79 ++++++++++++++++--- .../app/features/command/ParsedCommand.kt | 7 +- .../home/room/detail/RoomDetailFragment.kt | 1 + .../home/room/detail/RoomDetailViewEvents.kt | 12 +-- .../home/room/detail/RoomDetailViewModel.kt | 68 +++++++++++++--- vector/src/main/res/values/strings.xml | 5 ++ 7 files changed, 149 insertions(+), 30 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt index db429f9e58..c1b30b2744 100644 --- a/vector/src/main/java/im/vector/app/features/command/Command.kt +++ b/vector/src/main/java/im/vector/app/features/command/Command.kt @@ -28,8 +28,11 @@ enum class Command(val command: String, val parameters: String, @StringRes val d EMOTE("/me", "", R.string.command_description_emote), BAN_USER("/ban", " [reason]", R.string.command_description_ban_user), UNBAN_USER("/unban", " [reason]", R.string.command_description_unban_user), + IGNORE_USER("/ignore", " [reason]", R.string.command_description_ignore_user), + UNIGNORE_USER("/unignore", "", R.string.command_description_unignore_user), SET_USER_POWER_LEVEL("/op", " []", R.string.command_description_op_user), RESET_USER_POWER_LEVEL("/deop", "", R.string.command_description_deop_user), + ROOM_NAME("/roomname", " [reason]", R.string.command_description_room_name), INVITE("/invite", " [reason]", R.string.command_description_invite_user), JOIN_ROOM("/join", " [reason]", R.string.command_description_join_room), PART("/part", " [reason]", R.string.command_description_part_room), @@ -42,8 +45,10 @@ enum class Command(val command: String, val parameters: String, @StringRes val d CLEAR_SCALAR_TOKEN("/clear_scalar_token", "", R.string.command_description_clear_scalar_token), SPOILER("/spoiler", "", R.string.command_description_spoiler), POLL("/poll", "Question | Option 1 | Option 2 ...", R.string.command_description_poll), - SHRUG("/shrug", "", R.string.command_description_shrug), + SHRUG("/shrug", "[]", R.string.command_description_shrug), + LENNY("/lenny", "[]", R.string.command_description_lenny), PLAIN("/plain", "", R.string.command_description_plain), + WHOIS("/whois", "", R.string.command_description_whois), DISCARD_SESSION("/discardsession", "", R.string.command_description_discard_session); val length diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index 94de6bf265..fd7d587c1c 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -102,7 +102,7 @@ object CommandParser { ParsedCommand.SendRainbowEmote(message) } - Command.JOIN_ROOM.command -> { + Command.JOIN_ROOM.command -> { if (messageParts.size >= 2) { val roomAlias = messageParts[1] @@ -120,7 +120,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.JOIN_ROOM) } } - Command.PART.command -> { + Command.PART.command -> { if (messageParts.size >= 2) { val roomAlias = messageParts[1] @@ -138,7 +138,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] @@ -183,7 +192,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.KICK_USER) } } - Command.BAN_USER.command -> { + Command.BAN_USER.command -> { if (messageParts.size >= 2) { val userId = messageParts[1] @@ -201,7 +210,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.BAN_USER) } } - Command.UNBAN_USER.command -> { + Command.UNBAN_USER.command -> { if (messageParts.size >= 2) { val userId = messageParts[1] @@ -219,7 +228,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)) { @@ -252,7 +287,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) @@ -263,23 +298,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) { @@ -288,10 +328,23 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.POLL) } } - Command.DISCARD_SESSION.command -> { + Command.DISCARD_SESSION.command -> { ParsedCommand.DiscardSession } - else -> { + 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) + } + } + else -> { // Unknown command ParsedCommand.ErrorUnknownSlashCommand(slashCommand) } diff --git a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt index bdfa7779fb..54043f343a 100644 --- a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt +++ b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt @@ -41,7 +41,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() @@ -53,6 +56,8 @@ sealed class 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) : ParsedCommand() - object DiscardSession: ParsedCommand() + object DiscardSession : ParsedCommand() + class ShowUser(val userId: String) : ParsedCommand() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 51aeda2aab..a9c2307566 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -359,6 +359,7 @@ class RoomDetailFragment @Inject constructor( is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it) is RoomDetailViewEvents.ShowE2EErrorMessage -> displayE2eError(it.withHeldCode) RoomDetailViewEvents.DisplayPromptForIntegrationManager -> displayPromptForIntegrationManager() + is RoomDetailViewEvents.OpenRoomMemberProfile -> openRoomMemberProfile(it.userId) is RoomDetailViewEvents.OpenStickerPicker -> openStickerPicker(it) is RoomDetailViewEvents.DisplayEnableIntegrationsWarning -> displayDisabledIntegrationDialog() is RoomDetailViewEvents.OpenIntegrationManager -> openIntegrationManager() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt index 29ed43f17d..b747075622 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt @@ -64,14 +64,16 @@ sealed class RoomDetailViewEvents : VectorViewEvents { abstract class SendMessageResult : RoomDetailViewEvents() - object DisplayPromptForIntegrationManager: RoomDetailViewEvents() + object DisplayPromptForIntegrationManager : RoomDetailViewEvents() - object DisplayEnableIntegrationsWarning: RoomDetailViewEvents() + object DisplayEnableIntegrationsWarning : RoomDetailViewEvents() - data class OpenStickerPicker(val widget: Widget): RoomDetailViewEvents() + data class OpenRoomMemberProfile(val userId: String) : RoomDetailViewEvents() - object OpenIntegrationManager: RoomDetailViewEvents() - object OpenActiveWidgetBottomSheet: RoomDetailViewEvents() + data class OpenStickerPicker(val widget: Widget) : RoomDetailViewEvents() + + object OpenIntegrationManager : RoomDetailViewEvents() + object OpenActiveWidgetBottomSheet : RoomDetailViewEvents() data class RequestNativeWidgetPermission(val widget: Widget, val domain: String, val grantedEvents: RoomDetailViewEvents) : RoomDetailViewEvents() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 1b5e928843..2e7109b5e7 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -571,6 +571,10 @@ class RoomDetailViewModel @AssistedInject constructor( _viewEvents.post(RoomDetailViewEvents.MessageSent) popDraft() } + is ParsedCommand.ChangeRoomName -> { + handleChangeRoomNameSlashCommand(slashCommandResult) + popDraft() + } is ParsedCommand.Invite -> { handleInviteSlashCommand(slashCommandResult) popDraft() @@ -593,12 +597,20 @@ class RoomDetailViewModel @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 -> { @@ -641,14 +653,12 @@ class RoomDetailViewModel @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(RoomDetailViewEvents.SlashCommandHandled()) + popDraft() + } + is ParsedCommand.SendLenny -> { + sendPrefixedMessage("( ͡° ͜ʖ ͡°)", slashCommandResult.message) _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) popDraft() } @@ -665,6 +675,11 @@ class RoomDetailViewModel @AssistedInject constructor( handleChangeDisplayNameSlashCommand(slashCommandResult) popDraft() } + is ParsedCommand.ShowUser -> { + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) + handleWhoisSlashCommand(slashCommandResult) + popDraft() + } is ParsedCommand.DiscardSession -> { if (room.isEncrypted()) { session.cryptoService().discardOutboundSession(room.roomId) @@ -786,6 +801,12 @@ class RoomDetailViewModel @AssistedInject constructor( } } + private fun handleChangeRoomNameSlashCommand(changeRoomName: ParsedCommand.ChangeRoomName) { + launchSlashCommandFlow { + room.updateName(changeRoomName.name, it) + } + } + private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) { launchSlashCommandFlow { room.invite(invite.userId, invite.reason, it) @@ -833,6 +854,33 @@ class RoomDetailViewModel @AssistedInject constructor( } } + private fun handleIgnoreSlashCommand(ignore: ParsedCommand.IgnoreUser) { + launchSlashCommandFlow { + session.ignoreUserIds(listOf(ignore.userId), it) + } + } + + private fun handleUnignoreSlashCommand(unignore: ParsedCommand.UnignoreUser) { + launchSlashCommandFlow { + session.unIgnoreUserIds(listOf(unignore.userId), it) + } + } + + private fun handleWhoisSlashCommand(whois: ParsedCommand.ShowUser) { + _viewEvents.post(RoomDetailViewEvents.OpenRoomMemberProfile(whois.userId)) + } + + private fun sendPrefixedMessage(prefix: String, message: CharSequence) { + val sequence = buildString { + append(prefix) + if (message.isNotEmpty()) { + append(" ") + append(message) + } + } + room.sendTextMessage(sequence) + } + private fun launchSlashCommandFlow(lambda: (MatrixCallback) -> Unit) { _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) val matrixCallback = object : MatrixCallback { diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index c025054f98..f87b45cd05 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1287,8 +1287,11 @@ Displays action Bans user with given id Unbans user with given id + Ignores a user, hiding their messages from you + Stops ignoring a user, showing their messages going forward Define the power level of a user Deops user with given id + Sets the room name Invites user with given id to current room Joins room with given alias Leave room @@ -1297,6 +1300,7 @@ Changes your display nickname On/Off markdown To fix Matrix Apps management + Displays information about a user Markdown has been enabled. Markdown has been disabled. @@ -2063,6 +2067,7 @@ Element may crash more often when an unexpected error occurs Prepends ¯\\_(ツ)_/¯ to a plain-text message + Prepends ( ͡° ͜ʖ ͡°) to a plain-text message "Enable encryption" "Once enabled, encryption cannot be disabled." From 13960561c00d6a44d8e44d7f8586be66075aeeb5 Mon Sep 17 00:00:00 2001 From: Constantin Wartenburger Date: Sat, 10 Oct 2020 18:34:31 +0200 Subject: [PATCH 2/8] Added /myroomnick command --- .../im/vector/app/features/command/Command.kt | 1 + .../app/features/command/CommandParser.kt | 23 +++++++++++++------ .../app/features/command/ParsedCommand.kt | 1 + .../home/room/detail/RoomDetailViewModel.kt | 15 ++++++++++++ vector/src/main/res/values/strings.xml | 1 + 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt index c1b30b2744..1db1639b1d 100644 --- a/vector/src/main/java/im/vector/app/features/command/Command.kt +++ b/vector/src/main/java/im/vector/app/features/command/Command.kt @@ -39,6 +39,7 @@ enum class Command(val command: String, val parameters: String, @StringRes val d TOPIC("/topic", "", R.string.command_description_topic), KICK_USER("/kick", " [reason]", R.string.command_description_kick_user), CHANGE_DISPLAY_NAME("/nick", "", R.string.command_description_nick), + CHANGE_DISPLAY_NAME_FOR_ROOM("/myroomnick", "", R.string.command_description_room_nick), MARKDOWN("/markdown", "", R.string.command_description_markdown), RAINBOW("/rainbow", "", R.string.command_description_rainbow), RAINBOW_EMOTE("/rainbowme", "", R.string.command_description_rainbow_emote), diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index fd7d587c1c..e09b6a842d 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -60,7 +60,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()) { @@ -69,7 +69,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()) { @@ -78,7 +78,16 @@ 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.TOPIC.command -> { val newTopic = textMessage.substring(Command.TOPIC.command.length).trim() if (newTopic.isNotEmpty()) { @@ -87,22 +96,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] diff --git a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt index 54043f343a..60b4e1c3a2 100644 --- a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt +++ b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt @@ -52,6 +52,7 @@ 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 SetMarkdown(val enable: Boolean) : ParsedCommand() object ClearScalarToken : ParsedCommand() class SendSpoiler(val message: String) : ParsedCommand() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 2e7109b5e7..10942f17bf 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -74,6 +74,7 @@ import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent +import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.message.MessageContent @@ -675,6 +676,10 @@ class RoomDetailViewModel @AssistedInject constructor( handleChangeDisplayNameSlashCommand(slashCommandResult) popDraft() } + is ParsedCommand.ChangeDisplayNameForRoom -> { + handleChangeDisplayNameForRoomSlashCommand(slashCommandResult) + popDraft() + } is ParsedCommand.ShowUser -> { _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) handleWhoisSlashCommand(slashCommandResult) @@ -836,6 +841,16 @@ class RoomDetailViewModel @AssistedInject constructor( } } + private fun handleChangeDisplayNameForRoomSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayNameForRoom) { + val content = room.getStateEvent(EventType.STATE_ROOM_MEMBER, QueryStringValue.Equals(session.myUserId)) + ?.content?.toModel() + ?: RoomMemberContent(membership = Membership.JOIN) + + launchSlashCommandFlow { + room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, content.copy(displayName = changeDisplayName.displayName).toContent(), it) + } + } + private fun handleKickSlashCommand(kick: ParsedCommand.KickUser) { launchSlashCommandFlow { room.kick(kick.userId, kick.reason, it) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index f87b45cd05..33c648d647 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1298,6 +1298,7 @@ Set the room topic Kicks user with given id Changes your display nickname + Changes your display nickname On/Off markdown To fix Matrix Apps management Displays information about a user From 1a40b65b53677b79b3d6beb34335fdd9d3dab80a Mon Sep 17 00:00:00 2001 From: Constantin Wartenburger Date: Sun, 11 Oct 2020 18:56:13 +0200 Subject: [PATCH 3/8] Added /myroomavatar command (without upload) --- .../im/vector/app/features/command/Command.kt | 3 +- .../app/features/command/CommandParser.kt | 51 ++++++++++++------- .../app/features/command/ParsedCommand.kt | 1 + .../home/room/detail/RoomDetailViewModel.kt | 18 +++++-- vector/src/main/res/values/strings.xml | 3 +- 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt index 1db1639b1d..fd0623dc05 100644 --- a/vector/src/main/java/im/vector/app/features/command/Command.kt +++ b/vector/src/main/java/im/vector/app/features/command/Command.kt @@ -39,7 +39,8 @@ enum class Command(val command: String, val parameters: String, @StringRes val d TOPIC("/topic", "", R.string.command_description_topic), KICK_USER("/kick", " [reason]", R.string.command_description_kick_user), CHANGE_DISPLAY_NAME("/nick", "", R.string.command_description_nick), - CHANGE_DISPLAY_NAME_FOR_ROOM("/myroomnick", "", R.string.command_description_room_nick), + CHANGE_DISPLAY_NAME_FOR_ROOM("/myroomnick", "", R.string.command_description_nick_for_room), + CHANGE_AVATAR_FOR_ROOM("/myroomavatar", "", R.string.command_description_avatar_for_room), MARKDOWN("/markdown", "", R.string.command_description_markdown), RAINBOW("/rainbow", "", R.string.command_description_rainbow), RAINBOW_EMOTE("/rainbowme", "", R.string.command_description_rainbow_emote), diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index e09b6a842d..d5fb9a41b6 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -87,6 +87,19 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.CHANGE_DISPLAY_NAME_FOR_ROOM) } } + Command.CHANGE_AVATAR_FOR_ROOM.command -> { + if (messageParts.size == 2) { + val url = messageParts[1] + + if (url.isNotEmpty()) { + 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() @@ -129,7 +142,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.JOIN_ROOM) } } - Command.PART.command -> { + Command.PART.command -> { if (messageParts.size >= 2) { val roomAlias = messageParts[1] @@ -147,7 +160,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.PART) } } - Command.ROOM_NAME.command -> { + Command.ROOM_NAME.command -> { val newRoomName = textMessage.substring(Command.ROOM_NAME.command.length).trim() if (newRoomName.isNotEmpty()) { @@ -156,7 +169,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.ROOM_NAME) } } - Command.INVITE.command -> { + Command.INVITE.command -> { if (messageParts.size >= 2) { val userId = messageParts[1] @@ -183,7 +196,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.INVITE) } } - Command.KICK_USER.command -> { + Command.KICK_USER.command -> { if (messageParts.size >= 2) { val userId = messageParts[1] @@ -201,7 +214,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.KICK_USER) } } - Command.BAN_USER.command -> { + Command.BAN_USER.command -> { if (messageParts.size >= 2) { val userId = messageParts[1] @@ -219,7 +232,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.BAN_USER) } } - Command.UNBAN_USER.command -> { + Command.UNBAN_USER.command -> { if (messageParts.size >= 2) { val userId = messageParts[1] @@ -237,7 +250,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.UNBAN_USER) } } - Command.IGNORE_USER.command -> { + Command.IGNORE_USER.command -> { if (messageParts.size == 2) { val userId = messageParts[1] @@ -250,7 +263,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.IGNORE_USER) } } - Command.UNIGNORE_USER.command -> { + Command.UNIGNORE_USER.command -> { if (messageParts.size == 2) { val userId = messageParts[1] @@ -263,7 +276,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.UNIGNORE_USER) } } - Command.SET_USER_POWER_LEVEL.command -> { + Command.SET_USER_POWER_LEVEL.command -> { if (messageParts.size == 3) { val userId = messageParts[1] if (MatrixPatterns.isUserId(userId)) { @@ -283,7 +296,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] @@ -296,7 +309,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) @@ -307,28 +320,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.LENNY.command -> { + Command.LENNY.command -> { val message = textMessage.substring(Command.LENNY.command.length).trim() ParsedCommand.SendLenny(message) } - Command.POLL.command -> { + Command.POLL.command -> { val rawCommand = textMessage.substring(Command.POLL.command.length).trim() val split = rawCommand.split("|").map { it.trim() } if (split.size > 2) { @@ -337,10 +350,10 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.POLL) } } - Command.DISCARD_SESSION.command -> { + Command.DISCARD_SESSION.command -> { ParsedCommand.DiscardSession } - Command.WHOIS.command -> { + Command.WHOIS.command -> { if (messageParts.size == 2) { val userId = messageParts[1] @@ -353,7 +366,7 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.WHOIS) } } - else -> { + else -> { // Unknown command ParsedCommand.ErrorUnknownSlashCommand(slashCommand) } diff --git a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt index 60b4e1c3a2..f0dcbc9663 100644 --- a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt +++ b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt @@ -53,6 +53,7 @@ sealed class ParsedCommand { class KickUser(val userId: String, val reason: String?) : ParsedCommand() class ChangeDisplayName(val displayName: String) : ParsedCommand() class ChangeDisplayNameForRoom(val displayName: String) : ParsedCommand() + class ChangeAvatarForRoom(val url: String) : ParsedCommand() class SetMarkdown(val enable: Boolean) : ParsedCommand() object ClearScalarToken : ParsedCommand() class SendSpoiler(val message: String) : ParsedCommand() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 10942f17bf..e84eb5520c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -680,6 +680,10 @@ class RoomDetailViewModel @AssistedInject constructor( handleChangeDisplayNameForRoomSlashCommand(slashCommandResult) popDraft() } + is ParsedCommand.ChangeAvatarForRoom -> { + handleChangeAvatarForRoomSlashCommand(slashCommandResult) + popDraft() + } is ParsedCommand.ShowUser -> { _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) handleWhoisSlashCommand(slashCommandResult) @@ -841,13 +845,21 @@ class RoomDetailViewModel @AssistedInject constructor( } } - private fun handleChangeDisplayNameForRoomSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayNameForRoom) { - val content = room.getStateEvent(EventType.STATE_ROOM_MEMBER, QueryStringValue.Equals(session.myUserId)) + private fun getLastMemberEvent(): RoomMemberContent { + return room.getStateEvent(EventType.STATE_ROOM_MEMBER, QueryStringValue.Equals(session.myUserId)) ?.content?.toModel() ?: RoomMemberContent(membership = Membership.JOIN) + } + private fun handleChangeDisplayNameForRoomSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayNameForRoom) { launchSlashCommandFlow { - room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, content.copy(displayName = changeDisplayName.displayName).toContent(), it) + room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, getLastMemberEvent().copy(displayName = changeDisplayName.displayName).toContent(), it) + } + } + + private fun handleChangeAvatarForRoomSlashCommand(changeAvatar: ParsedCommand.ChangeAvatarForRoom) { + launchSlashCommandFlow { + room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, getLastMemberEvent().copy(avatarUrl = changeAvatar.url).toContent(), it) } } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 33c648d647..823d567f20 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1298,7 +1298,8 @@ Set the room topic Kicks user with given id Changes your display nickname - Changes your display nickname + Changes your display nickname in the current room only + Changes your avatar in this current room only On/Off markdown To fix Matrix Apps management Displays information about a user From 24c67660c12d8ac402e50dee16a2c2f6ea94dae1 Mon Sep 17 00:00:00 2001 From: Constantin Wartenburger Date: Mon, 12 Oct 2020 17:43:07 +0200 Subject: [PATCH 4/8] Added /roomavatar command (not upload) --- .../im/vector/app/features/command/Command.kt | 3 ++- .../vector/app/features/command/CommandParser.kt | 15 ++++++++++++++- .../vector/app/features/command/ParsedCommand.kt | 1 + .../home/room/detail/RoomDetailViewModel.kt | 11 +++++++++++ vector/src/main/res/values/strings.xml | 1 + 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt index fd0623dc05..b74b608e32 100644 --- a/vector/src/main/java/im/vector/app/features/command/Command.kt +++ b/vector/src/main/java/im/vector/app/features/command/Command.kt @@ -32,7 +32,7 @@ enum class Command(val command: String, val parameters: String, @StringRes val d UNIGNORE_USER("/unignore", "", R.string.command_description_unignore_user), SET_USER_POWER_LEVEL("/op", " []", R.string.command_description_op_user), RESET_USER_POWER_LEVEL("/deop", "", R.string.command_description_deop_user), - ROOM_NAME("/roomname", " [reason]", R.string.command_description_room_name), + ROOM_NAME("/roomname", "", R.string.command_description_room_name), INVITE("/invite", " [reason]", R.string.command_description_invite_user), JOIN_ROOM("/join", " [reason]", R.string.command_description_join_room), PART("/part", " [reason]", R.string.command_description_part_room), @@ -40,6 +40,7 @@ enum class Command(val command: String, val parameters: String, @StringRes val d KICK_USER("/kick", " [reason]", R.string.command_description_kick_user), CHANGE_DISPLAY_NAME("/nick", "", R.string.command_description_nick), CHANGE_DISPLAY_NAME_FOR_ROOM("/myroomnick", "", R.string.command_description_nick_for_room), + ROOM_AVATAR("/roomavatar", "", R.string.command_description_room_avatar), CHANGE_AVATAR_FOR_ROOM("/myroomavatar", "", R.string.command_description_avatar_for_room), MARKDOWN("/markdown", "", R.string.command_description_markdown), RAINBOW("/rainbow", "", R.string.command_description_rainbow), diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index d5fb9a41b6..41961c209a 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -87,11 +87,24 @@ object CommandParser { ParsedCommand.ErrorSyntax(Command.CHANGE_DISPLAY_NAME_FOR_ROOM) } } + Command.ROOM_AVATAR.command -> { + if (messageParts.size == 2) { + val url = messageParts[1] + + if (url.isNotEmpty() && url.startsWith("mxc://")) { + 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.isNotEmpty()) { + if (url.isNotEmpty() && url.startsWith("mxc://")) { ParsedCommand.ChangeAvatarForRoom(url) } else { ParsedCommand.ErrorSyntax(Command.CHANGE_AVATAR_FOR_ROOM) diff --git a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt index f0dcbc9663..16f2eaac29 100644 --- a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt +++ b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt @@ -53,6 +53,7 @@ sealed class 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() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index e84eb5520c..737cdf61b0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -74,6 +74,7 @@ import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.Membership 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.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -680,6 +681,10 @@ class RoomDetailViewModel @AssistedInject constructor( handleChangeDisplayNameForRoomSlashCommand(slashCommandResult) popDraft() } + is ParsedCommand.ChangeRoomAvatar -> { + handleChangeRoomAvatarSlashCommand(slashCommandResult) + popDraft() + } is ParsedCommand.ChangeAvatarForRoom -> { handleChangeAvatarForRoomSlashCommand(slashCommandResult) popDraft() @@ -857,6 +862,12 @@ class RoomDetailViewModel @AssistedInject constructor( } } + private fun handleChangeRoomAvatarSlashCommand(changeAvatar: ParsedCommand.ChangeRoomAvatar) { + launchSlashCommandFlow { + room.sendStateEvent(EventType.STATE_ROOM_AVATAR, null, RoomAvatarContent(changeAvatar.url).toContent(), it) + } + } + private fun handleChangeAvatarForRoomSlashCommand(changeAvatar: ParsedCommand.ChangeAvatarForRoom) { launchSlashCommandFlow { room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, getLastMemberEvent().copy(avatarUrl = changeAvatar.url).toContent(), it) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 823d567f20..909ef01b4c 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1299,6 +1299,7 @@ Kicks user with given id Changes your display nickname Changes your display nickname in the current room only + Changes the avatar of the current room Changes your avatar in this current room only On/Off markdown To fix Matrix Apps management From 5b6727408b5498aa553f7781ecb63d2b2863066b Mon Sep 17 00:00:00 2001 From: Constantin Wartenburger Date: Tue, 13 Oct 2020 15:10:57 +0200 Subject: [PATCH 5/8] Fix wrong parameter name --- .../src/main/java/im/vector/app/features/command/Command.kt | 2 +- .../main/java/im/vector/app/features/command/CommandParser.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt index b74b608e32..81bbf8177d 100644 --- a/vector/src/main/java/im/vector/app/features/command/Command.kt +++ b/vector/src/main/java/im/vector/app/features/command/Command.kt @@ -32,7 +32,7 @@ enum class Command(val command: String, val parameters: String, @StringRes val d UNIGNORE_USER("/unignore", "", R.string.command_description_unignore_user), SET_USER_POWER_LEVEL("/op", " []", R.string.command_description_op_user), RESET_USER_POWER_LEVEL("/deop", "", R.string.command_description_deop_user), - ROOM_NAME("/roomname", "", R.string.command_description_room_name), + ROOM_NAME("/roomname", "", R.string.command_description_room_name), INVITE("/invite", " [reason]", R.string.command_description_invite_user), JOIN_ROOM("/join", " [reason]", R.string.command_description_join_room), PART("/part", " [reason]", R.string.command_description_part_room), diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index 41961c209a..29eba00490 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -91,7 +91,7 @@ object CommandParser { if (messageParts.size == 2) { val url = messageParts[1] - if (url.isNotEmpty() && url.startsWith("mxc://")) { + if (url.startsWith("mxc://")) { ParsedCommand.ChangeRoomAvatar(url) } else { ParsedCommand.ErrorSyntax(Command.ROOM_AVATAR) @@ -104,7 +104,7 @@ object CommandParser { if (messageParts.size == 2) { val url = messageParts[1] - if (url.isNotEmpty() && url.startsWith("mxc://")) { + if (url.startsWith("mxc://")) { ParsedCommand.ChangeAvatarForRoom(url) } else { ParsedCommand.ErrorSyntax(Command.CHANGE_AVATAR_FOR_ROOM) From 5076369173dbc91c94837eb9317ddc15559cebe2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 4 Oct 2021 16:16:13 +0200 Subject: [PATCH 6/8] Improve code --- .../im/vector/app/features/command/Command.kt | 2 +- .../home/room/detail/RoomDetailViewModel.kt | 1 - .../detail/composer/TextComposerViewEvents.kt | 1 - .../detail/composer/TextComposerViewModel.kt | 21 +++++++++++++------ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt index 22a6de14fb..33ccd08d22 100644 --- a/vector/src/main/java/im/vector/app/features/command/Command.kt +++ b/vector/src/main/java/im/vector/app/features/command/Command.kt @@ -49,7 +49,7 @@ enum class Command(val command: String, val parameters: String, @StringRes val d SPOILER("/spoiler", "", R.string.command_description_spoiler, false), POLL("/poll", "Question | Option 1 | Option 2 ...", R.string.command_description_poll, false), SHRUG("/shrug", "", R.string.command_description_shrug, false), - LENNY("/lenny", "[]", R.string.command_description_lenny, false), + LENNY("/lenny", "", R.string.command_description_lenny, false), PLAIN("/plain", "", R.string.command_description_plain, false), WHOIS("/whois", "", R.string.command_description_whois, false), DISCARD_SESSION("/discardsession", "", R.string.command_description_discard_session, false), diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index e8cafa94f8..bd11ec6718 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -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 diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewEvents.kt index 226e7f8bf4..691ed4d93e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewEvents.kt @@ -19,7 +19,6 @@ package im.vector.app.features.home.room.detail.composer import androidx.annotation.StringRes import im.vector.app.core.platform.VectorViewEvents import im.vector.app.features.command.Command -import im.vector.app.features.home.room.detail.RoomDetailViewEvents sealed class TextComposerViewEvents : VectorViewEvents { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt index c5b86148e6..35871611c0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt @@ -45,7 +45,6 @@ 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.Membership 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 @@ -607,15 +606,20 @@ class TextComposerViewModel @AssistedInject constructor( } } - private fun getLastMemberEvent(): RoomMemberContent { + private fun getMyRoomMemberContent(): RoomMemberContent? { return room.getStateEvent(EventType.STATE_ROOM_MEMBER, QueryStringValue.Equals(session.myUserId)) - ?.content?.toModel() - ?: RoomMemberContent(membership = Membership.JOIN) + ?.content + ?.toModel() } private fun handleChangeDisplayNameForRoomSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayNameForRoom) { launchSlashCommandFlowSuspendable { - room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, getLastMemberEvent().copy(displayName = changeDisplayName.displayName).toContent()) + getMyRoomMemberContent() + ?.copy(displayName = changeDisplayName.displayName) + ?.toContent() + ?.let { + room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it) + } } } @@ -627,7 +631,12 @@ class TextComposerViewModel @AssistedInject constructor( private fun handleChangeAvatarForRoomSlashCommand(changeAvatar: ParsedCommand.ChangeAvatarForRoom) { launchSlashCommandFlowSuspendable { - room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, getLastMemberEvent().copy(avatarUrl = changeAvatar.url).toContent()) + getMyRoomMemberContent() + ?.copy(avatarUrl = changeAvatar.url) + ?.toContent() + ?.let { + room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it) + } } } From 068c9393f1482f49c8c9309aa568d6af7fabfadf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 4 Oct 2021 16:24:57 +0200 Subject: [PATCH 7/8] Create extension `String.isMxcUrl()` --- changelog.d/4158.removal | 1 + .../org/matrix/android/sdk/api/MatrixUrls.kt | 26 +++++++++++++++++++ .../content/DefaultContentUrlResolver.kt | 14 ++++------ .../session/room/send/DefaultSendService.kt | 3 ++- .../app/features/command/CommandParser.kt | 5 ++-- .../timeline/factory/MessageItemFactory.kt | 5 ++-- 6 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 changelog.d/4158.removal create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt diff --git a/changelog.d/4158.removal b/changelog.d/4158.removal new file mode 100644 index 0000000000..557a85262e --- /dev/null +++ b/changelog.d/4158.removal @@ -0,0 +1 @@ +Create extension `String.isMxcUrl()` \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt new file mode 100644 index 0000000000..dc4e0f152d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt @@ -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) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt index e4efdaa254..5c8cf99dc6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt @@ -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) - } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt index dbc30efcc4..177c98541c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt @@ -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() 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) diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index 71dbf22ebc..e570033d35 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -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 @@ -92,7 +93,7 @@ object CommandParser { if (messageParts.size == 2) { val url = messageParts[1] - if (url.startsWith("mxc://")) { + if (url.isMxcUrl()) { ParsedCommand.ChangeRoomAvatar(url) } else { ParsedCommand.ErrorSyntax(Command.ROOM_AVATAR) @@ -105,7 +106,7 @@ object CommandParser { if (messageParts.size == 2) { val url = messageParts[1] - if (url.startsWith("mxc://")) { + if (url.isMxcUrl()) { ParsedCommand.ChangeAvatarForRoom(url) } else { ParsedCommand.ErrorSyntax(Command.CHANGE_AVATAR_FOR_ROOM) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index ada06422a5..98deaaf9c3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -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() } } } ?: "" From 90781dbd9959a778c7b01baa964fafd9e5fafebd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 4 Oct 2021 16:28:49 +0200 Subject: [PATCH 8/8] changelog --- changelog.d/4158.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/4158.feature diff --git a/changelog.d/4158.feature b/changelog.d/4158.feature new file mode 100644 index 0000000000..86d2c760c2 --- /dev/null +++ b/changelog.d/4158.feature @@ -0,0 +1 @@ +Handle 8 new slash commands: `/ignore`, `/unignore`, `/roomname`, `/myroomnick`, `/roomavatar`, `/myroomavatar`, `/lenny`, `/whois`. \ No newline at end of file