diff --git a/CHANGELOG.md b/CHANGELOG.md index e305ac83431..2f36ab90351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,8 +81,12 @@ ### ⬆️ Improved ### ✅ Added +- Added `MessageOptionItemVisibility` class that controls menu item visibility in the selected message options menu. +- Added new `ChatTheme.messageOptionItemVisibility` property of type `MessageOptionItemVisibility`. +- Added docs sections that describe these changes. ### ⚠️ Changed +- Used the new `ChatTheme.messageOptionItemVisibility` property in `defaultMessageOptionsState()` in combination with own capabilities to control menu option item visibility. ### ❌ Removed diff --git a/docusaurus/docs/Android/compose/general-customization/chat-theme.mdx b/docusaurus/docs/Android/compose/general-customization/chat-theme.mdx index fa2978f3bfc..42b6a0b21e3 100644 --- a/docusaurus/docs/Android/compose/general-customization/chat-theme.mdx +++ b/docusaurus/docs/Android/compose/general-customization/chat-theme.mdx @@ -12,11 +12,13 @@ The `ChatTheme` component is a wrapper that **you should use as the root** of al * `attachmentPreviewHandlers`: Used to provide previews for all supported attachment types. If you do not wish to use the default previews, you can customize this. * `quotedAttachmentFactories`: Used to process messages and show different types of attachment UI, when quoting a message that contains an attachment. * `reactionIconFactory`: Used to create a reaction icon for the given reaction type. You can use the default factory that supports a predefined set of reactions, or provide a custom one. +* `reactionOptionsTheme`: Used to define the appearance of the reaction option list in the selected message menu. For theming the message option list in the same menu, see `messageOptionsTheme` below. * `dateFormatter`: Used to define the timestamp formatting in the app. You can use the default formatting, or customize it to your needs. * `channelNameFormatter`: Used to define the channel name formatting in the app. You can use the default implementation, or customize it according to your needs. * `messagePreviewFormatter`: Used to define the message preview formatting in the app. You can use the default implementation, or customize the display of message previews according to your needs. * `imageLoaderFactory`: Used to create Coil image loader instances. You can use the default image loader factory, or provide a custom one. * `messageAlignmentProvider`: Used to provide an alignment for a particular message. You can use the default implementation which aligns the messages of the current user to end, or customize it according to your needs. +* `messageOptionsTheme`: Used to define the appearance of the message option list in the selected message menu. For theming the reaction option list in the same menu, see `reactionOptionsTheme` above. * `messageOptionsUserReactionAlignment`: Used to define how message reactions are aligned when browsing all reactions for a given message. * `permissionHandlers`: Used to handle permissions inside the app. Default implementation of the download permission handler automatically downloads files after the permission has been granted. * `attachmentsPickerTabFactories`: Used to display different tabs in the attachments picker dialog. @@ -170,6 +172,12 @@ You can find their definitions in the [class documentation](https://github.com/G Reactions are easily customizable by passing in your own `ReactionIconFactory` which contains reactions and overriding `ChatTheme.reactionIconFactory` with it. +### ReactionOptionsTheme + +Defines the appearance of the reaction option list in the selected message menu. Allows you to show/hide options through the `areReactionOptionsVisible` parameter. + +See the [class documentation](https://github.com/GetStream/stream-chat-android/blob/0817af6b82cd72d541ed5e816fef8a3a27441e69/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme.kt) for more details. + ### DateFormatter Used for formatting various times and dates such as the timestamp you see when a message is displayed. The default date formatter in `ChatTheme` is Stream's `DefaultDateFormatter`. @@ -303,6 +311,12 @@ You can find out more about it by reading the [class documentation](https://gith As with all of the other `ChatTheme` properties, you can easily customize how the messages are aligned by overriding `ChatTheme.messageAlignmentProvider` with your own implementation of `MessageAlignmentProvider`. +### MessageOptionsTheme + +Defines the appearance of the message option list in the selected message menu. Allows you to show/hide options through the `optionVisibility` parameter. + +See the [class documentation](https://github.com/GetStream/stream-chat-android/blob/e01d636f66fb0986ab71288f4ddee92afe550fd0/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/MessageOptionsTheme.kt) for more details. + ### MessageOptionsUserReactionAlignment Determines the alignment of the reaction icon inside user reactions. By default, they are aligned to the end. diff --git a/docusaurus/docs/Android/compose/guides/implementing-own-capabilities.mdx b/docusaurus/docs/Android/compose/guides/implementing-own-capabilities.mdx index d51f5d1e59e..6254759a8c4 100644 --- a/docusaurus/docs/Android/compose/guides/implementing-own-capabilities.mdx +++ b/docusaurus/docs/Android/compose/guides/implementing-own-capabilities.mdx @@ -102,7 +102,7 @@ public fun defaultMessageOptionsState( ): List ``` -This function uses `ownCapabilities` to produce the correct list of `MessageOptionItemState`. +This function uses the [`ChatTheme.messageOptionsTheme.optionVisibility`](../general-customization/chat-theme.mdx#messageoptionstheme) property and `ownCapabilities` to produce the correct list of `MessageOptionItemState`. Read more about customizing what options `SelectedMessageMenu` shows [here](../message-components/selected-message-menu.mdx#customizing-the-menu-option-list). `defaultMessageOptionsState` regulates the following capabilities: @@ -182,7 +182,7 @@ Additionally, the capability '**send-typing-events ***' is implemented in our `M our `MessageComposerViewModel`. Please keep this in mind should you wish to not use our `ViewModel`s. -# How capabilities affect the UI +## How capabilities affect the UI Let's take `MessageComposer` into consideration. If we left it with the default, empty set of own capabilities we would get the following result: diff --git a/docusaurus/docs/Android/compose/message-components/selected-message-menu.mdx b/docusaurus/docs/Android/compose/message-components/selected-message-menu.mdx index 3944412a71c..ed999853ece 100644 --- a/docusaurus/docs/Android/compose/message-components/selected-message-menu.mdx +++ b/docusaurus/docs/Android/compose/message-components/selected-message-menu.mdx @@ -1,4 +1,8 @@ -# Selecting Messages +--- +toc_max_heading_level: 4 +--- + +# Selected Message Menu The `SelectedMessageMenu` component allows you to show different message options to the user when they select a message in the `MessageList`. This is usually done by long tapping on a message item. @@ -99,7 +103,7 @@ Next, let's see how to customize the menu. ## Customization -You can customize the reactions you show, as well as the message options in this component: +You can customize the `SelectedMessageMenu` component by using the following parameters: ```kotlin @Composable @@ -114,15 +118,44 @@ fun SelectedMessageMenu( ) ``` -* `messageOptions`: Allows you to customize which message options are shown in the overlay. You can use `defaultMessageOptionsState()` to get the default actions that we expose in our SDK. +* `messageOptions`: Allows you to customize which message options are shown in the overlay. See [below](#customizing-the-menu-option-list). * `modifier`: Modifier for the dialog component. * `overlayColor`: Allows you to customize the color of the overlay. * `shape`: Allows you to customize the shape of the dialog. -* `reactionTypes`: Allows you to customize which reactions show in the overlay. By default it uses `ChatTheme.reactionIconFactory` which is exposed by the [`ChatTheme`](../general-customization/chat-theme.mdx) component. +* `reactionTypes`: Allows you to customize which reactions show in the overlay. See [below](#customizing-reactions). + +#### Customizing the Menu Option List + +You can pass `defaultMessageOptionsState()` to the `messageOptions` parameter to get the default actions that we expose in our SDK. This function uses the [`ChatTheme.messageOptionsTheme.optionVisibility`](../general-customization/chat-theme.mdx#messageoptionstheme) property and [own capabilities](../guides/implementing-own-capabilities.mdx) under the hood to control which action is visible to the user. + +The values that `defaultMessageOptionsState()` gets from `ChatTheme.messageOptionsTheme.optionVisibility` take precedence over own capabilities, so you can pass your own implementation of [`MessageOptionTheme`](https://github.com/GetStream/stream-chat-android/blob/e01d636f66fb0986ab71288f4ddee92afe550fd0/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/MessageOptionsTheme.kt) to `ChatTheme.messageOptionsTheme` to control which options to show. This is useful when you are using `MessagesScreen`, for example, which sets up `SelectedMessageMenu` automatically. + +```kotlin +ChatTheme( + // ... + messageOptionsTheme = MessageOptionsTheme.defaultTheme( + optionVisibility = MessageOptionItemVisibility( + isMarkAsUnreadVisible = false, + isCopyTextVisible = false, + ), + ), + // ... +) { + // Rest of the UI +} +``` + +#### Customizing Reactions + +By default, the `reactionTypes` parameter uses [`ChatTheme.reactionIconFactory`](../general-customization/chat-theme.mdx#reactioniconfactory) as a value which is exposed by the [`ChatTheme`](../general-customization/chat-theme.mdx) component. The best way to customize reactions is by overriding `ChatTheme.reactionIconFactory` with your own implementation of `ReactionIconFactory` so that all of your components wrapped inside of `ChatTheme` draw from the same source. -By default `SelectedMessageMenu` looks like a bottom sheet, however you can customize it to look like a completely different component, such as a dialog, a drawer or whatever helps you retain the look and feel of your app. +You can also control the reaction list visibility by using your own implementation of `ReactionOptionsTheme` for the [`ChatTheme.reactionOptionsTheme`](../general-customization/chat-theme.mdx#reactionoptionstheme) parameter. + +#### Customizing the Appearance + +By default `SelectedMessageMenu` looks like a bottom sheet. However you can customize it to look like a completely different component, such as a dialog, a drawer or whatever helps you retain the look and feel of your app. ```kotlin if (selectedMessageState is SelectedMessageOptionsState) { @@ -154,7 +187,9 @@ The code above will produce the following UI: |---|---| | ![Stylised SelectedMessageMenu component](../../assets/compose_custom_selected_message_menu_shape_and_alignment.png) | ![Stylised SelectedMessageMenu component dark](../../assets/compose_custom_selected_message_menu_shape_and_alignment_dark.png) | -`SelectedMessageMenu` provides you with `Composable` slots that are ready for more extensive customizations. +#### Customizing by Using Slots + +`SelectedMessageMenu` provides you with `Composable` slots that are ready for more extensive customizations: ```kotlin @Composable diff --git a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/MessagesActivity.kt b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/MessagesActivity.kt index 8c4f4e5a615..a654379f636 100644 --- a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/MessagesActivity.kt +++ b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/MessagesActivity.kt @@ -53,6 +53,7 @@ import io.getstream.chat.android.compose.sample.R import io.getstream.chat.android.compose.state.mediagallerypreview.MediaGalleryPreviewResultType import io.getstream.chat.android.compose.state.messages.attachments.StatefulStreamMediaRecorder import io.getstream.chat.android.compose.ui.components.composer.MessageInput +import io.getstream.chat.android.compose.ui.components.messageoptions.MessageOptionItemVisibility import io.getstream.chat.android.compose.ui.components.messageoptions.defaultMessageOptionsState import io.getstream.chat.android.compose.ui.components.reactionpicker.ReactionsPicker import io.getstream.chat.android.compose.ui.components.selectedmessage.SelectedMessageMenu @@ -63,6 +64,8 @@ import io.getstream.chat.android.compose.ui.messages.composer.MessageComposer import io.getstream.chat.android.compose.ui.messages.list.MessageList import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.MessageComposerTheme +import io.getstream.chat.android.compose.ui.theme.MessageOptionsTheme +import io.getstream.chat.android.compose.ui.theme.ReactionOptionsTheme import io.getstream.chat.android.compose.ui.theme.StreamColors import io.getstream.chat.android.compose.ui.theme.StreamTypography import io.getstream.chat.android.compose.ui.util.rememberMessageListState @@ -126,6 +129,10 @@ class MessagesActivity : BaseConnectedActivity() { ), ) }, + reactionOptionsTheme = ReactionOptionsTheme.defaultTheme(), + messageOptionsTheme = MessageOptionsTheme.defaultTheme( + optionVisibility = MessageOptionItemVisibility(), + ), ) { MessagesScreen( viewModelFactory = factory, diff --git a/stream-chat-android-compose/api/stream-chat-android-compose.api b/stream-chat-android-compose/api/stream-chat-android-compose.api index 31657a595bb..3ce78610db4 100644 --- a/stream-chat-android-compose/api/stream-chat-android-compose.api +++ b/stream-chat-android-compose/api/stream-chat-android-compose.api @@ -959,6 +959,36 @@ public final class io/getstream/chat/android/compose/ui/components/messageoption public static final fun MessageOptionItem (Lio/getstream/chat/android/compose/state/messageoptions/MessageOptionItemState;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;Landroidx/compose/runtime/Composer;II)V } +public final class io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility { + public static final field $stable I + public fun ()V + public fun (ZZZZZZZZZ)V + public synthetic fun (ZZZZZZZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Z + public final fun component2 ()Z + public final fun component3 ()Z + public final fun component4 ()Z + public final fun component5 ()Z + public final fun component6 ()Z + public final fun component7 ()Z + public final fun component8 ()Z + public final fun component9 ()Z + public final fun copy (ZZZZZZZZZ)Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility; + public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility;ZZZZZZZZZILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public final fun isCopyTextVisible ()Z + public final fun isDeleteMessageVisible ()Z + public final fun isEditMessageVisible ()Z + public final fun isFlagMessageVisible ()Z + public final fun isMarkAsUnreadVisible ()Z + public final fun isPinMessageVisible ()Z + public final fun isReplyVisible ()Z + public final fun isRetryMessageVisible ()Z + public final fun isThreadReplyVisible ()Z + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionsKt { public static final fun MessageOptions (Ljava/util/List;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)V public static final fun defaultMessageOptionsState (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;ZLjava/util/Set;Landroidx/compose/runtime/Composer;I)Ljava/util/List; @@ -1481,6 +1511,7 @@ public final class io/getstream/chat/android/compose/ui/theme/ChatTheme { public final fun getMessageAlignmentProvider (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/util/MessageAlignmentProvider; public final fun getMessageComposerTheme (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/theme/MessageComposerTheme; public final fun getMessageDateSeparatorTheme (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/theme/MessageDateSeparatorTheme; + public final fun getMessageOptionsTheme (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme; public final fun getMessageOptionsUserReactionAlignment (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/ui/common/state/messages/list/MessageOptionsUserReactionAlignment; public final fun getMessagePreviewFormatter (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/util/MessagePreviewFormatter; public final fun getMessageTextFormatter (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/util/MessageTextFormatter; @@ -1490,6 +1521,7 @@ public final class io/getstream/chat/android/compose/ui/theme/ChatTheme { public final fun getQuotedAttachmentFactories (Landroidx/compose/runtime/Composer;I)Ljava/util/List; public final fun getQuotedMessageTextFormatter (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/util/QuotedMessageTextFormatter; public final fun getReactionIconFactory (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/util/ReactionIconFactory; + public final fun getReactionOptionsTheme (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme; public final fun getReadCountEnabled (Landroidx/compose/runtime/Composer;I)Z public final fun getSearchResultNameFormatter (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/util/SearchResultNameFormatter; public final fun getShapes (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/theme/StreamShapes; @@ -1501,7 +1533,7 @@ public final class io/getstream/chat/android/compose/ui/theme/ChatTheme { } public final class io/getstream/chat/android/compose/ui/theme/ChatThemeKt { - public static final fun ChatTheme (ZZZLio/getstream/chat/android/compose/ui/theme/StreamColors;Lio/getstream/chat/android/compose/ui/theme/StreamDimens;Lio/getstream/chat/android/compose/ui/theme/StreamTypography;Lio/getstream/chat/android/compose/ui/theme/StreamShapes;Landroidx/compose/material/ripple/RippleTheme;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lio/getstream/chat/android/compose/ui/util/ReactionIconFactory;ZLio/getstream/chat/android/ui/common/helper/DateFormatter;Lio/getstream/chat/android/ui/common/utils/ChannelNameFormatter;Lio/getstream/chat/android/compose/ui/util/MessagePreviewFormatter;Lio/getstream/chat/android/compose/ui/util/SearchResultNameFormatter;Lio/getstream/chat/android/compose/ui/util/StreamCoilImageLoaderFactory;Lio/getstream/chat/android/compose/ui/util/MessageAlignmentProvider;Lio/getstream/chat/android/ui/common/state/messages/list/MessageOptionsUserReactionAlignment;Ljava/util/List;ZLio/getstream/chat/android/ui/common/images/resizing/StreamCdnImageResizing;ZLio/getstream/chat/android/compose/ui/theme/MessageTheme;Lio/getstream/chat/android/compose/ui/theme/MessageTheme;Lio/getstream/chat/android/compose/ui/theme/MessageDateSeparatorTheme;Lio/getstream/chat/android/compose/ui/theme/MessageUnreadSeparatorTheme;Lio/getstream/chat/android/compose/ui/theme/MessageComposerTheme;Lio/getstream/chat/android/compose/ui/util/MessageTextFormatter;Lio/getstream/chat/android/compose/ui/util/QuotedMessageTextFormatter;Lio/getstream/sdk/chat/audio/recording/StreamMediaRecorder;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;IIIIII)V + public static final fun ChatTheme (ZZZLio/getstream/chat/android/compose/ui/theme/StreamColors;Lio/getstream/chat/android/compose/ui/theme/StreamDimens;Lio/getstream/chat/android/compose/ui/theme/StreamTypography;Lio/getstream/chat/android/compose/ui/theme/StreamShapes;Landroidx/compose/material/ripple/RippleTheme;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lio/getstream/chat/android/compose/ui/util/ReactionIconFactory;Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme;ZLio/getstream/chat/android/ui/common/helper/DateFormatter;Lio/getstream/chat/android/ui/common/utils/ChannelNameFormatter;Lio/getstream/chat/android/compose/ui/util/MessagePreviewFormatter;Lio/getstream/chat/android/compose/ui/util/SearchResultNameFormatter;Lio/getstream/chat/android/compose/ui/util/StreamCoilImageLoaderFactory;Lio/getstream/chat/android/compose/ui/util/MessageAlignmentProvider;Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme;Lio/getstream/chat/android/ui/common/state/messages/list/MessageOptionsUserReactionAlignment;Ljava/util/List;ZLio/getstream/chat/android/ui/common/images/resizing/StreamCdnImageResizing;ZLio/getstream/chat/android/compose/ui/theme/MessageTheme;Lio/getstream/chat/android/compose/ui/theme/MessageTheme;Lio/getstream/chat/android/compose/ui/theme/MessageDateSeparatorTheme;Lio/getstream/chat/android/compose/ui/theme/MessageUnreadSeparatorTheme;Lio/getstream/chat/android/compose/ui/theme/MessageComposerTheme;Lio/getstream/chat/android/compose/ui/util/MessageTextFormatter;Lio/getstream/chat/android/compose/ui/util/QuotedMessageTextFormatter;Lio/getstream/sdk/chat/audio/recording/StreamMediaRecorder;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;IIIIII)V } public final class io/getstream/chat/android/compose/ui/theme/ComponentSize { @@ -1639,6 +1671,24 @@ public final class io/getstream/chat/android/compose/ui/theme/MessageDateSeparat public final fun defaultTheme (Lio/getstream/chat/android/compose/ui/theme/StreamTypography;Lio/getstream/chat/android/compose/ui/theme/StreamColors;Landroidx/compose/runtime/Composer;II)Lio/getstream/chat/android/compose/ui/theme/MessageDateSeparatorTheme; } +public final class io/getstream/chat/android/compose/ui/theme/MessageOptionsTheme { + public static final field $stable I + public static final field Companion Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme$Companion; + public fun (Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility;)V + public final fun component1 ()Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility; + public final fun copy (Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility;)Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme; + public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme;Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme; + public fun equals (Ljava/lang/Object;)Z + public final fun getOptionVisibility ()Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/chat/android/compose/ui/theme/MessageOptionsTheme$Companion { + public final fun defaultTheme (Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility;)Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme; + public static synthetic fun defaultTheme$default (Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme$Companion;Lio/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/MessageOptionsTheme; +} + public final class io/getstream/chat/android/compose/ui/theme/MessageTheme { public static final field $stable I public static final field Companion Lio/getstream/chat/android/compose/ui/theme/MessageTheme$Companion; @@ -1684,6 +1734,24 @@ public final class io/getstream/chat/android/compose/ui/theme/MessageUnreadSepar public final fun defaultTheme (Lio/getstream/chat/android/compose/ui/theme/StreamTypography;Lio/getstream/chat/android/compose/ui/theme/StreamColors;Landroidx/compose/runtime/Composer;II)Lio/getstream/chat/android/compose/ui/theme/MessageUnreadSeparatorTheme; } +public final class io/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme { + public static final field $stable I + public static final field Companion Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme$Companion; + public fun (Z)V + public final fun component1 ()Z + public final fun copy (Z)Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme; + public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme;ZILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme; + public fun equals (Ljava/lang/Object;)Z + public final fun getAreReactionOptionsVisible ()Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme$Companion { + public final fun defaultTheme (Z)Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme; + public static synthetic fun defaultTheme$default (Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme$Companion;ZILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme; +} + public final class io/getstream/chat/android/compose/ui/theme/StreamColors { public static final field $stable I public static final field Companion Lio/getstream/chat/android/compose/ui/theme/StreamColors$Companion; diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility.kt new file mode 100644 index 00000000000..113354739c9 --- /dev/null +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageoptions/MessageOptionItemVisibility.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014-2024 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * 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 io.getstream.chat.android.compose.ui.components.messageoptions + +import io.getstream.chat.android.compose.ui.components.selectedmessage.SelectedMessageMenu + +/** + * Controls option visibility in the message options menu. All options are visible by default. + * + * @param isRetryMessageVisible Visibility of the retry failed message option. + * @param isReplyVisible Visibility of the reply to message option (quote message). + * @param isThreadReplyVisible Visibility of the reply to message in thread option. + * @param isMarkAsUnreadVisible Visibility of the mark message as unread option. + * @param isCopyTextVisible Visibility of the copy message text option. + * @param isEditMessageVisible Visibility of the edit message option. + * @param isFlagMessageVisible Visibility of the flag message option. + * @param isPinMessageVisible Visibility of the pin message to chat option. + * @param isDeleteMessageVisible Visibility of the delete message option. + * + * @see [SelectedMessageMenu] + * @see [MessageOptions] + * @see [defaultMessageOptionsState] + */ +public data class MessageOptionItemVisibility( + val isRetryMessageVisible: Boolean = true, + val isReplyVisible: Boolean = true, + val isThreadReplyVisible: Boolean = true, + val isMarkAsUnreadVisible: Boolean = true, + val isCopyTextVisible: Boolean = true, + val isEditMessageVisible: Boolean = true, + val isFlagMessageVisible: Boolean = true, + val isPinMessageVisible: Boolean = true, + val isDeleteMessageVisible: Boolean = true, +) 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 a8c8f28b8a3..b28f341f09b 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 @@ -146,8 +146,15 @@ public fun defaultMessageOptionsState( val canMarkAsUnread = ownCapabilities.contains(ChannelCapabilities.READ_EVENTS) val canFlagMessage = ownCapabilities.contains(ChannelCapabilities.FLAG_MESSAGE) + val isThreadReplyPossible = !isInThread && isMessageSynced && canThreadReply + val isEditMessagePossible = ((isOwnMessage && canEditOwnMessage) || canEditAnyMessage) && !selectedMessage.isGiphy() + val isDeleteMessagePossible = canDeleteAnyMessage || (isOwnMessage && canDeleteOwnMessage) + + // options menu item visibility + val visibility = ChatTheme.messageOptionsTheme.optionVisibility + return listOfNotNull( - if (isOwnMessage && isMessageFailed) { + if (visibility.isRetryMessageVisible && isOwnMessage && isMessageFailed) { MessageOptionItemState( title = R.string.stream_compose_resend_message, iconPainter = painterResource(R.drawable.stream_compose_ic_resend), @@ -158,7 +165,7 @@ public fun defaultMessageOptionsState( } else { null }, - if (isMessageSynced && canQuoteMessage) { + if (visibility.isReplyVisible && isMessageSynced && canQuoteMessage) { MessageOptionItemState( title = R.string.stream_compose_reply, iconPainter = painterResource(R.drawable.stream_compose_ic_reply), @@ -169,7 +176,7 @@ public fun defaultMessageOptionsState( } else { null }, - if (!isInThread && isMessageSynced && canThreadReply) { + if (visibility.isThreadReplyVisible && isThreadReplyPossible) { MessageOptionItemState( title = R.string.stream_compose_thread_reply, iconPainter = painterResource(R.drawable.stream_compose_ic_thread), @@ -180,7 +187,7 @@ public fun defaultMessageOptionsState( } else { null }, - if (canMarkAsUnread) { + if (visibility.isMarkAsUnreadVisible && canMarkAsUnread) { MessageOptionItemState( title = R.string.stream_compose_mark_as_unread, iconPainter = painterResource(R.drawable.stream_compose_ic_mark_as_unread), @@ -191,7 +198,7 @@ public fun defaultMessageOptionsState( } else { null }, - if (isTextOnlyMessage || hasLinks) { + if (visibility.isCopyTextVisible && (isTextOnlyMessage || hasLinks)) { MessageOptionItemState( title = R.string.stream_compose_copy_message, iconPainter = painterResource(R.drawable.stream_compose_ic_copy), @@ -202,7 +209,7 @@ public fun defaultMessageOptionsState( } else { null }, - if (((isOwnMessage && canEditOwnMessage) || canEditAnyMessage) && !selectedMessage.isGiphy()) { + if (visibility.isEditMessageVisible && isEditMessagePossible) { MessageOptionItemState( title = R.string.stream_compose_edit_message, iconPainter = painterResource(R.drawable.stream_compose_ic_edit), @@ -213,7 +220,7 @@ public fun defaultMessageOptionsState( } else { null }, - if (canFlagMessage && !isOwnMessage) { + if (visibility.isFlagMessageVisible && canFlagMessage && !isOwnMessage) { MessageOptionItemState( title = R.string.stream_compose_flag_message, iconPainter = painterResource(R.drawable.stream_compose_ic_flag), @@ -224,7 +231,7 @@ public fun defaultMessageOptionsState( } else { null }, - if (isMessageSynced && canPinMessage) { + if (visibility.isPinMessageVisible && isMessageSynced && canPinMessage) { MessageOptionItemState( title = if (selectedMessage.pinned) R.string.stream_compose_unpin_message else R.string.stream_compose_pin_message, action = Pin(selectedMessage), @@ -235,7 +242,7 @@ public fun defaultMessageOptionsState( } else { null }, - if (canDeleteAnyMessage || (isOwnMessage && canDeleteOwnMessage)) { + if (visibility.isDeleteMessageVisible && isDeleteMessagePossible) { MessageOptionItemState( title = R.string.stream_compose_delete_message, iconPainter = painterResource(R.drawable.stream_compose_ic_delete), diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt index 3a687f172fb..dc2d9dba29b 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt @@ -77,7 +77,7 @@ public fun SelectedMessageMenu( headerContent: @Composable ColumnScope.() -> Unit = { val canLeaveReaction = ownCapabilities.contains(ChannelCapabilities.SEND_REACTION) - if (canLeaveReaction) { + if (ChatTheme.reactionOptionsTheme.areReactionOptionsVisible && canLeaveReaction) { DefaultSelectedMessageReactionOptions( message = message, reactionTypes = reactionTypes, diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt index e266f29580f..bf7a5c1e64a 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt @@ -83,6 +83,9 @@ private val LocalQuotedAttachmentFactories = compositionLocalOf { error("No reaction icon factory provided! Make sure to wrap all usages of Stream components in a ChatTheme.") } +private val LocalReactionOptionsTheme = compositionLocalOf { + error("No ReactionOptionsTheme provided! Make sure to wrap all usages of Stream components in a ChatTheme.") +} private val LocalDateFormatter = compositionLocalOf { error("No DateFormatter provided! Make sure to wrap all usages of Stream components in a ChatTheme.") } @@ -104,6 +107,9 @@ private val LocalSearchResultNameFormatter = compositionLocalOf { error("No MessageAlignmentProvider provided! Make sure to wrap all usages of Stream components in a ChatTheme.") } +private val LocalMessageOptionsTheme = compositionLocalOf { + error("No MessageOptionsTheme provided! Make sure to wrap all usages of Stream components in a ChatTheme.") +} private val LocalMessageOptionsUserReactionAlignment = compositionLocalOf { error( "No LocalMessageOptionsUserReactionAlignment provided! Make sure to wrap all usages of Stream components " + @@ -180,12 +186,16 @@ private val LocalStreamMediaRecorder = compositionLocalOf { * @param attachmentPreviewHandlers Attachment preview handlers we provide. * @param quotedAttachmentFactories Quoted attachment factories that we provide. * @param reactionIconFactory Used to create an icon [Painter] for the given reaction type. + * @param reactionOptionsTheme [ReactionOptionsTheme] Theme for the reaction option list in the selected message menu. + * For theming the message option list in the same menu, use [messageOptionsTheme]. * @param allowUIAutomationTest Allow to simulate ui automation with given test tags. - * @param dateFormatter [DateFormatter] used throughout the app for date and time information. - * @param channelNameFormatter [ChannelNameFormatter] used throughout the app for channel names. - * @param messagePreviewFormatter [MessagePreviewFormatter] used to generate a string preview for the given message. + * @param dateFormatter [DateFormatter] Used throughout the app for date and time information. + * @param channelNameFormatter [ChannelNameFormatter] Used throughout the app for channel names. + * @param messagePreviewFormatter [MessagePreviewFormatter] Used to generate a string preview for the given message. * @param imageLoaderFactory A factory that creates new Coil [ImageLoader] instances. - * @param messageAlignmentProvider [MessageAlignmentProvider] used to provide message alignment for the given message. + * @param messageAlignmentProvider [MessageAlignmentProvider] Used to provide message alignment for the given message. + * @param messageOptionsTheme [MessageOptionsTheme] Theme for the message option list in the selected message menu. + * For theming the reaction option list in the same menu, use [reactionOptionsTheme]. * @param messageOptionsUserReactionAlignment Alignment of the user reaction inside the message options. * @param attachmentsPickerTabFactories Attachments picker tab factories that we provide. * @param videoThumbnailsEnabled Dictates whether video thumbnails will be displayed inside video previews. @@ -215,6 +225,7 @@ public fun ChatTheme( AttachmentPreviewHandler.defaultAttachmentHandlers(LocalContext.current), quotedAttachmentFactories: List = StreamAttachmentFactories.defaultQuotedFactories(), reactionIconFactory: ReactionIconFactory = ReactionIconFactory.defaultFactory(), + reactionOptionsTheme: ReactionOptionsTheme = ReactionOptionsTheme.defaultTheme(), allowUIAutomationTest: Boolean = false, dateFormatter: DateFormatter = DateFormatter.from(LocalContext.current), channelNameFormatter: ChannelNameFormatter = ChannelNameFormatter.defaultFormatter(LocalContext.current), @@ -227,6 +238,7 @@ public fun ChatTheme( searchResultNameFormatter: SearchResultNameFormatter = SearchResultNameFormatter.defaultFormatter(), imageLoaderFactory: StreamCoilImageLoaderFactory = StreamCoilImageLoaderFactory.defaultFactory(), messageAlignmentProvider: MessageAlignmentProvider = MessageAlignmentProvider.defaultMessageAlignmentProvider(), + messageOptionsTheme: MessageOptionsTheme = MessageOptionsTheme.defaultTheme(), messageOptionsUserReactionAlignment: MessageOptionsUserReactionAlignment = MessageOptionsUserReactionAlignment.END, attachmentsPickerTabFactories: List = AttachmentsPickerTabFactories.defaultFactories(), videoThumbnailsEnabled: Boolean = true, @@ -285,6 +297,7 @@ public fun ChatTheme( LocalAttachmentPreviewHandlers provides attachmentPreviewHandlers, LocalQuotedAttachmentFactories provides quotedAttachmentFactories, LocalReactionIconFactory provides reactionIconFactory, + LocalReactionOptionsTheme provides reactionOptionsTheme, LocalDateFormatter provides dateFormatter, LocalChannelNameFormatter provides channelNameFormatter, LocalMessagePreviewFormatter provides messagePreviewFormatter, @@ -298,6 +311,7 @@ public fun ChatTheme( LocalMessageComposerTheme provides messageComposerTheme, LocalStreamImageLoader provides imageLoaderFactory.imageLoader(LocalContext.current.applicationContext), LocalMessageAlignmentProvider provides messageAlignmentProvider, + LocalMessageOptionsTheme provides messageOptionsTheme, LocalMessageOptionsUserReactionAlignment provides messageOptionsUserReactionAlignment, LocalAttachmentsPickerTabFactories provides attachmentsPickerTabFactories, LocalVideoThumbnailsEnabled provides videoThumbnailsEnabled, @@ -388,6 +402,14 @@ public object ChatTheme { @ReadOnlyComposable get() = LocalReactionIconFactory.current + /** + * Retrieves the current [ReactionOptionsTheme] at the call site's position in the hierarchy. + */ + public val reactionOptionsTheme: ReactionOptionsTheme + @Composable + @ReadOnlyComposable + get() = LocalReactionOptionsTheme.current + /** * Retrieves the current [DateFormatter] at the call site's position in the hierarchy. */ @@ -444,6 +466,14 @@ public object ChatTheme { @ReadOnlyComposable get() = LocalMessageAlignmentProvider.current + /** + * Retrieves the current [MessageOptionsTheme] at the call site's position in the hierarchy. + */ + public val messageOptionsTheme: MessageOptionsTheme + @Composable + @ReadOnlyComposable + get() = LocalMessageOptionsTheme.current + /** * Retrieves the current [MessageOptionsUserReactionAlignment] at the call site's position in the hierarchy. */ diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/MessageOptionsTheme.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/MessageOptionsTheme.kt new file mode 100644 index 00000000000..bdba75a59bf --- /dev/null +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/MessageOptionsTheme.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014-2024 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * 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 io.getstream.chat.android.compose.ui.theme + +import androidx.compose.runtime.Immutable +import io.getstream.chat.android.compose.ui.components.messageoptions.MessageOptionItemVisibility + +/** + * Represents the theme for the message option list in the selected message menu. + * For reaction option list theming, see [ReactionOptionsTheme]. + * + * @param optionVisibility The visibility of the message options. + * + * @see MessageOptionItemVisibility + */ +@Immutable +public data class MessageOptionsTheme( + public val optionVisibility: MessageOptionItemVisibility, +) { + public companion object { + public fun defaultTheme( + optionVisibility: MessageOptionItemVisibility = MessageOptionItemVisibility(), + ): MessageOptionsTheme { + return MessageOptionsTheme( + optionVisibility = optionVisibility, + ) + } + } +} diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme.kt new file mode 100644 index 00000000000..965ab6a1db4 --- /dev/null +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ReactionOptionsTheme.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014-2024 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * 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 io.getstream.chat.android.compose.ui.theme + +import androidx.compose.runtime.Immutable + +/** + * Represents the theme for the reaction option list in the selected message menu. + * For message option list theming, see [MessageOptionsTheme]. + * + * @param areReactionOptionsVisible The visibility of the reaction options. + */ +@Immutable +public data class ReactionOptionsTheme( + public val areReactionOptionsVisible: Boolean, +) { + public companion object { + public fun defaultTheme( + areReactionOptionsVisible: Boolean = true, + ): ReactionOptionsTheme = ReactionOptionsTheme( + areReactionOptionsVisible = areReactionOptionsVisible, + ) + } +}