From 9e0a8ef2e3f8107d9d2e6ea4496193433cadf4ce Mon Sep 17 00:00:00 2001 From: Aleksandar Apostolov Date: Tue, 18 Jun 2024 17:55:41 +0200 Subject: [PATCH] [PBE-3848] add additional option over message xml compose for user blocking (#5289) * Add the API to block/unblock users and expose it via chat client * Use `Date` instead of raw `String` for dates. * Remove list as response and add single `UserBlock` instead for both block and unblock * Add block/unblock support into `MessageListController` * Api & Spotless * Api & Spotless after merge * Add option to block user in the menu items of a message both in compose and xml * Remove useless bool check for capability --- .../messageoptions/MessageOptions.kt | 12 +++++ .../src/main/res/values/strings.xml | 1 + .../api/stream-chat-android-ui-common.api | 14 ++++++ .../messages/list/MessageListController.kt | 28 +++++++++++ .../ui/common/state/messages/MessageAction.kt | 6 +++ .../api/stream-chat-android-ui-components.api | 48 +++++++++++++------ .../feature/messages/list/MessageListView.kt | 27 +++++++++++ .../messages/list/MessageListViewStyle.kt | 14 ++++++ .../message/MessageOptionItemsFactory.kt | 10 ++++ .../messages/MessageListViewModel.kt | 9 ++++ .../messages/MessageListViewModelBinding.kt | 7 +++ .../res/values/attrs_message_list_view.xml | 2 + 12 files changed, 164 insertions(+), 14 deletions(-) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptions.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptions.kt index b28f341f09b..39e8be9967f 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptions.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptions.kt @@ -41,6 +41,7 @@ import io.getstream.chat.android.models.ChannelCapabilities import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.SyncStatus import io.getstream.chat.android.models.User +import io.getstream.chat.android.ui.common.state.messages.BlockUser import io.getstream.chat.android.ui.common.state.messages.Copy import io.getstream.chat.android.ui.common.state.messages.Delete import io.getstream.chat.android.ui.common.state.messages.Edit @@ -242,6 +243,17 @@ public fun defaultMessageOptionsState( } else { null }, + if (!isOwnMessage) { + MessageOptionItemState( + title = R.string.stream_compose_block_user, + iconPainter = painterResource(R.drawable.stream_compose_ic_clear), + action = BlockUser(selectedMessage), + iconColor = ChatTheme.colors.textLowEmphasis, + titleColor = ChatTheme.colors.textHighEmphasis, + ) + } else { + null + }, if (visibility.isDeleteMessageVisible && isDeleteMessagePossible) { MessageOptionItemState( title = R.string.stream_compose_delete_message, diff --git a/stream-chat-android-compose/src/main/res/values/strings.xml b/stream-chat-android-compose/src/main/res/values/strings.xml index 07a4a08213e..889bfaa4659 100644 --- a/stream-chat-android-compose/src/main/res/values/strings.xml +++ b/stream-chat-android-compose/src/main/res/values/strings.xml @@ -85,6 +85,7 @@ File + Block user Resend Reply Thread reply diff --git a/stream-chat-android-ui-common/api/stream-chat-android-ui-common.api b/stream-chat-android-ui-common/api/stream-chat-android-ui-common.api index 4b4360bfe02..a7a392bb410 100644 --- a/stream-chat-android-ui-common/api/stream-chat-android-ui-common.api +++ b/stream-chat-android-ui-common/api/stream-chat-android-ui-common.api @@ -132,6 +132,7 @@ public final class io/getstream/chat/android/ui/common/feature/messages/list/Mes public synthetic fun (Ljava/lang/String;Lio/getstream/chat/android/ui/common/helper/ClipboardHandler;ZLjava/lang/String;Ljava/lang/String;ILio/getstream/chat/android/client/ChatClient;Lio/getstream/chat/android/client/setup/state/ClientState;Lio/getstream/chat/android/ui/common/state/messages/list/DeletedMessageVisibility;ZLio/getstream/chat/android/ui/common/state/messages/list/MessageFooterVisibility;ZLio/getstream/chat/android/ui/common/feature/messages/list/DateSeparatorHandler;Lio/getstream/chat/android/ui/common/feature/messages/list/DateSeparatorHandler;Lio/getstream/chat/android/ui/common/feature/messages/list/MessagePositionHandler;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun banUser (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V public static synthetic fun banUser$default (Lio/getstream/chat/android/ui/common/feature/messages/list/MessageListController;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;ILjava/lang/Object;)V + public final fun blockUser (Ljava/lang/String;)V public final fun clearNewMessageState ()V public final fun deleteMessage (Lio/getstream/chat/android/models/Message;Z)V public static synthetic fun deleteMessage$default (Lio/getstream/chat/android/ui/common/feature/messages/list/MessageListController;Lio/getstream/chat/android/models/Message;ZILjava/lang/Object;)V @@ -202,6 +203,7 @@ public final class io/getstream/chat/android/ui/common/feature/messages/list/Mes public final fun shadowBanUser (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V public static synthetic fun shadowBanUser$default (Lio/getstream/chat/android/ui/common/feature/messages/list/MessageListController;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;ILjava/lang/Object;)V public final fun unbanUser (Ljava/lang/String;)V + public final fun unblockUser (Ljava/lang/String;)V public final fun unmuteUser (Lio/getstream/chat/android/models/User;)V public final fun unmuteUser (Ljava/lang/String;)V public final fun unpinMessage (Lio/getstream/chat/android/models/Message;)V @@ -517,6 +519,18 @@ public final class io/getstream/chat/android/ui/common/state/channels/actions/Vi public fun toString ()Ljava/lang/String; } +public final class io/getstream/chat/android/ui/common/state/messages/BlockUser : io/getstream/chat/android/ui/common/state/messages/MessageAction { + public static final field $stable I + public fun (Lio/getstream/chat/android/models/Message;)V + public final fun component1 ()Lio/getstream/chat/android/models/Message; + public final fun copy (Lio/getstream/chat/android/models/Message;)Lio/getstream/chat/android/ui/common/state/messages/BlockUser; + public static synthetic fun copy$default (Lio/getstream/chat/android/ui/common/state/messages/BlockUser;Lio/getstream/chat/android/models/Message;ILjava/lang/Object;)Lio/getstream/chat/android/ui/common/state/messages/BlockUser; + public fun equals (Ljava/lang/Object;)Z + public fun getMessage ()Lio/getstream/chat/android/models/Message; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/chat/android/ui/common/state/messages/Copy : io/getstream/chat/android/ui/common/state/messages/MessageAction { public static final field $stable I public fun (Lio/getstream/chat/android/models/Message;)V diff --git a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/list/MessageListController.kt b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/list/MessageListController.kt index a8d15ada07b..2e90143236e 100644 --- a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/list/MessageListController.kt +++ b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/list/MessageListController.kt @@ -60,6 +60,7 @@ import io.getstream.chat.android.state.extensions.loadOlderMessages import io.getstream.chat.android.state.extensions.watchChannelAsState import io.getstream.chat.android.state.plugin.state.channel.thread.ThreadState import io.getstream.chat.android.ui.common.helper.ClipboardHandler +import io.getstream.chat.android.ui.common.state.messages.BlockUser import io.getstream.chat.android.ui.common.state.messages.Copy import io.getstream.chat.android.ui.common.state.messages.Delete import io.getstream.chat.android.ui.common.state.messages.MarkAsUnread @@ -1431,6 +1432,7 @@ public class MessageListController( is Delete, is FlagMessage -> { _messageActions.value = _messageActions.value + messageAction } + is BlockUser -> blockUser(messageAction.message.user.id) is Copy -> copyMessage(messageAction.message) is React -> reactToMessage(messageAction.reaction, messageAction.message) is Pin -> updateMessagePin(messageAction.message) @@ -1873,6 +1875,32 @@ public class MessageListController( }) } + /** + * Block a user. Unlike ban the block is not channel related but rather directly to the user. + * + * @param userId the id of the user that will be blocked. + */ + public fun blockUser(userId: String) { + chatClient.blockUser(userId).enqueue(onError = { error -> + onActionResult(error) { + ErrorEvent.BlockUserError(it) + } + }) + } + + /** + * Unblock a user. + * + * @param userId the id of the user that will be unblocked. + */ + public fun unblockUser(userId: String) { + chatClient.unblockUser(userId).enqueue(onError = { error -> + onActionResult(error) { + ErrorEvent.BlockUserError(it) + } + }) + } + /** * Executes one of the actions for the given ephemeral giphy message. * diff --git a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/state/messages/MessageAction.kt b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/state/messages/MessageAction.kt index f82096ff2a6..7f57c5bce16 100644 --- a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/state/messages/MessageAction.kt +++ b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/state/messages/MessageAction.kt @@ -98,6 +98,11 @@ public data class Flag( override val message: Message, ) : MessageAction() +/** + * Block the sender of the message. + */ +public data class BlockUser(override val message: Message) : MessageAction() + /** * User-customizable action, with any number of extra properties. * @@ -121,5 +126,6 @@ public fun MessageAction.updateMessage(message: Message): MessageAction { is Delete -> copy(message = message) is Flag -> copy(message = message) is CustomAction -> copy(message = message) + is BlockUser -> copy(message = message) } } diff --git a/stream-chat-android-ui-components/api/stream-chat-android-ui-components.api b/stream-chat-android-ui-components/api/stream-chat-android-ui-components.api index c6833806051..0ff6a9e8d29 100644 --- a/stream-chat-android-ui-components/api/stream-chat-android-ui-components.api +++ b/stream-chat-android-ui-components/api/stream-chat-android-ui-components.api @@ -2108,6 +2108,7 @@ public final class io/getstream/chat/android/ui/feature/messages/list/MessageLis public final fun setMessageRetryHandler (Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$MessageRetryHandler;)V public final fun setMessageRetryListener (Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$MessageRetryListener;)V public final fun setMessageUnpinHandler (Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$MessageUnpinHandler;)V + public final fun setMessageUserBlockHandler (Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$MessageUserBlockHandler;)V public final fun setMessageViewHolderFactory (Lio/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItemViewHolderFactory;)V public final fun setModeratedMessageHandler (Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$ModeratedMessageOptionHandler;)V public final fun setModeratedMessageLongClickListener (Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$ModeratedMessageLongClickListener;)V @@ -2267,6 +2268,10 @@ public abstract interface class io/getstream/chat/android/ui/feature/messages/li public abstract fun onMessageUnpin (Lio/getstream/chat/android/models/Message;)V } +public abstract interface class io/getstream/chat/android/ui/feature/messages/list/MessageListView$MessageUserBlockHandler { + public abstract fun onUserBlocked (Lio/getstream/chat/android/models/Message;)V +} + public final class io/getstream/chat/android/ui/feature/messages/list/MessageListView$MessagesStart : java/lang/Enum { public static final field BOTTOM Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$MessagesStart; public static final field TOP Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$MessagesStart; @@ -2389,7 +2394,7 @@ public abstract interface class io/getstream/chat/android/ui/feature/messages/li public final class io/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle : io/getstream/chat/android/ui/helper/ViewStyle { public static final field Companion Lio/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle$Companion; - public fun (Lio/getstream/chat/android/ui/feature/messages/list/ScrollButtonViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$NewMessagesBehaviour;Lio/getstream/chat/android/ui/feature/messages/list/MessageListItemStyle;Lio/getstream/chat/android/ui/feature/messages/list/GiphyViewHolderStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageReplyStyle;Lio/getstream/chat/android/ui/feature/messages/list/UnreadLabelButtonStyle;ZIIZIZIIIZIIZIIZIZZZZZZLio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;IILio/getstream/chat/android/ui/font/TextStyle;ILio/getstream/chat/android/ui/font/TextStyle;IIIIIIZIIIIIIIIIIIIZZ)V + public fun (Lio/getstream/chat/android/ui/feature/messages/list/ScrollButtonViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$NewMessagesBehaviour;Lio/getstream/chat/android/ui/feature/messages/list/MessageListItemStyle;Lio/getstream/chat/android/ui/feature/messages/list/GiphyViewHolderStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageReplyStyle;Lio/getstream/chat/android/ui/feature/messages/list/UnreadLabelButtonStyle;ZIIZIZIIIZIIZIIZIZIZZZZZZLio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;IILio/getstream/chat/android/ui/font/TextStyle;ILio/getstream/chat/android/ui/font/TextStyle;IIIIIIZIIIIIIIIIIIIZZ)V public final fun component1 ()Lio/getstream/chat/android/ui/feature/messages/list/ScrollButtonViewStyle; public final fun component10 ()I public final fun component11 ()Z @@ -2408,29 +2413,29 @@ public final class io/getstream/chat/android/ui/feature/messages/list/MessageLis public final fun component23 ()Z public final fun component24 ()I public final fun component25 ()Z - public final fun component26 ()Z + public final fun component26 ()I public final fun component27 ()Z public final fun component28 ()Z public final fun component29 ()Z public final fun component3 ()Lio/getstream/chat/android/ui/feature/messages/list/MessageListItemStyle; public final fun component30 ()Z - public final fun component31 ()Lio/getstream/chat/android/ui/font/TextStyle; - public final fun component32 ()Lio/getstream/chat/android/ui/font/TextStyle; - public final fun component33 ()I - public final fun component34 ()I - public final fun component35 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component31 ()Z + public final fun component32 ()Z + public final fun component33 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component34 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component35 ()I public final fun component36 ()I public final fun component37 ()Lio/getstream/chat/android/ui/font/TextStyle; public final fun component38 ()I - public final fun component39 ()I + public final fun component39 ()Lio/getstream/chat/android/ui/font/TextStyle; public final fun component4 ()Lio/getstream/chat/android/ui/feature/messages/list/GiphyViewHolderStyle; public final fun component40 ()I public final fun component41 ()I public final fun component42 ()I public final fun component43 ()I - public final fun component44 ()Z + public final fun component44 ()I public final fun component45 ()I - public final fun component46 ()I + public final fun component46 ()Z public final fun component47 ()I public final fun component48 ()I public final fun component49 ()I @@ -2442,17 +2447,21 @@ public final class io/getstream/chat/android/ui/feature/messages/list/MessageLis public final fun component54 ()I public final fun component55 ()I public final fun component56 ()I - public final fun component57 ()Z - public final fun component58 ()Z + public final fun component57 ()I + public final fun component58 ()I + public final fun component59 ()Z public final fun component6 ()Lio/getstream/chat/android/ui/feature/messages/list/MessageReplyStyle; + public final fun component60 ()Z public final fun component7 ()Lio/getstream/chat/android/ui/feature/messages/list/UnreadLabelButtonStyle; public final fun component8 ()Z public final fun component9 ()I - public final fun copy (Lio/getstream/chat/android/ui/feature/messages/list/ScrollButtonViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$NewMessagesBehaviour;Lio/getstream/chat/android/ui/feature/messages/list/MessageListItemStyle;Lio/getstream/chat/android/ui/feature/messages/list/GiphyViewHolderStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageReplyStyle;Lio/getstream/chat/android/ui/feature/messages/list/UnreadLabelButtonStyle;ZIIZIZIIIZIIZIIZIZZZZZZLio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;IILio/getstream/chat/android/ui/font/TextStyle;ILio/getstream/chat/android/ui/font/TextStyle;IIIIIIZIIIIIIIIIIIIZZ)Lio/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle; - public static synthetic fun copy$default (Lio/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/ScrollButtonViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$NewMessagesBehaviour;Lio/getstream/chat/android/ui/feature/messages/list/MessageListItemStyle;Lio/getstream/chat/android/ui/feature/messages/list/GiphyViewHolderStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageReplyStyle;Lio/getstream/chat/android/ui/feature/messages/list/UnreadLabelButtonStyle;ZIIZIZIIIZIIZIIZIZZZZZZLio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;IILio/getstream/chat/android/ui/font/TextStyle;ILio/getstream/chat/android/ui/font/TextStyle;IIIIIIZIIIIIIIIIIIIZZIILjava/lang/Object;)Lio/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle; + public final fun copy (Lio/getstream/chat/android/ui/feature/messages/list/ScrollButtonViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$NewMessagesBehaviour;Lio/getstream/chat/android/ui/feature/messages/list/MessageListItemStyle;Lio/getstream/chat/android/ui/feature/messages/list/GiphyViewHolderStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageReplyStyle;Lio/getstream/chat/android/ui/feature/messages/list/UnreadLabelButtonStyle;ZIIZIZIIIZIIZIIZIZIZZZZZZLio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;IILio/getstream/chat/android/ui/font/TextStyle;ILio/getstream/chat/android/ui/font/TextStyle;IIIIIIZIIIIIIIIIIIIZZ)Lio/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle; + public static synthetic fun copy$default (Lio/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/ScrollButtonViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageListView$NewMessagesBehaviour;Lio/getstream/chat/android/ui/feature/messages/list/MessageListItemStyle;Lio/getstream/chat/android/ui/feature/messages/list/GiphyViewHolderStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageViewStyle;Lio/getstream/chat/android/ui/feature/messages/list/MessageReplyStyle;Lio/getstream/chat/android/ui/feature/messages/list/UnreadLabelButtonStyle;ZIIZIZIIIZIIZIIZIZIZZZZZZLio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;IILio/getstream/chat/android/ui/font/TextStyle;ILio/getstream/chat/android/ui/font/TextStyle;IIIIIIZIIIIIIIIIIIIZZIILjava/lang/Object;)Lio/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle; public fun equals (Ljava/lang/Object;)Z public final fun getAudioRecordPlayerViewStyle ()Lio/getstream/chat/android/ui/feature/messages/list/MessageViewStyle; public final fun getBackgroundColor ()I + public final fun getBlockUserEnabled ()Z + public final fun getBlockUserIcon ()I public final fun getCopyIcon ()I public final fun getCopyTextEnabled ()Z public final fun getDeleteConfirmationEnabled ()Z @@ -4264,6 +4273,17 @@ public final class io/getstream/chat/android/ui/viewmodel/messages/MessageListVi public fun toString ()Ljava/lang/String; } +public final class io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel$Event$BlockUser : io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel$Event { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel$Event$BlockUser; + public static synthetic fun copy$default (Lio/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel$Event$BlockUser;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel$Event$BlockUser; + public fun equals (Ljava/lang/Object;)Z + public final fun getUserId ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel$Event$BottomEndRegionReached : io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel$Event { public fun (Ljava/lang/String;)V public final fun component1 ()Ljava/lang/String; diff --git a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/MessageListView.kt b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/MessageListView.kt index 4b288cf3398..91c0d32d881 100644 --- a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/MessageListView.kt +++ b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/MessageListView.kt @@ -52,6 +52,7 @@ import io.getstream.chat.android.ui.ChatUI import io.getstream.chat.android.ui.R import io.getstream.chat.android.ui.common.feature.messages.list.MessageListController import io.getstream.chat.android.ui.common.helper.DateFormatter +import io.getstream.chat.android.ui.common.state.messages.BlockUser import io.getstream.chat.android.ui.common.state.messages.Copy import io.getstream.chat.android.ui.common.state.messages.CustomAction import io.getstream.chat.android.ui.common.state.messages.Delete @@ -199,6 +200,9 @@ public class MessageListView : ConstraintLayout { private var messageFlagHandler = MessageFlagHandler { throw IllegalStateException("onMessageFlagHandler must be set.") } + private var messageUserBlockHandler = MessageUserBlockHandler { + throw IllegalStateException("onMessageFlagHandler must be set.") + } private var flagMessageResultHandler = FlagMessageResultHandler { // no-op } @@ -338,6 +342,7 @@ public class MessageListView : ConstraintLayout { replyMessageClickListener.onReplyClick(replyTo) true } + else -> false } } @@ -511,6 +516,7 @@ public class MessageListView : ConstraintLayout { attachmentGalleryDestination.setData(attachmentGalleryItems, attachmentIndex) attachmentGalleryDestination } + else -> AttachmentDestination(message, attachment, context) } @@ -1798,6 +1804,15 @@ public class MessageListView : ConstraintLayout { this.messageMarkAsUnreadHandler = messageMarkAsUnreadHandler } + /** + * Set a handler used to handle when a user is blocked. + * + * @param messageUserBlockHandler the handler + */ + public fun setMessageUserBlockHandler(messageUserBlockHandler: MessageUserBlockHandler) { + this.messageUserBlockHandler = messageUserBlockHandler + } + /** * Sets the handler used to handle when the message is going to be unpinned. * @@ -2016,6 +2031,7 @@ public class MessageListView : ConstraintLayout { val displayedText = message.getTranslatedText() context.copyToClipboard(displayedText) } + is Edit -> messageEditHandler.onMessageEdit(message) is Pin -> { if (message.pinned) { @@ -2024,6 +2040,7 @@ public class MessageListView : ConstraintLayout { messagePinHandler.onMessagePin(message) } } + is MarkAsUnread -> messageMarkAsUnreadHandler.onMessageMarkAsUnread(message) is Delete -> { if (style.deleteConfirmationEnabled) { @@ -2034,6 +2051,7 @@ public class MessageListView : ConstraintLayout { messageDeleteHandler.onMessageDelete(message) } } + is FlagAction -> { if (style.flagMessageConfirmationEnabled) { confirmFlagMessageHandler.onConfirmFlagMessage(message) { @@ -2043,10 +2061,15 @@ public class MessageListView : ConstraintLayout { messageFlagHandler.onMessageFlag(message) } } + is CustomAction -> customActionHandler.onCustomAction(message, messageAction.extraProperties) is React -> { // Handled by a separate handler. } + + is BlockUser -> { + messageUserBlockHandler.onUserBlocked(message) + } } } @@ -2295,6 +2318,10 @@ public class MessageListView : ConstraintLayout { public fun onMessageFlag(message: Message) } + public fun interface MessageUserBlockHandler { + public fun onUserBlocked(message: Message) + } + public fun interface MessagePinHandler { public fun onMessagePin(message: Message) } diff --git a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle.kt b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle.kt index 9bc6f685f52..d855cf9d8af 100644 --- a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle.kt +++ b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/MessageListViewStyle.kt @@ -124,6 +124,8 @@ public data class MessageListViewStyle( val pinMessageEnabled: Boolean, val deleteIcon: Int, val deleteMessageEnabled: Boolean, + val blockUserIcon: Int, + val blockUserEnabled: Boolean, val copyTextEnabled: Boolean, val markAsUnreadEnabled: Boolean, val retryMessageEnabled: Boolean, @@ -588,7 +590,19 @@ public data class MessageListViewStyle( true, ) + val userBlockEnabled = attributes.getBoolean( + R.styleable.MessageListView_streamUiBlockUserOptionEnabled, + true, + ) + + val userBlockIcon = attributes.getResourceId( + R.styleable.MessageListView_streamUiBlockUserOptionIcon, + R.drawable.stream_ui_ic_clear, + ) + return MessageListViewStyle( + blockUserEnabled = userBlockEnabled, + blockUserIcon = userBlockIcon, scrollButtonViewStyle = scrollButtonViewStyle, scrollButtonBehaviour = scrollButtonBehaviour, scrollButtonBottomMargin = scrollButtonMarginBottom, diff --git a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/options/message/MessageOptionItemsFactory.kt b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/options/message/MessageOptionItemsFactory.kt index c24621023c5..6630d75dce7 100644 --- a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/options/message/MessageOptionItemsFactory.kt +++ b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/options/message/MessageOptionItemsFactory.kt @@ -24,6 +24,7 @@ import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.SyncStatus import io.getstream.chat.android.models.User import io.getstream.chat.android.ui.R +import io.getstream.chat.android.ui.common.state.messages.BlockUser import io.getstream.chat.android.ui.common.state.messages.Copy import io.getstream.chat.android.ui.common.state.messages.Delete import io.getstream.chat.android.ui.common.state.messages.Edit @@ -202,6 +203,15 @@ public open class DefaultMessageOptionItemsFactory( } else { null }, + if (style.blockUserEnabled && !isOwnMessage) { + MessageOptionItem( + optionText = context.getString(R.string.stream_ui_message_list_block_user), + optionIcon = context.getDrawableCompat(style.blockUserIcon)!!, + messageAction = BlockUser(selectedMessage), + ) + } else { + null + }, if (style.deleteMessageEnabled && (canDeleteAnyMessage || (isOwnMessage && canDeleteOwnMessage))) { MessageOptionItem( optionText = context.getString(R.string.stream_ui_message_list_delete_message), diff --git a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel.kt b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel.kt index 91cd7d133e7..81a40146ce6 100644 --- a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel.kt +++ b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModel.kt @@ -285,6 +285,8 @@ public class MessageListViewModel( true -> messageListController.scrollToFirstUnreadMessage() false -> messageListController.disableUnreadLabelButton() } + + is Event.BlockUser -> messageListController.blockUser(event.userId) } } @@ -700,5 +702,12 @@ public class MessageListViewModel( * @param navigateToFirstUnreadMessage If true, the user will be navigated to the first unread message. */ public data class HideUnreadLabel(val navigateToFirstUnreadMessage: Boolean) : Event() + + /** + * Block a user. + * + * @param userId the id of the user that is blocked. + */ + public data class BlockUser(val userId: String) : Event() } } diff --git a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModelBinding.kt b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModelBinding.kt index 59e9730f37b..e911b71641b 100644 --- a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModelBinding.kt +++ b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageListViewModelBinding.kt @@ -98,6 +98,13 @@ public fun MessageListViewModel.bindView( ) } view.setOnScrollToBottomHandler { scrollToBottom { view.scrollToBottom() } } + view.setMessageUserBlockHandler { message -> + onEvent( + MessageListViewModel.Event.BlockUser( + message.user.id, + ), + ) + } ownCapabilities.observe(lifecycleOwner) { view.setOwnCapabilities(it) diff --git a/stream-chat-android-ui-components/src/main/res/values/attrs_message_list_view.xml b/stream-chat-android-ui-components/src/main/res/values/attrs_message_list_view.xml index c637257a7e9..6bc947b7fbc 100644 --- a/stream-chat-android-ui-components/src/main/res/values/attrs_message_list_view.xml +++ b/stream-chat-android-ui-components/src/main/res/values/attrs_message_list_view.xml @@ -426,6 +426,8 @@ + +