diff --git a/CHANGELOG.md b/CHANGELOG.md index b15081f27ff..1db80ceb4f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,7 @@ ### ⬆️ Improved ### ✅ Added +- Added `MessageComposerTheme` to customize the message composer. [#5183](https://github.com/GetStream/stream-chat-android/pull/5183) ### ⚠️ Changed 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 c4e85ceab99..5c07d25df5f 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 @@ -24,6 +24,7 @@ import androidx.activity.viewModels import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -61,6 +62,8 @@ import io.getstream.chat.android.compose.ui.messages.attachments.AttachmentsPick 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.StreamColors import io.getstream.chat.android.compose.ui.util.rememberMessageListState import io.getstream.chat.android.compose.viewmodel.messages.AttachmentsPickerViewModel import io.getstream.chat.android.compose.viewmodel.messages.MessageComposerViewModel @@ -101,10 +104,21 @@ class MessagesActivity : BaseConnectedActivity() { super.onCreate(savedInstanceState) setContent { + val colors = if (isSystemInDarkTheme()) StreamColors.defaultDarkColors() else StreamColors.defaultColors() ChatTheme( + colors = colors, dateFormatter = ChatApp.dateFormatter, autoTranslationEnabled = ChatApp.autoTranslationEnabled, allowUIAutomationTest = true, + messageComposerTheme = MessageComposerTheme.defaultTheme().let { messageComposerTheme -> + messageComposerTheme.copy( + attachmentCancelIcon = messageComposerTheme.attachmentCancelIcon.copy( + painter = painterResource(id = R.drawable.stream_compose_ic_clear), + tint = colors.overlayDark, + backgroundColor = colors.appBackground, + ), + ) + }, ) { 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 c4bf100b3b9..347ec8ec512 100644 --- a/stream-chat-android-compose/api/stream-chat-android-compose.api +++ b/stream-chat-android-compose/api/stream-chat-android-compose.api @@ -1395,6 +1395,7 @@ public final class io/getstream/chat/android/compose/ui/theme/ChatTheme { public final fun getDateFormatter (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/ui/common/helper/DateFormatter; public final fun getDimens (Landroidx/compose/runtime/Composer;I)Lio/getstream/chat/android/compose/ui/theme/StreamDimens; 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 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; @@ -1412,7 +1413,42 @@ 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 (ZZLio/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/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/sdk/chat/audio/recording/StreamMediaRecorder;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;IIII)V + public static final fun ChatTheme (ZZLio/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/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/sdk/chat/audio/recording/StreamMediaRecorder;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;IIII)V +} + +public final class io/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle { + public static final field $stable I + public synthetic fun (Landroidx/compose/ui/graphics/Shape;JLandroidx/compose/ui/graphics/painter/Painter;JLkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Landroidx/compose/ui/graphics/Shape; + public final fun component2-0d7_KjU ()J + public final fun component3 ()Landroidx/compose/ui/graphics/painter/Painter; + public final fun component4-0d7_KjU ()J + public final fun copy-3bbok98 (Landroidx/compose/ui/graphics/Shape;JLandroidx/compose/ui/graphics/painter/Painter;J)Lio/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle; + public static synthetic fun copy-3bbok98$default (Lio/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle;Landroidx/compose/ui/graphics/Shape;JLandroidx/compose/ui/graphics/painter/Painter;JILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle; + public fun equals (Ljava/lang/Object;)Z + public final fun getBackgroundColor-0d7_KjU ()J + public final fun getBackgroundShape ()Landroidx/compose/ui/graphics/Shape; + public final fun getPainter ()Landroidx/compose/ui/graphics/painter/Painter; + public final fun getTint-0d7_KjU ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/chat/android/compose/ui/theme/MessageComposerTheme { + public static final field $stable I + public static final field Companion Lio/getstream/chat/android/compose/ui/theme/MessageComposerTheme$Companion; + public fun (Lio/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle;)V + public final fun component1 ()Lio/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle; + public final fun copy (Lio/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle;)Lio/getstream/chat/android/compose/ui/theme/MessageComposerTheme; + public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/MessageComposerTheme;Lio/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/MessageComposerTheme; + public fun equals (Ljava/lang/Object;)Z + public final fun getAttachmentCancelIcon ()Lio/getstream/chat/android/compose/ui/theme/ComposerCancelIconStyle; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/chat/android/compose/ui/theme/MessageComposerTheme$Companion { + 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/MessageComposerTheme; } public final class io/getstream/chat/android/compose/ui/theme/MessageDateSeparatorTheme { diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/CancelIcon.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/CancelIcon.kt index 39ea916ebc4..2bf8db13669 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/CancelIcon.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/CancelIcon.kt @@ -19,12 +19,10 @@ package io.getstream.chat.android.compose.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import io.getstream.chat.android.compose.R import io.getstream.chat.android.compose.ui.theme.ChatTheme @@ -42,14 +40,17 @@ public fun CancelIcon( ) { Icon( modifier = modifier - .background(shape = CircleShape, color = ChatTheme.colors.overlayDark) + .background( + shape = ChatTheme.messageComposerTheme.attachmentCancelIcon.backgroundShape, + color = ChatTheme.messageComposerTheme.attachmentCancelIcon.backgroundColor, + ) .clickable( indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = onClick, ), - painter = painterResource(id = R.drawable.stream_compose_ic_close), + painter = ChatTheme.messageComposerTheme.attachmentCancelIcon.painter, contentDescription = stringResource(id = R.string.stream_compose_cancel), - tint = ChatTheme.colors.appBackground, + tint = ChatTheme.messageComposerTheme.attachmentCancelIcon.tint, ) } 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 ce9fe04d516..0218ed069e0 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 @@ -133,6 +133,9 @@ private val LocalMessageDateSeparatorTheme = compositionLocalOf { error("No MessageUnreadSeparatorTheme provided! Make sure to wrap all usages of Stream components in a ChatTheme.") } +private val LocalMessageComposerTheme = compositionLocalOf { + error("No MessageComposerTheme provided! Make sure to wrap all usages of Stream components in a ChatTheme.") +} private val LocalAutoTranslationEnabled = compositionLocalOf { error( "No AutoTranslationEnabled Boolean provided! " + @@ -173,6 +176,8 @@ private val LocalStreamMediaRecorder = compositionLocalOf { * @param ownMessageTheme Theme of the current user messages. * @param otherMessageTheme Theme of the other users messages. * @param messageDateSeparatorTheme Theme of the message date separator. + * @param messageUnreadSeparatorTheme Theme of the message unread separator. + * @param messageComposerTheme Theme of the message composer. * @param streamMediaRecorder Used for recording audio messages. * @param content The content shown within the theme wrapper. */ @@ -218,7 +223,11 @@ public fun ChatTheme( typography = typography, colors = colors, ), - messageUnradSeparatorTheme: MessageUnreadSeparatorTheme = MessageUnreadSeparatorTheme.defaultTheme( + messageUnreadSeparatorTheme: MessageUnreadSeparatorTheme = MessageUnreadSeparatorTheme.defaultTheme( + typography = typography, + colors = colors, + ), + messageComposerTheme: MessageComposerTheme = MessageComposerTheme.defaultTheme( typography = typography, colors = colors, ), @@ -245,7 +254,8 @@ public fun ChatTheme( LocalOwnMessageTheme provides ownMessageTheme, LocalOtherMessageTheme provides otherMessageTheme, LocalMessageDateSeparatorTheme provides messageDateSeparatorTheme, - LocalMessageUnreadSeparatorTheme provides messageUnradSeparatorTheme, + LocalMessageUnreadSeparatorTheme provides messageUnreadSeparatorTheme, + LocalMessageComposerTheme provides messageComposerTheme, LocalStreamImageLoader provides imageLoaderFactory.imageLoader(LocalContext.current.applicationContext), LocalMessageAlignmentProvider provides messageAlignmentProvider, LocalMessageOptionsUserReactionAlignment provides messageOptionsUserReactionAlignment, @@ -439,6 +449,14 @@ public object ChatTheme { @ReadOnlyComposable get() = LocalMessageUnreadSeparatorTheme.current + /** + * Retrieves the current [MessageComposerTheme] at the call site's position in the hierarchy. + */ + public val messageComposerTheme: MessageComposerTheme + @Composable + @ReadOnlyComposable + get() = LocalMessageComposerTheme.current + /** * Retrieves the current [autoTranslationEnabled] value 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/MessageComposerTheme.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/MessageComposerTheme.kt new file mode 100644 index 00000000000..28b6181046a --- /dev/null +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/MessageComposerTheme.kt @@ -0,0 +1,75 @@ +/* + * 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.foundation.isSystemInDarkTheme +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import io.getstream.chat.android.compose.R + +/** + * Represents the theming for the message composer. + * @param attachmentCancelIcon The theming for the cancel icon used in the message composer. + */ +public data class MessageComposerTheme( + val attachmentCancelIcon: ComposerCancelIconStyle, +) { + + public companion object { + + /** + * Builds the default message composer theme. + * + * @return A [MessageComposerTheme] instance holding the default theming. + */ + @Composable + public fun defaultTheme( + typography: StreamTypography = StreamTypography.defaultTypography(), + colors: StreamColors = when (isSystemInDarkTheme()) { + true -> StreamColors.defaultDarkColors() + else -> StreamColors.defaultColors() + }, + ): MessageComposerTheme { + return MessageComposerTheme( + attachmentCancelIcon = ComposerCancelIconStyle( + backgroundShape = CircleShape, + backgroundColor = colors.overlayDark, + painter = painterResource(id = R.drawable.stream_compose_ic_close), + tint = colors.appBackground, + ), + ) + } + } +} + +/** + * Represents the theming for the cancel icon used in the message composer. + * + * @param backgroundShape The shape of the background for the cancel icon. + * @param backgroundColor The background color for the cancel icon. + * @param tint The tint color for the cancel icon. + */ +public data class ComposerCancelIconStyle( + val backgroundShape: Shape, + val backgroundColor: Color, + val painter: Painter, + val tint: Color, +)